【计算机知识学习】OpenCV——模板匹配、霍夫变换

模板匹配

原理

模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果。

模板块每次移动一个像素 (从左往右,从上往下),在每一个位置,都计算与模板图像的相似程度

对于每一个位置将计算的相似结果保存在结果矩阵(R)中。如果输入图像的大小(WxH)且模板图像的大小(wxh),则输出矩阵R的大小为(W-w + 1,H-h + 1)将R显示为图像

获得上述图像后,查找最大值所在的位置,那么该位置对应的区域就被认为是最匹配的。对应的区域就是以该点为顶点,长宽和模板图像一样大小的矩阵。

API

res = cv.matchTemplate(img,template,method)

参数:

img: 要进行模板匹配的图像

Template :模板

  • method:实现模板匹配的算法,主要有:
    1. 平方差匹配(CV_TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。
    2. 相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。
    3. 利用相关系数匹配(CV_TM_CCOEFF):利用模板与图像间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配。

完成匹配后,使用cv.minMaxLoc()方法查找最大值所在的位置即可。如果使用平方差作为比较方法,则最小值位置是最佳匹配位置。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1 图像和模板读取
img = cv.imread("D:\Python\Opencvlearn\\02.code\image\wulin.jpeg")
template = cv.imread("D:\Python\Opencvlearn\\02.code\image\\bai.jpeg")
h,w,l = template.shape
# 2 模板匹配
# 2.1 模板匹配
res = cv.matchTemplate(img,template,cv.TM_CCORR)
# 2.2 返回图像中最匹配的位置,确定左上角的坐标,并将匹配位置绘制在图像上
min_val,max_val,min_loc,max_loc = cv.minMaxLoc(res)
# 使用平方差时最小值为最佳匹配位置
# top_left = min_loc
top_left = max_loc
bottom_right = (top_left[0]+w,top_left[1]+h)
cv.rectangle(img,top_left,bottom_right,(0,255,0),2)
# 3 图像显示
plt.imshow(img[:,:,::-1])
plt.title("The result of match"),plt.xticks([]),plt.yticks([])
plt.show()

拓展:模板匹配不适用于尺度变换,视角变换后的图像,这时我们就要使用关键点匹配算法,比较经典的关键点检测算法包括SIFTSURF等,主要的思路是首先通过关键点检测算法获取模板和测试图片中的关键点;然后使用关键点匹配算法处理即可,这些关键点可以很好的处理尺度变化、视角变换、旋转变化、光照变化等,具有很好的不变性。

霍夫变换

霍夫变换常用来提取图像中的直线和圆等几何形状

霍夫线检测

API

cv.HoughLines(img, rho, theta, threshold)

参数:

  • img: 检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
  • rhotheta: ρ θ的精确度
  • threshold: 阈值,只有累加器中的值高于该阈值时才被认为是直线。
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import random
# 1.加载图片,转为二值图
img = cv.imread("D:\Python\Opencvlearn\\02.code\image\\rili.jpg")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150)
# 2.霍夫直线变换
lines = cv.HoughLines(edges,0.8,np.pi/180,150)
# 3.将检测的线绘制在图像上(注意是极坐标噢)
for line in lines:
    rho,theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))
    cv.line(img,(x1,y1),(x2,y2),(0,255,0))
# 4. 图像显示
plt.figure(figsize=(10,8), dpi=100)
plt.imshow(img[:,:,::-1]),plt.title("霍夫变换线检测")
plt.xticks([]),plt.yticks([])
plt.show()

霍夫圆检测[了解]

原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。

API

cv2.circle()方法用于在任何图像上绘制圆。

cv2.circle(image, center_coordinates, radius, color, thickness)

参数:
image:它是要在其上绘制圆的图像。
center_coordinates它是圆的中心坐标。坐标表示为两个值的元组,即(X坐标值,Y坐标值)
radius:它是圆的半径。
color:它是要绘制的圆的边界线的颜色。对于BGR,我们通过一个元组。例如:(25500)为蓝色。
thickness:它是圆边界线的粗细像素。厚度-1像素将以指定的颜色填充矩形形状。

OpenCV中检测图像中的圆环使用的是API是:

circles = cv.HoughCircles(image, method, dp, minDist, param1=100, param2=100, minRadius=0,maxRadius=0 )

参数:

    • image:输入图像,应输入灰度图像
    • method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT
    • dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
    • minDist为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
    • param1:边缘检测时使用Canny算子的高阈值,低阈值是高阈值的一半。
    • param2:检测圆心和确定半径时所共有的阈值
    • minRadius和maxRadius为所检测到的圆半径的最小值和最大值

返回:

  1. circles:输出圆向量,包括三个浮点型的元素——圆心横坐标,圆心纵坐标和圆半径
  2. 实现    由于霍夫圆检测对噪声比较敏感,所以首先对图像进行中值滤波。
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import random
# 导入
img = cv.imread('D:\Python\Opencvlearn\\02.code\image\star.jpeg')
# BGR图像转为RGB图像, plt可以正常显示
img_RGB = cv.cvtColor(img, cv.COLOR_BGR2RGB)
plt.subplot(121), plt.imshow(img_RGB, cmap='gray')
plt.title('Original img'), plt.xticks([]), plt.yticks([])
# 去噪
img_blur = cv.medianBlur(img,5)
img_gray = cv.cvtColor(img_blur, cv.COLOR_BGR2GRAY)
circles = cv.HoughCircles(img_gray, cv.HOUGH_GRADIENT, 1, 40,
 param1=200, param2=50, minRadius=50, maxRadius=130)
# circles = cv.HoughCircles(img_gray,cv.HOUGH_GRADIENT,1,80,
#  param1=150,param2=40,minRadius=30,maxRadius=80)
circles = np.uint16(np.around(circles))   # 这里不懂,所以课件中的代码一直实现不了,这个是csdn复制的。
for i in circles[0, :]:
 # 绘制外圆
 img_circle = cv.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
 # 绘制圆心
 img_circlep = cv.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)
img_circlep = cv.cvtColor(img_circlep, cv.COLOR_BGR2RGB)
plt.subplot(122), plt.imshow(img_circlep, cmap='gray')
plt.title("detected circles (minDist=40)"), plt.xticks([]), plt.yticks([])
plt.show()

你可能感兴趣的:(OpenCV,学习,python,opencv,pycharm)