二维直方图
目标
在本篇文章中,我们将学习查找和绘制2D直方图,包括以下内容:
- OpenCV中的二维直方图
- Numpy中的二维直方图
- 绘制二维直方图
- 示例补充
前言
在直方图板块的第一篇文章图像直方图的查找、绘制和分析中,我们计算并绘制了一维直方图, 之所以称为一维,是因为我们仅考虑一个特征,即像素的灰度强度值。 但是在二维直方图中,需要考虑两个特征,通常,它用于查找颜色直方图,其中两个特征是每个像素的色相和饱和度值。我们将尝试了解如何创建这种颜色直方图,它将有助于理解像直方图反向投影这样的更深入的内容。
1. OpenCV中的二维直方图
它非常简单,并且使用相同的函数cv.calcHist()进行计算。 对于颜色直方图,我们需要将图像从BGR转换为HSV。(请记住,对于一维直方图,我们从BGR转换为灰度)。对于二维直方图,其参数将进行如下修改:
- channel = [0,1],因为我们需要同时处理H和S平面。
- bins = [180,256] 对于H平面为180,对于S平面为256。
- range = [0,180,0,256] 色相值介于0和180之间,饱和度介于0和256之间。
演示代码1:
import numpy as np
import cv2 as cv
# 加载原始图像
img = cv.imread('./data/leuvenA.jpg')
# 显示原始图像
cv.imshow('img2', img)
# 转化为HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 显示HSV图像
cv.imshow('hsv', hsv)
# cv.calcHist() 来查找整个图像的二维直方图
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 可调整窗口大小
cv.namedWindow('2Dhist_img', 0)
# 显示二维直方图
cv.imshow('2Dhist_img', hist) # 显示图像窗口较小,窗口可调整
cv.waitKey()



2. Numpy中的二维直方图
Numpy还为此提供了一个特定的函数:np.histogram2d()。
注意: 对于一维直方图我们使用了
np.histogram()。
演示代码2:
import numpy as np
import cv2 as cv
# 加载原始图像
img = cv.imread('./data/leuvenA.jpg')
# 转化为HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 分离出h, s通道
h, s = hsv[:, :, 0], hsv[:, :, 1]
# cv.histogram2d() 来查找整个图像的二维直方图
hist, xbins, ybins = np.histogram2d(h.ravel(), s.ravel(), [180, 256], [[0, 180], [0, 256]])
# 可调整窗口大小
cv.namedWindow('2Dhist_img', 0)
# 显示二维直方图
cv.imshow('2Dhist_img', hist) # 显示图像窗口较小,窗口可调整
cv.waitKey()
结果与上述在opencv中实现的一致。

Tips:
np.histogram2d()函数中,第一个参数是H平面,第二个是S平面,第三个是每个bin的数量,第四个是色相值和饱和度值的范围。
3. 绘制二维直方图
3.1 使用 cv.imshow()绘制
我们得到的结果是尺寸为 180x256 的二维数组。
print(hist.shape)
>>>(180, 256)
因此,可以使用cv.imshow()函数像平常一样显示它们。上面的演示代码1和演示代码2就是用cv.imshow()绘制的二维直方图,它是一幅灰度图像,除非你知道不同颜色的色相值,否则不会对其中的颜色有太多了解。
3.2 使用Matplotlib绘制
我们可以使用matplotlib.pyplot.imshow()函数绘制具有不同颜色图的2D直方图。它使我们对不同的像素密度有更好的了解。但是,除非你知道不同颜色的色相值,否则乍一看并不能使我们知道到底是什么颜色。我还是更喜欢这种方法,它简单而更好。
注意: 使用此功能时,请记住,插值法应采用最近邻以获得更好的结果。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 加载原始图像
img = cv.imread('./data/leuvenA.jpg')
# 转化为HSV
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# cv.calcHist() 来查找整个图像的二维直方图
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# 原图cv读取BGR通道顺序转换成Matplotlib的RGB通道顺序,为了正常显示图像
img_BGR2RGB = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# HSV图像cv处理的BGR通道顺序转换成Matplotlib的RGB通道顺序,为了正常显示图像
hsv_BGR2RGB = cv.cvtColor(hsv, cv.COLOR_BGR2RGB)
plt.subplot(131), plt.imshow(img_BGR2RGB), plt.title('Original_img')
plt.subplot(132), plt.imshow(hsv_BGR2RGB), plt.title('hsv_img')
plt.subplot(133), plt.imshow(hist, interpolation='nearest'), plt.title('2Dhist_img')
# 显示直方图
plt.show()
下面是输入图像及其颜色直方图。X轴显示饱和度S值,Y轴显示色相H值.


在直方图6中,你可以在H = 110和S = 25附近看到一些较高的值。它对应于天空的白灰色。同样,在H = 30和S = 30附近可以看到另一个峰值。它对应屋子的红砖色。
4. 补充一个示例
为加深对二维直方图Matplotlib绘制的理解,在此再给出一个补充示例,根据个人需要进行学习参考。
import cv2 as cv
from matplotlib import pyplot as plt
images = []
hists = []
# 图像二维直方图(Image 2D Histograms)
image_file_name = ['E:/Opencv-python-exercises/OpenCV4.1Tutorials/data/home.jpg', 'E:/Opencv-python-exercises/OpenCV4.1Tutorials/data/lena.jpg']
for i in range(len(image_file_name)):
# 读取图像
image = cv.imread(image_file_name[i])
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
hsv_image = cv.cvtColor(image, cv.COLOR_RGB2HSV)
hist = cv.calcHist([hsv_image], [0, 1], None, [180, 256], [0, 180, 0, 256])
images.append(image)
hists.append(hist)
# 显示图像
plt.figure('Image Display: 2D Histograms')
for i in range(len(images)):
plt.subplot(2, 2, i * 2 + 1)
plt.imshow(images[i], cmap='gray')
plt.title('Original Image')
plt.xticks([])
plt.yticks([])
plt.subplot(2, 2, i * 2 + 2)
plt.imshow(hists[i], interpolation='nearest')
plt.title('2D Histogram')
plt.show()

5. 总结
在本篇文章中,主要介绍了二维直方图的查找及绘制,分析了OpenCV中的二维直方图与一维直方图的区别,解释了Numpy中二维直方图函数np.histogram2d()各参数含义,并利用cv.imshow()与Matplotlib分别绘制了二维直方图,最后还给出了一个补充示例,加深对二维直方图Matplotlib绘制的理解。
如果文章对你有帮助,欢迎一键三连哦~~
269



被折叠的 条评论
为什么被折叠?



