参考:
https://stackoverflow.com/questions/11541154/checking-images-for-similarity-with-opencv
1、比较直方图
最简单和最快速的方法之一。 建议几十年前作为一种手段来找到图片相似之处。 这个想法是,一个森林将有很多的绿色,人脸很多粉红色,或其他颜色。 所以,如果你将两幅图片的森林进行比较,你会得到直方图之间的一些相似之处,因为两者都有很多的绿色。
缺点:这太简单了。 香蕉和海滩看起来是一样的,因为两者都是黄色的。
OpenCV方法:compareHist()
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread("messi5.jpg")
# Comparing histograms
H1=cv2.calcHist([img],[1],None,[256],[0,256]) # 统计第2个波段
H1=cv2.normalize(H1,H1,0,1,cv2.NORM_MINMAX,-1) # 归一化
H2=cv2.calcHist([img],[2],None,[256],[0,256])
H2=cv2.normalize(H2,H2,0,1,cv2.NORM_MINMAX,-1)
Similarity=cv2.compareHist(H1,H2,0) # 比较直方图
print(Similarity) # 0.55
plt.subplot(2,1,1);plt.plot(H1)
plt.subplot(2,1,2);plt.plot(H2)
plt.show()
2、模板匹配
这里的一个很好的例子是matchTemplate找到好匹配。 它将搜索图像与正在搜索的图像进行卷积。 通常用于查找更大的图像部分。
缺点:只有相同的图像,相同的尺寸和方向才能返回良好的效果。
OpenCV方法:matchTemplate()
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',1)
img2 = img.copy()
template = cv2.imread('messi_face.jpg',1)
template=cv2.resize(template,None,fx=1.5,fy=2)
h, w,c = template.shape
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
# Apply template Matching
res = cv2.matchTemplate(img,template,cv2.TM_CCOEFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc
bottom_right = (top_left[0] + h, top_left[1] + w)
cv2.rectangle(img,top_left, bottom_right, 255, 2)
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle("TM_CCOEFF")
plt.show()
附加
霍夫圆变换找太阳
# -*- coding: UTF-8 -*-
import cv2
import numpy as np
image=cv2.imread("b2gUH.png")
# Color to Gray
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# color threshold
_,gray=cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
# Morphologic open for 2 times
dst=cv2.morphologyEx(gray,cv2.MORPH_OPEN,None,iterations=2)
# 使用霍夫圆变换
circles = cv2.HoughCircles(dst,cv2.HOUGH_GRADIENT,12,dst.shape[1]/2,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(image,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(image,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow("dst",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
模板匹配找太阳
# -*- coding: UTF-8 -*-
import cv2
import numpy as np
# Load image and template
img=cv2.imread("b2gUH.png")
templ =cv2.imread("sun.png")
# Create the result matrix
result_cols = img.shape[1] - templ.shape[1] + 1;
result_rows = img.shape[0] - templ.shape[0] + 1;
result=np.zeros([result_rows,result_cols],np.float32)
# Do the Matching and Normalize
result=cv2.matchTemplate(img,templ,cv2.TM_CCOEFF)
cv2.normalize(result,result,0,1,cv2.NORM_MINMAX,-1)
min_val, max_val, min_loc, max_loc=cv2.minMaxLoc(result)
top_left = max_loc
bottom_right = (top_left[0] + templ.shape[0], top_left[1] + templ.shape[1])
cv2.rectangle(img,top_left,bottom_right,(0, 255, 0),2,cv2.LINE_AA)
cv2.rectangle(result,top_left,bottom_right,(0, 255, 0),2,cv2.LINE_AA)
cv2.imshow("img",img)
cv2.imshow("result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
3、特征匹配
被认为是最有效的图像搜索方法之一。 从图像中提取许多特征,以确保即使旋转/缩放/倾斜也能再次识别相同的特征。 以这种方式提取的特征可以与其他图像特征集匹配。 另一个在第一个图像中具有高比例特征的图像很可能描绘了同一个对象/场景。 它可以用来查找图片之间拍摄角度的相对差异,或重叠的数量。
这里有一些OpenCV的教程/示例,还有一个很好的视频。 整个OpenCV模块(features2d)专门用于它。
缺点:可能会很慢。 这并不完美。
http://answers.opencv.org/question/877/how-to-match-2-hog-for-object-detection/#882
4、方法总结
import cv2
class CompareImage(object):
def __init__(self, image_1_path, image_2_path):
self.minimum_commutative_image_diff = 0.25
self.image_1_path = image_1_path
self.image_2_path = image_2_path
def compare_image(self):
image_1 = cv2.imread(self.image_1_path, 0)
image_2 = cv2.imread(self.image_2_path, 0)
img_hist_diff, img_template_diff, commutative_image_diff = self.get_image_difference(image_1, image_2)
if img_hist_diff<0.3 and img_template_diff<0.3:
if commutative_image_diff < self.minimum_commutative_image_diff:
print("Matched")
return commutative_image_diff
return 10000 # random failure value
@staticmethod
def get_image_difference(image_1, image_2):
first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256])
second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256])
img_hist_diff = 1-cv2.compareHist(first_image_hist, second_image_hist,0)
img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0]
img_template_diff = 1 - img_template_probability_match
# taking only 10% of histogram diff, since it's less accurate than template method
commutative_image_diff = (img_hist_diff / 10) + img_template_diff
return [img_hist_diff,img_template_diff,commutative_image_diff]
if __name__ == '__main__':
compare_image = CompareImage('E:/07/L15-3345E-2311N.tif', 'E:/08/L15-3345E-2311N.tif')
image_difference = compare_image.compare_image()
print(image_difference)