图像匹配学习笔记
1.模板匹配
含义:模板匹配就是通过现有的模板去与图片进行比较找出图中所匹配的图像。
简书:模板匹配就是一种用于在较大图像中搜索和查找模板图像位置的方法。为此,OpenCV带有一个函数cv2.matchTemplate()。它只是将模板图像滑动到输入图像上(2D卷积),然后在模板图像下比较模板和输入图像的补丁。OpenCV中实现了几种比较方法。它返回一个灰度图像,其中每个像素表示该像素的领域与模板匹配多少。如果输入图像的大小(W*H)和模板图像大小(w*h),这输出图像大小将为(W-w+1,H-h+1)。获得结果后,可以使用cv2.minMaxLoc()函数查找最大/最小值在哪里。
理解:模板在需要被检测的图像上从左到右,从上到下的滑动,每到达一个
模板在待检测的图像上从左至右,从上至下的滑动(我做了一个简陋的gif示意动画,如图),模板从源图像左上角开始每次以模板的左上角像素点为单位从左至右,从上至下移动,每到达一个像素点,就会以这个像素点为左上角顶点从源图像中截取出与模板一样大小的图像与模板进行像素比较运算。将比较计算的结果存入一个矩阵R中,OpenCV中共有6中计量方法。
(1)平方差匹配法:模板图像的像素减去覆盖的原图像的像素的平方和为对应矩阵的点的值,值越大匹配越差。method=CV_TM_SQDIFF
(2)归一化平方差匹配法。 method=CV_TM_SQDIFF_NORMED
(3)相关标识匹配法:模板和图像间的乘法操作,较大的数标识匹配程度较高,0标识最坏的结果。(有弊端)method=CV_TM_CCORR
(4)归一化相关匹配法。method=CV_TM_CCORR_NORMED
(5)相关系数匹配法。method=CV_TM_CCOEFF
(6)归一化相关系数匹配法。method=CV_TM_CCOEFF_NORMED
import cv2 import numpy as np src = cv2.imread("./jpg/8700.jpg") template = cv2.imread('./jpg/1.jpg') h,w,l = np.shape(template) def templateMacthing(src, template, method): result = cv2.matchTemplate(src, template, method) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) location = [0, 0] if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: location = min_loc score=min_val else: location = max_loc score = max_val cv2.rectangle(src, (location[0], location[1]), (location[0] + w, location[1] + h), (0, 0, 255), 3) cv2.imshow('result', src) cv2.waitKey(0) return location , score methods = [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED] locations = [] scores=[] templateMacthing(src, template, methods[5]) for method in methods: location,score=templateMacthing(src, template, method) locations.append(location) scores.append(score) print(locations) print(scores)
2.多尺度模板匹配(模板匹配的改进)
当模板大小和测试图片中的目标的大小之间存在着较大的差异时,cv2.matchtemplate()并不能获得准确的结果,使用滑窗思路在测试图片中只能获得对应大小的一块区域,针对此问题可以使用多尺度的模板匹配算法。
具体步骤:
1)在每次迭代中,图像都会被调整大小并计算Canny边缘图;
2)应用模板匹配,找到相关系数最大的图像的边界框(x,y)坐标;
3)最后,将这些值存储在簿记变量中;
4)在算法的最后,找到所有尺度上相关系数响应最大的区域的(x,y)-坐标,然后绘制边界框;
import cv2 import numpy as np import imutils # 加载模板图像,转换灰度图,检测边缘 # 使用边缘而不是原始图像进行模板匹配可以大大提高模板匹配的精度。 template = cv2.imread('./jpg/1.jpg') template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) template = cv2.Canny(template, 50, 200) (tH, tW) = template.shape[:2] cv2.imshow("Template", template) # 加载图像,转换为灰度图,初始化用于追踪匹配区域的簿记变量 image = cv2.imread("./jpg/400.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) found = None # 遍历图像尺寸 for scale in np.linspace(0.2, 1.0, 20)[::-1]: # 根据scale比例缩放图像,并保持其宽高比 resized = imutils.resize(gray, width=int(gray.shape[1] * scale)) r = gray.shape[1] / float(resized.shape[1]) # 缩放到图像比模板小,则终止 if resized.shape[0] < tH or resized.shape[1] < tW: break # 在缩放后的灰度图中检测边缘,进行模板匹配 # 使用与模板图像完全相同的参数计算图像的Canny边缘表示; # 使用cv2.matchTemplate应用模板匹配; # cv2.minMaxLoc获取相关结果并返回一个4元组,其中分别包含最小相关值、最大相关值、最小值的(x,y)坐标和最大值的(x,y)坐标。我们只对最大值和(x,y)-坐标感兴趣,所以只保留最大值而丢弃最小值。 edged = cv2.Canny(resized, 50, 200) result = cv2.matchTemplate(edged, template, cv2.TM_CCOEFF_NORMED) minVal, maxVal, minLoc, maxLoc= cv2.minMaxLoc(result) # 如果我们找到了一个新的最大校正值,更新簿记变量值 if found is None or maxVal > found[0]: found = (maxVal, maxLoc, r) # 解包簿记变量并基于调整大小的比率,计算边界框(x,y)坐标 (_, maxLoc, r) = found (startX, startY) = (int(maxLoc[0] * r), int(maxLoc[1] * r)) (endX, endY) = (int((maxLoc[0] + tW) * r), int((maxLoc[1] + tH) * r)) # 在检测结果上绘制边界框并展示图像 cv2.rectangle(image, (startX, startY), (endX, endY), (0, 0, 255), 2) cv2.imshow("Image", image) cv2.waitKey(0)
参考链接:
https://blog.csdn.net/qihoo_tech/article/details/107873079
https://blog.csdn.net/a906958671/article/details/89551856
https://blog.csdn.net/fu_shuwu/article/details/81427709
https://blog.csdn.net/WZZ18191171661/article/details/91345166
https://blog.csdn.net/qq_40985985/article/details/112230085