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()
函式中使用了相關方法,但也可以使用其他方法來比較直方圖。
單擊此連結瞭解有關直方圖方法的更多詳細資訊。