Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧。
基础知识铺垫
上篇博客 Python OpenCV 图像处理之图像直方图,取经之旅第 25 天中,我们重点学习了直方图的绘制方法与应用,本篇博客继续对直方图进行分析。
本篇博客咱们首先学习一下,如何用直方图去比较两幅图片的相似性。
通过 <kbd>cv2.compareHist</kbd> 函数计算图片的相似度,在今天的学习中,橡皮擦并没有 get 到一个特别好的场景,故本部分从语法角度进行学习。
cv2.compareHist 函数
该函数原型如下:
cv2.compareHist(H1, H2, method)
参数说明如下:
- H1,H2:要比较图像的直方图;
- method: 比较方式
其中比较方式涉及如下几种枚举值。
- <kbd>cv2.HISTCMP_CORREL</kbd>:相关性比较,值越大,相关度越高,最大值为 1,最小值为 0;
- <kbd>cv2.HISTCMP_CHISQR</kbd>:卡方比较,值越小,相关度越高,最大值无上界,最小值 0;
- <kbd>cv2.HISTCMP_BHATTACHARYYA</kbd>:巴氏距离比较,值越小,相关度越高,最大值为 1,最小值为 0;
- <kbd>cv2.HISTCMP_INTERSECT</kbd>:十字交叉,值越大越相似。
先比较灰度图的,运行下述代码即可。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def create_gray_hist(image):
# 创建一个灰度直方图
img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
hist = cv.calcHist([img], [0], None, [256], [0, 256])
return hist
def hist_compare(image1, image2):
# 第一幅图的灰度图直方图
hist1 = create_gray_hist(image1)
# 第二幅图的灰度图直方图
hist2 = create_gray_hist(image2)
# 进行三种方式的直方图比较
match1 = cv.compareHist(hist1, hist2, cv.HISTCMP_BHATTACHARYYA)
match2 = cv.compareHist(hist1, hist2, cv.HISTCMP_CORREL)
match3 = cv.compareHist(hist1, hist2, cv.HISTCMP_CHISQR)
match4 = cv.compareHist(hist1, hist2, cv.HISTCMP_INTERSECT)
print("巴氏距离:%s, 相关性:%s, 卡方:%s, 十字交叉:%s" % (match1, match2, match3, match4))
src1 = cv.imread("./black.jpg")
cv.imshow("diff1", src1)
src2 = cv.imread("./yellow.jpg")
cv.imshow("diff2", src2)
plt.subplot(1, 2, 1)
plt.title("diff1")
plt.plot(create_gray_hist(src1))
plt.subplot(1, 2, 2)
plt.title("diff2")
plt.plot(create_gray_hist(src2))
hist_compare(src1, src2)
plt.show()
while True:
k = cv.waitKey(0) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
结果如下图所示,这里我找的是两个相似的图片(从找不同游戏里面找到的)。
20210127191953928[1].png
得到的结果如下:
巴氏距离:0.0501735845451386, 相关性:0.9855477082033252, 卡方:3887.8752812639, 十字交叉:166493.0
由于两张图非常相似,得到的结果也符合刚才的说明。
- 巴氏距离:0.0501735845451386 >>> 值越小,相关度越高,最大值为 1,最小值为 0;
- 相关性:0.9855477082033252 >>> 值越大,相关度越高,最大值为 1,最小值为 0;
- 卡方:3887.8752812639 >>> 值越小,相关度越高,最大值无上界,最小值 0;(不过看起来,这个好像用处不大)
- 十字交叉:166493.0 >>> 十字交叉,值越大越相似。
切换成不同的两张图片,可以看一下运行结果,首先看灰度直方图。
20210127193407582[1].png在看得到的各个值:
巴氏距离:0.28273836677812036, 相关性:0.4615912771396342, 卡方:186501.9955618743, 十字交叉:126877.0
接下来,我们比较一下彩色图的直方图,这部分我也在网上看到了一个算法,但是由于代码实在没看太懂,直接忽略掉了。以下代码转载自网络,建议本阶段,看一下就好,不要钻牛角尖。
代码来源:网络。
def create_rgb_hist(image):
""""创建 RGB 三通道直方图(直方图矩阵)"""
h, w, c = image.shape
# 创建一个(16*16*16,1)的初始矩阵,作为直方图矩阵
# 16*16*16的意思为三通道每通道有16个bins
rgbhist = np.zeros([16 * 16 * 16, 1], np.float32)
bsize = 256 / 16
for row in range(h):
for col in range(w):
b = image[row, col, 0]
g = image[row, col, 1]
r = image[row, col, 2]
# 人为构建直方图矩阵的索引,该索引是通过每一个像素点的三通道值进行构建
index = int(b / bsize) * 16 * 16 + int(g / bsize) * 16 + int(r / bsize)
# 该处形成的矩阵即为直方图矩阵
rgbhist[int(index), 0] += 1
plt.ylim([0, 10000])
plt.grid(color='r', linestyle='--', linewidth=0.5, alpha=0.3)
return rgbhist
不过,除了灰度直方图,咱们用已有的知识可以比较不同通道的直方图。
具体代码修改部分如下:
def create_gray_hist(image):
# 创建一个灰度直方图
# img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
hist = cv.calcHist([image], [1], None, [256], [0, 256])
return hist
关于上文提及的 巴氏距离
,卡方
都属于统计学知识,暂时按下不表。
橡皮擦的小节
希望今天的一个小时,你有所收获,我们下篇博客见~
相关阅读
今天是持续写作的第 <font color="red">66</font> / 100 天。
如果你有想要交流的想法、技术,欢迎在评论区留言。
如果你想跟博主建立亲密关系,可以关注同名公众号 <font color="red">梦想橡皮擦</font>,近距离接触一个逗趣的互联网高级网虫。
博主 ID:梦想橡皮擦,希望大家<font color="red">点赞</font>、<font color="red">评论</font>、<font color="red">收藏</font>。
网友评论