- 1. 学习如何在你的电脑上配置OpenCV-Python环境!
- 1.1 开始了解OpenCV-Python
- 1.2 在 Windows 下安装 OpenCV-Python
- 1.3 在 Fedora 环境下安装 OpenCV-Python
- 1.4 在 Debian(Ubuntu)中配置 OpenCV-Python
- 1.5 在Docker中安装OpenCV-Python
- 1.6 在树莓派配置OpenCV-Python
- 2. OpenCV中的GUI功能
- 2.1 开始使用图像
- 2.2 开始使用视频
- 2.3 OpenCV 中的绘图函数
- 2.4 以鼠标为画笔
- 2.5 用滑块控制条做调色板
- 3. OpenCV中的GUI功能
- 3.1 图片基本操作
- 3.2 图像算术操作
- 3.3 性能评估与改进技巧
- 4. OpenCV中的图像处理
- 4.1 更换颜色空间
- 4.2 对图像进行几何变换
- 4.3 图像二值化处理
- 4.4 平滑图像
- 4.5 形态学转换
- 4.6 图像梯度
- 4.7 Canny边缘检测
- 4.8 图像金字塔
- 4.9.1 直方图:查找,绘制,分析
- 4.9.2 直方图均衡化
- 4.9.3 二维直方图
- 4.9.4 直方图反投影
- 4.10 OpenCV中的图像变换
- 4.10.1 傅立叶变换
- 4.11 模板匹配
- 4.12 霍夫直线变换
- 4.13 霍夫圆变换
- 4.14 基于分水岭算法的图像分割
- 4.14 使用 GrabCut 算法交互式前景提取
- 5. 特征检测和描述符
- 5.1 理解特征
- 5.2 Harris 角点检测
- 5.3 Shi-Tomasi 角点检测 & 适合用来跟踪的特征
- 5.4 介绍SIFT(尺度不变特征转换)
- 5.5 介绍SURF(加速稳健特征)
- 5.6 角点检测的FAST算法
- 5.7 BRIEF特征点描述算法
- 5.8 ORB 特征描述符(Oriented FAST and Rotated BRIEF)
- 5.9 特征匹配
- 5.10 特征匹配和使用单应性匹配来搜索物体
- 6. 视频分析
- 6.1 Meanshift和Camshift
- 6.2 光流
- 6.3 背景分割
- 7. 相机校准和3D重建
- 7.1 相机校准
- 7.2 姿势估计
- 7.3 极线几何
- 7.4 来自立体图像的深度图
- 8. 机器学习
- 8.1 K-最近邻算法
- 8.1.1 了解k-最近邻算法
- 8.1.2 使用kNN进行手写字符的OCR
- 8.2 支持向量机(SVM)
- 8.2.1 理解SVM
- 8.2.2 使用SVM的手写数据的OCR
- 8.3 K-Means聚类
- 8.3.1 理解 K-Means 聚类
- 8.3.2 OpenCV中的K-Means聚类
- 9. 计算摄影学
- 9.1 图像去噪
- 9.2 图像修复
- 9.3 高动态范围(HDR)
- 10. 目标检测
- 10.1 使用 Haar Cascades 的面部识别
- 11. OpenCV-Python 绑定
- 11.1 OpenCV-Python绑定如何工作?
4.9.1 直方图:查找,绘制,分析
目标
- 使用 OpenCV 和 Numpy 函数查找直方图
- 绘制直方图,使用 OpenCV 和 Matplotlib 函数
- 你会学到这些函数:
cv2.calcHist()
,np.histogram()
等
理论基础
什么是直方图?您可以将直方图视为一个图形,它将会为您提供有关图像强度分布的大体情况。这是一个在X轴上具有像素值(一般来说是从0到255,但并非总是这样)的图形,并且在Y轴上具有相应的像素数量。
直方图只是理解图像的另一种方式。通过查看图像的直方图,您可以直观了解该图像的对比度,亮度,强度分布等。目前几乎所有的图像处理工具都提供了直方图上功能。
你可以看到图像和直方图。 (请记住,这个直方图是为灰度图像绘制的,而不是彩色图像)。直方图的左侧区域显示图像中较暗像素的数量,右侧区域显示较亮像素的数量。从直方图中,您可以看到黑色区域比明亮区域多,中间色调(中等范围内的像素值,例如127左右)的数量非常少。
查找直方图
现在我们心中有直方图的概念了,我们可以来看看如何找到它了。 OpenCV和Numpy都有内置的函数。在使用这些函数之前,我们需要了解一些与直方图有关的术语。
BINS:上面的直方图显示了每个像素值的像素数量,即从0到255。也就是说,您需要256个值来显示上述直方图。但是想一想,如果你不需要分别找出所有像素值的像素数量,而是需要找到每个像素值的区间中的像素数量怎么办?举例来说,您需要找到位于0到15之间,然后是16到31,...,240到255之间的像素数目。
您将只需要16个值来表示直方图。这就是OpenCV教程中关于直方图的例子。
所以你所做的只是将整个直方图拆分为16个子部分,每个子部分的值是其中所有像素数的总和。这个子部分被称为“面元(BIN)”。在第一种情况下,面元的数量是256(每种亮度的像素一个),而在第二种情况下,只有16个。在OpenCV文档中,面元数量由术语histSize表示。
DIMS:这是我们收集数据的参数数量。在这种情况下,只收集关于一个东西的数据,即强度值的数据。所以这里是1。
RANGE:这是您要测量的强度值的范围。通常,它是[0,256],即所有强度值。
OpenCV 中的直方图计算
所以现在我们使用 cv2.calcHist()
函数来查找直方图。让我们熟悉这个函数及其参数:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
images
:它是类型为uint8或float32的源图像。应该将其放在方括号传入,即[img]
。channels
:它也应该放在方括号内。这是我们计算直方图的通道索引。例如,如果输入是灰度图像,则其值为[0]。对于彩色图像,可以通过[0],[1]或[2]分别计算蓝色,绿色或红色通道的直方图。mask
:mask图片。要查找完整图像的直方图,可以传入None
。但是,如果你想找到特定区域的图像直方图,你必须创建一个mask图像,并将其作为传入。 (我稍后会举例说明。)histSize
:这代表我们的面元数量。需放入方括号给出。对于全部像素值,我们传入[256]
。ranges
:这是我们的RANGE。通常是[0,256]。
那么让我们从一个示例图像开始。只需以灰度模式加载图像,并找到完整的图像直方图。
img = cv2.imread('home.jpg',0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])
hist 是一个 256x1 数组,每个值对应于该图像中具有其对应像素值的像素的数量。
Numpy 中的直方图计算
Numpy 也为你提供了一个函数np.histogram()
。所以,替代calcHist()
函数,你可以尝试使用下面这行代码:
hist,bins = np.histogram(img.ravel(),256,[0,256])
hist 与我们之前计算的相同。但是bins将会有257个元素,因为Numpy计算的bins为0-0.99,1-1.99,2-2.99等,所以最后的范围是255-255.99。为了表示这个范围,他们在bin结尾加上了256。但是我们不需要256。到255就足够了。
numpy 有另外一个函数,np.bincount()
,它比np.histogram()
要快得多(10倍左右)。所以对于一维直方图,你可以最好尝试一下它。不要忘记在np.bincount
中设置minlength = 256
。例如:
hist = np.bincount(img.ravel(),minlength=256)
OpenCV 函数比 np.histogram()
要快(大约40X)。所以应该坚持使用OpenCV函数。
现在我们应该绘制直方图了,但是应该怎么做呢?
绘制直方图
有两种方法来做到这一点,
- 捷径:使用 Matplotlib 绘图功能
- 不那么方便的方法:使用 OpenCV 绘图功能
使用 Matplotlib
Matplotlib 带有一个直方图绘图函数:matplotlib.pyplot.hist()
它直接找到直方图并绘制它。您不需要使用 calcHist()
或 np.histogram()
函数找到直方图。请参阅下面的代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()
或者你可以使用 matplotlib 的普通 plot,这对于 BGR 图像来说比较好用。为此,您需要首先查找直方图数据。尝试下面的代码:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('home.jpg')
color = ('b','g','r')
for i,col in enumerate(color):
histr = cv2.calcHist([img],[i],None,[256],[0,256])
plt.plot(histr,color = col)
plt.xlim([0,256])
plt.show()
你可以从上面的图中看出,蓝色值在图像中有一些高的区域(显然这应该是由于天空)
使用 OpenCV
您可以将直方图的值与其面元值一起调整为 (x,y) 坐标,以便您可以使用 cv2.line()
或 cv2.polyline()
函数绘制直方图以生成与上面相同的图像。 OpenCV-Python 的官方示例已经展示了这一点。检查 samples/python /hist.py
中的代码。
应用 mask
我们使用 cv2.calcHist()
来查找完整图像的直方图。如果你想找到一个图像的某些区域的直方图呢?只需在要查找直方图的区域创建一个白色的 mask 图像,否则就是黑色。然后传入这个 mask。
img = cv2.imread('home.jpg',0)
# 创建一个mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = mask)
# Calculate histogram with mask and without mask
# 计算出直方图,一个用mask,另一个不用
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask,'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()
在直方图中,蓝线显示完整图像的直方图,而绿线显示 mask 出的区域的直方图。
更多资源
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论