目标
在本章中,我们将学习如何查找和绘制 2D 直方图。这将在后面的章节中有所帮助。
介绍
在第一篇文章中,我们计算并绘制了一维直方图。之所以称为一维,是因为我们仅考虑了一个特征,即像素的灰度强度值。但是在二维直方图中,你会考虑两个特征。它通常用于查找颜色直方图,其中两个特征是每个像素的色调和饱和度值。
已经有了一个 Python 样本(samples/python/color_histogram.py)用于查找颜色直方图。我们将尝试理解如何创建这样的颜色直方图,这将有助于理解诸如直方图反向投影之类的进一步主题。
OpenCV 中的 2D 直方图
它相当简单,并使用相同的函数计算,cv.calcHist()。对于颜色直方图,我们需要将图像从 BGR 转换为 HSV。(记住,对于一维直方图,我们将图像从 BGR 转换为灰度)。对于二维直方图,其参数将修改如下
- channels = [0,1] 因为我们需要处理 H 和 S 平面。
- bins = [180,256] H 平面为 180,S 平面为 256。
- range = [0,180,0,256] 色调值介于 0 到 180 之间,饱和度介于 0 到 256 之间。
现在检查以下代码
import numpy as np
import cv2 as cv
assert img is not None, "file could not be read, check with os.path.exists()"
hist =
cv.calcHist([hsv], [0, 1],
None, [180, 256], [0, 180, 0, 256])
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
从文件中加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)
将图像从一种颜色空间转换为另一种颜色空间。
void calcHist(const Mat *images, int nimages, const int *channels, InputArray mask, OutputArray hist, int dims, const int *histSize, const float **ranges, bool uniform=true, bool accumulate=false)
计算一系列数组的直方图。
就是这样。
Numpy 中的 2D 直方图
Numpy 也为此提供了特定函数:np.histogram2d()。(请记住,对于 1D 直方图,我们使用了 np.histogram())。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
assert img is not None, "file could not be read, check with os.path.exists()"
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
第一个参数属于 H 平面,第二个属于 S 平面,第三个为每个参数的区间数量,第四个参数为其范围。
我们现在可以检查如何绘制此颜色直方图。
绘制 2D 直方图
方法 1:使用 cv.imshow()
我们得到的结果是大小为 180x256 的二维数组。因此,我们可以像通常使用 cv.imshow() 函数那样显示它们。该函数就是一个灰度图像,它不会提供太多想法,除非你知道不同颜色的色相值。
方法 2:使用 Matplotlib
我们可以使用 matplotlib.pyplot.imshow() 函数通过不同的颜色映射绘制 2D 直方图。它让我们更好地了解不同像素密度。但是,该方法也不让我们了解什么颜色是第一眼,除非你知道不同颜色的色相值。但我仍然更喜欢这种方法。它简单且更好。
- 注意
- 在使用此函数时,请记住,对于更好的结果,插值标志应该是最接近的。
考虑代码
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
assert img is not None, "file could not be read, check with os.path.exists()"
hist =
cv.calcHist( [hsv], [0, 1],
None, [180, 256], [0, 180, 0, 256] )
plt.imshow(hist,interpolation = 'nearest')
plt.show()
以下是输入图像及其颜色直方图图。X 轴显示 S 值,Y 轴显示色相。
图像
在直方图中,你可以在 H = 100 且 S = 200 附近看到一些较高的值。它对应于天空的蓝色。同样,在 H = 25 且 S = 100 附近可以看到另一个峰值。它对应于宫殿的黄色。你可以在像 GIMP 这样的任何图像编辑工具中进行验证。
方法 3:OpenCV 样例风格!
OpenCV-Python2 样例 (samples/python/color_histogram.py) 中有一个有关颜色直方图的样例代码。如果你运行该代码,你会看到直方图会显示相应的颜色。或者它会简单地输出一个带颜色的直方图。它的效果非常好(尽管你需要添加很多其它的行)。
在此代码中,作者在 HSV 中创建了一个颜色映射表。然后将其转换为 BGR。生成的直方图图像使用此颜色映射表进行乘法。他还使用一些预处理步骤来移除小块孤立像素,从而生成了良好的直方图。
我让读者运行此代码,对其进行分析并完成您自己的破解。以下是此代码输出与上方相同的图像
图像
您可以在直方图中清晰地看到现有的颜色,存在蓝色、黄色,还存在一些棋盘格造成的白色。不错!!!
其他资源
练习