「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」
直方图的比较
我们已经在《灰度直方图详解》中学习了如何使用 cv2.calcHist()
函数计算直方图,并且了解了直方图的一些使用示例。
本节,我们将介绍 OpenCV
提供的另一个与直方图相关的函数是 cv2.compareHist()
,该函数可用于计算两个直方图的匹配程度。由于直方图反映了图像中像素值的强度分布,因此该函数也可以用于比较图像,但是由于直方图仅显示统计信息,而不显示像素的位置。因此,图像比较的常用方法是将图像划分为一定数量的区域(通常大小相同),计算每个区域的直方图,最后将所有直方图连接起来,创建图像的特征表示。为了简单起见,示例将仅使用一个区域(完整图像),并不会将图像划分多个区域。
cv2.compareHist()
函数的用法:
cv2.compareHist(H1, H2, method)
复制代码
这里,H1
和 H2
是被比较的直方图,method表示度量方法。OpenCV
提供了四种不同的度量方法( method )来计算匹配程度:
度量方法 | 解释 |
---|---|
cv2.HISTCMP_CORREL | 计算两个直方图之间的相关性,此指标返回 [-1, 1] 范围内的值,其中 1 表示完美匹配,-1 表示完全不匹配 |
cv2.HISTCMP_CHISQR | 计算两个直方图之间的卡方距离,此指标返回 [0, unbounded] 范围内的值,其中 0 表示完美匹配,而不匹配则使用 unbounded 表示 |
cv2.HISTCMP_INTERSECT | 计算两个直方图之间的交集,如果直方图被归一化,则该指标返回范围 [0, 1] 内的值,其中 1 表示完全匹配,0 表示完全不匹配 |
cv2.HISTCMP_BHATTACHARYYA | 计算两个直方图之间的 Bhattacharyya 距离。此指标返回 [0, 1] 范围内的值,其中 0 是完美匹配,1 完全不匹配 |
为了对比不同的度量方法,我们首先图像并对其进行变换,然后使用所有度量方法计算这些图像和测试图像之间的相似度。
# 加载图像
image = cv2.imread('example.png')
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
M = np.ones(gray_image.shape, dtype='uint8') * 30
# 所有像素值加上 30
added_image = cv2.add(gray_image, M)
# 所有像素值减去 30
subtracted_image = cv2.subtract(gray_image, M)
# 使用模糊滤镜
blurred_image = cv2.blur(gray_image, (10,10))
def load_all_test_images():
images = []
images.append(gray_image)
images.append(added_image)
images.append(subtracted_image)
images.append(blurred_image)
return images
复制代码
使用四种不同的度量方法计算这些图像和测试图像之间的相似度:
for img in test_images:
# 计算直方图
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
# 直方图归一化
hist = cv2.normalize(hist, hist, norm_type=cv2.NORM_L1)
hists.append(hist)
# 使用 cv2.HISTCMP_CORREL 度量方法
gray_gray = cv2.compareHist(hists[0], hists[1], cv2.HISTCMP_CORREL)
gray_grayblurred = cv2.compareHist(hists[0], hists[1], cv2.HISTCMP_CORREL)
gray_addedgray = cv2.compareHist(hists[0], hists[2], cv2.HISTCMP_CORREL)
gray_subgray = cv2.compareHist(hists[0], hists[3], cv2.HISTCMP_CORREL)
# 使用 cv2.HISTCMP_CHISQR 度量方法
gray_gray = cv2.compareHist(hists[0], hists[0], cv2.HISTCMP_CHISQR)
gray_grayblurred = cv2.compareHist(hists[0], hists[1], cv2.HISTCMP_CHISQR)
gray_addedgray = cv2.compareHist(hists[0], hists[2], cv2.HISTCMP_CHISQR)
gray_subgray = cv2.compareHist(hists[0], hists[3], cv2.HISTCMP_CHISQR)
# 使用 cv2.HISTCMP_INTERSECT 度量方法
gray_gray = cv2.compareHist(hists[0], hists[0], cv2.HISTCMP_INTERSECT)
gray_grayblurred = cv2.compareHist(hists[0], hists[1], cv2.HISTCMP_INTERSECT)
gray_addedgray = cv2.compareHist(hists[0], hists[2], cv2.HISTCMP_INTERSECT)
gray_subgray = cv2.compareHist(hists[0], hists[3], cv2.HISTCMP_INTERSECT)
# 使用 cv2.HISTCMP_BHATTACHARYYA 度量方法
gray_gray = cv2.compareHist(hists[0], hists[0], cv2.HISTCMP_BHATTACHARYYA)
gray_grayblurred = cv2.compareHist(hists[0], hists[1], cv2.HISTCMP_BHATTACHARYYA)
gray_addedgray = cv2.compareHist(hists[0], hists[2], cv2.HISTCMP_BHATTACHARYYA)
gray_subgray = cv2.compareHist(hists[0], hists[3], cv2.HISTCMP_BHATTACHARYYA)
复制代码
程序的输出如下所示:
从上图可以看出,img 1
所有指标都完美匹配,因为它是相同的图像,img 2
也具有较好的匹配指标,这是因为 img 2
是查询图像的平滑版本,而 img 3
和 img 4
给出的匹配程度很差,这是因为直方图发生了偏移。