OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
没有匹配项
直方图 - 3 : 2D 直方图

目标

在本章中,我们将学习如何查找和绘制 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
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
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
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
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
img = cv.imread('home.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
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。生成的直方图图像使用此颜色映射表进行乘法。他还使用一些预处理步骤来移除小块孤立像素,从而生成了良好的直方图。

我让读者运行此代码,对其进行分析并完成您自己的破解。以下是此代码输出与上方相同的图像

图像

您可以在直方图中清晰地看到现有的颜色,存在蓝色、黄色,还存在一些棋盘格造成的白色。不错!!!

其他资源

练习