OpenCV 4.12.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, "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_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, "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 平面,第三个是每个平面的 bins 数,第四个是它们的范围。

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

绘制二维直方图

方法 - 1:使用 cv.imshow()

我们得到的结果是一个大小为 180x256 的二维数组。 所以我们可以像通常一样,使用 cv.imshow() 函数来显示它们。 它将是一个灰度图像,除非您知道不同颜色的色调值,否则它不会给出太多关于颜色的概念。

方法 - 2:使用 Matplotlib

我们可以使用 matplotlib.pyplot.imshow() 函数来绘制具有不同颜色图的二维直方图。 它使我们更好地了解不同的像素密度。 但同样,除非您知道不同颜色的色调值,否则乍一看,它也不会让我们知道那里有什么颜色。 不过我更喜欢这种方法。 它简单且更好。

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

考虑代码

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 轴显示色调。

image

在直方图中,您可以看到 H = 100 和 S = 200 附近的一些高值。它对应于天空的蓝色。 类似地,在 H = 25 和 S = 100 附近可以看到另一个峰值。它对应于宫殿的黄色。 您可以使用任何图像编辑工具(如 GIMP)来验证它。

方法 3:OpenCV 示例样式!!

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

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

我将其留给读者运行代码、分析它并进行自己的 hack 操作。 下面是该代码对上述相同图像的输出

image

您可以在直方图中清楚地看到存在哪些颜色,蓝色存在,黄色存在,还有一些由于棋盘而产生的白色。 真好!!!