OpenCV 比较图像
本教程将讨论使用 OpenCV 的 norm()
和 compareHist()
函数比较图像。
使用 OpenCV 的 norm()
函数比较图像
如果我们要比较的两个图像具有相同的大小和方向,我们可以使用 OpenCV 的 norm()
函数。此函数查找两个图像的相同像素中存在的错误。
我们必须找到 L2 误差,也就是平方误差和的平方根,然后将其除以图像中存在的像素总数,以找出它们之间的相似性。
我们通过将行数乘以给定图像之一中存在的列数来获得像素总数。
例如,让我们使用 NumPy
的 zeros()
函数创建两个相同的图像,并使用 norm()
函数找到它们的相似性。请参阅下面的代码。
import cv2
import numpy as np
height = 312
width = 312
A = np.zeros((height, width, 3), np.uint8)
B = np.zeros((height, width, 3), np.uint8)
errorL2 = cv2.norm(A, B, cv2.NORM_L2)
similarity = 1 - errorL2 / (height * width)
print("Similarity = ", similarity)
cv2.imshow("A", A)
cv2.imshow("B", B)
cv2.waitKey(0)
输出:
Similarity = 1.0
正如我们所见,两个图像是相同的。这就是为什么相似度是 1% 或 100%。
现在让我们在一张图像中添加一些颜色并与另一张图像进行比较。
例如,让我们将一半图像的颜色设置为红色,然后将其与另一张图像进行比较。请参阅下面的代码。
import cv2
import numpy as np
height = 312
width = 312
A = np.zeros((height, width, 3), np.uint8)
B = np.zeros((height, width, 3), np.uint8)
B[0 : width // 2, :, :] = (0, 0, 255)
errorL2 = cv2.norm(A, B, cv2.NORM_L2)
similarity = 1 - errorL2 / (height * width)
print("Similarity = ", similarity)
cv2.imshow("A", A)
cv2.imshow("B", B)
cv2.waitKey(0)
输出:
Similarity = 0.4220761884533025
由于一张图像中的红色,相似度有所降低。
此方法仅在两个图像具有相同大小和方向时才有用;否则,此方法无用。
使用 OpenCV 的 compareHist()
函数比较图像
我们可以使用 OpenCV 的 compareHist()
函数找到两个图像之间的相似性。compareHist()
函数根据颜色比较两个图像的直方图。
此方法仅根据颜色比较图像,因此在我们不关心对象的形状或方向的地方很有用。
例如,一棵树和一片森林将具有 100% 的相似性,因为这两个图像都有许多绿色。
要使用 compareHist()
函数比较两个图像,我们必须使用 OpenCV 的 cvt.Color()
函数将图像转换为 HSV,然后使用 calcHist()
函数找到图像的直方图。
之后,我们可以使用 normalize()
函数对直方图进行归一化以进行比较。然后,我们必须在 compareHist()
函数中传递两个图像的归一化直方图以及比较方法。
compareHist()
函数将相似度作为浮点数返回。如果相似度为 1,则表示图像 100% 相同,如果接近 0,则表示两幅图像不相似。
例如,让我们使用其中包含多个水果的图像作为基础图像,并使用另外两个也包含单个水果的测试图像。
请参阅下面的代码。
import cv2 as cv
import numpy as np
base = cv.imread("Base.jpg")
test = cv.imread("test.jpg")
test2 = cv.imread("test2.jpg")
hsv_base = cv.cvtColor(base, cv.COLOR_BGR2HSV)
hsv_test = cv.cvtColor(test, cv.COLOR_BGR2HSV)
hsv_test2 = cv.cvtColor(test2, cv.COLOR_BGR2HSV)
h_bins = 50
s_bins = 60
histSize = [h_bins, s_bins]
h_ranges = [0, 180]
s_ranges = [0, 256]
ranges = h_ranges + s_ranges
channels = [0, 1]
hist_base = cv.calcHist([hsv_base], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_base, hist_base, alpha=0, beta=1, norm_type=cv.NORM_MINMAX)
hist_test = cv.calcHist([hsv_test], channels, None, histSize, ranges, accumulate=False)
cv.normalize(hist_test, hist_test, alpha=0, beta=1, norm_type=cv.NORM_MINMAX)
hist_test2 = cv.calcHist(
[hsv_test2], channels, None, histSize, ranges, accumulate=False
)
cv.normalize(hist_test2, hist_test2, alpha=0, beta=1, norm_type=cv.NORM_MINMAX)
compare_method = cv.HISTCMP_CORREL
base_base = cv.compareHist(hist_base, hist_base, compare_method)
base_test = cv.compareHist(hist_base, hist_test, compare_method)
base_test2 = cv.compareHist(hist_base, hist_test2, compare_method)
print("base_base Similarity = ", base_base)
print("base_test Similarity = ", base_test)
print("base_test2 Similarity = ", base_test2)
cv.imshow("base", base)
cv.imshow("test1", test)
cv.imshow("test2", test2)
cv.waitKey(0)
输出:
base_base Similarity = 1.0
base_test Similarity = 0.9850943125966266
base_test2 Similarity = -0.00323646777704442
如输出所示,基本图像与基本图像的相似度为 1% 或 100%,因为两个图像相同。
test
图像与基本图像的相似度为 0.98 或 98%,因为 test
图像包含的香蕉也存在于基本图像中。
test2
图像与基本图像的相似度接近于 0,因为 test2
图像中存在的水果和颜色在基本图像中不存在。
OpenCV 的 calcHist()
和 normalize()
函数的参数
在上面的代码中,calcHist()
函数的第一个参数是 HSV 颜色空间中的图像。第二个参数是我们想要用来查找直方图的给定图像的通道。
第三个参数用于传递掩码,如果我们想查找图像的一部分而不是整个图像的直方图,它会很有用。第四个参数是直方图的大小,它包含直方图箱的高度和大小。
第五个参数是 HSV 颜色空间的色调和饱和度范围。
normalize()
函数的第一个参数是我们想要标准化的源图像。
第二个参数是目标图像,创建具有我们所需尺寸或大小的输出图像。第三个参数是我们想要标准化图像的范围的下限值。
第四个参数是我们想要标准化图像的范围的上限值。第五个参数是归一化类型,如 cv2.NORM_INF
、cv2.NORM_L1
和 cv2.NORM_MINMAX
。
每个归一化类型都使用其公式来计算归一化。第六个参数用于设置输出图像的数据类型。
第七个参数用于创建遮罩,当我们不想标准化整个图像时它很有用。相反,我们只想规范化图像的一部分。
我们可以在掩码中定义该部分,以便仅对掩码部分执行归一化。
我们在 compareHist()
函数中使用了相关方法,但也可以使用其他方法来比较直方图。
单击此链接了解有关直方图方法的更多详细信息。