OpenCV 4.11.0
开源计算机视觉
加载中...
搜索中...
无匹配项
直方图 - 3:二维直方图

目标

本章我们将学习如何查找和绘制二维直方图。这在接下来的章节中将非常有用。

简介

在第一篇文章中,我们计算并绘制了一维直方图。之所以称为一维,是因为我们只考虑一个特征,即像素的灰度强度值。但在二维直方图中,您考虑两个特征。通常用于查找颜色直方图,其中两个特征是每个像素的色相和饱和度值。

已经有一个 Python 示例 (samples/python/color_histogram.py) 用于查找颜色直方图。我们将尝试了解如何创建这样的颜色直方图,这将有助于理解直方图反投影等后续主题。

OpenCV中的二维直方图

它非常简单,可以使用相同的函数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, "文件无法读取,请使用 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_BGR)
从文件加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
将图像从一个颜色空间转换为另一个颜色空间。
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中的二维直方图

NumPy也为此提供了一个特定函数:np.histogram2d()。(记住,对于一维直方图,我们使用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, "文件无法读取,请使用 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 平面,第三个是每个平面的 bin 数,第四个是它们的范围。

现在我们可以检查如何绘制这个颜色直方图。

绘制二维直方图

方法一:使用 cv.imshow()

我们得到的结果是一个大小为 180x256 的二维数组。因此,我们可以像平时一样使用cv.imshow()函数显示它们。它将是一幅灰度图像,不会让我们对其中有哪些颜色有太多了解,除非您知道不同颜色的色相值。

方法二:使用 Matplotlib

我们可以使用matplotlib.pyplot.imshow()函数使用不同的颜色映射来绘制二维直方图。它让我们对不同的像素密度有了更好的了解。但是,除非您知道不同颜色的色相值,否则这也无法让我们一眼看出是什么颜色。但我仍然更喜欢这种方法。它简单且更好。

注意
使用此函数时,请记住,为了获得更好的结果,插值标志应为最近邻。

考虑代码

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('home.jpg')
assert img is not None, "文件无法读取,请使用 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 等任何图像编辑工具进行验证。

方法三:OpenCV 示例风格!!

在 OpenCV-Python2 示例 (samples/python/color_histogram.py) 中有一个颜色直方图示例代码。如果您运行代码,您会看到直方图也显示了相应的颜色。或者它简单地输出一个颜色编码的直方图。其结果非常好(尽管您需要添加额外的几行)。

在该代码中,作者在 HSV 中创建了一个颜色映射。然后将其转换为 BGR。生成的直方图图像与该颜色映射相乘。他还使用一些预处理步骤来去除小的孤立像素,从而得到一个良好的直方图。

我把它留给读者运行代码,分析它并进行自己的修改。以下是与上面相同的图像的代码输出

图像

您可以清楚地看到直方图中存在哪些颜色,蓝色、黄色,以及棋盘造成的白色。不错!!!