opencv之模板匹配和霍夫变换(七)
一、模板匹配
模板匹配就是用模板图(通常是一个小图)在目标图像(通常是一个比模板图大的图片)中不断的滑动比较,通过某种比较方法来判断是否匹配成功,找到模板图所在的位置。
-
不会有边缘填充。
-
类似于卷积,滑动比较,挨个比较象素。
-
返回结果大小是:目标图大小-模板图大小-1。
匹配方法
res=cv2.matchTemplate(image, templ, method)
-
image:原图像,这是一个灰度图像或彩色图像(在这种情况下,匹配将在每个通道上独立进行)。
-
templ:模板图像,也是灰度图像或与原图像相同通道数的彩色图像。
-
method:匹配方法,可以是以下之一:
- cv2.TM_CCOEFF(平方差匹配)
- cv2.TM_CCOEFF_NORMED(归一化平方差匹配)
- cv2.TM_CCORR(相关系数匹配)
- cv2.TM_CCORR_NORMED(归一化相关系数匹配)
- cv2.TM_SQDIFF(相关匹配)
- cv2.TM_SQDIFF_NORMED(归一化相关匹配)
- 这些方法决定了如何度量模板图像与原图像子窗口之间的相似度。
-
返回值res
函数在完成图像模板匹配后返回一个结果矩阵,这个矩阵的大小与原图像相同。矩阵的每个元素表示原图像中相应位置与模板图像匹配的相似度。
匹配方法不同,返回矩阵的值的含义也会有所区别。以下是几种常用的匹配方法及其返回值含义:
-
cv2.TM_SQDIFF
或cv2.TM_SQDIFF_NORMED
:返回值越接近0,表示匹配程度越好。最小值对应的最佳匹配位置。
-
cv2.TM_CCORR
或cv2.TM_CCORR_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
-
cv2.TM_CCOEFF
或cv2.TM_CCOEFF_NORMED
:返回值越大,表示匹配程度越好。最大值对应的最佳匹配位置。
-
案例
import numpy as np
import cv2 as cv
# 读图
img = cv.imread("images/game.png")# 目标图
temp = cv.imread("images/temp.png")# 模板图
# 转灰度
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
temp_gray = cv.cvtColor(temp, cv.COLOR_BGR2GRAY)
# 模板匹配,拿到匹配结果,返回匹配成都矩阵
res = cv.matchTemplate(img_gray, temp_gray, cv.TM_CCOEFF_NORMED)
# 设置阈值,使用np.where()
threshold = 0.8
loc = np.where(res >= threshold)
# 获取模板宽高
h,w = temp.shape[:2]
# 解包,拿到坐标
# for pt in zip(*loc[::-1]):# pt ===>(y,x),所以翻转一下
# cv.rectangle(img, pt, (pt[0] + temp.shape[1], pt[1] + temp.shape[0]), (0, 0, 255), 2)
for pt in zip(*loc):# pt ===>(y,x),所以翻转一下
left_upper = pt[::-1] # 翻转一下(x,y)
right_lower = (pt[1] + w, pt[0] + h)
cv.rectangle(img, left_upper, right_lower, (0, 0, 255), 2,cv.LINE_AA)
# 绘制出匹配的部分并且框出来
cv.imshow("img", img)
cv.waitKey()
cv.destroyAllWindows()
二、霍夫变换
2.1 理解霍夫变换
- 霍夫变换是图像处理的一种技术,主要用于检测图像中的直线、圆等几何形状。基本思想就是将图像空间中的点映射到参数空间中,通过在参数空间中寻找累计最大值实现对特定形状的检测。
2.2 霍夫直线变换
使用API
lines=cv2.HoughLines(image, rho, theta, threshold)
image
:输入图像,通常为二值图像,其中白点表示边缘点,黑点为背景。rho
:r的精度,以像素为单位,表示霍夫空间中每一步的距离增量, 值越大,考虑越多的线。theta
:角度θ的精度,通常以弧度为单位,表示霍夫空间中每一步的角度增量。值越小,考虑越多的线。threshold
:累加数阈值,只有累积投票数超过这个阈值的候选直线才会被返回。
返回值:cv2.HoughLines
函数返回一个二维数组,每一行代表一条直线在霍夫空间中的参数 (rho, theta)
。
2.3 统计概率霍夫直线变换
前面的方法又称为标准霍夫变换,它会计算图像中的每一个点,计算量比较大,另外它得到的是整一条线(r和θ),并不知道原图中直线的端点。所以提出了统计概率霍夫直线变换(Probabilistic Hough Transform),是一种改进的霍夫变换,它在获取到直线之后,会检测原图中在该直线上的点,并获取到两侧的端点坐标,然后通过两个点的坐标来计算该直线的长度,通过直线长度与最短长度阈值的比较来决定该直线要不要被保留。
使用API
lines=cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=0, maxLineGap=0)
image
:输入图像,通常为二值图像,其中白点表示边缘点,黑点为背景。rho
:极径分辨率,以像素为单位,表示极坐标系中的距离分辨率。theta
:极角分辨率,以弧度为单位,表示极坐标系中角度的分辨率。threshold
:阈值,用于过滤掉弱检测结果,只有累计投票数超过这个阈值的直线才会被返回。lines
(可选):一个可初始化的输出数组,用于存储检测到的直线参数。minLineLength
(可选):最短长度阈值,比这个长度短的线会被排除。maxLineGap
(可选):同一直线两点之间的最大距离。当霍夫变换检测到一系列接近直角的线段时,这些线段可能是同一直线的不同部分。maxLineGap
参数指定了在考虑这些线段属于同一直线时,它们之间最大可接受的像素间隔。
返回值lines:cv2.HoughLinesP
函数返回一个二维数组,每个元素是一个包含4个元素的数组,分别表示每条直线的起始点和结束点在图像中的坐标(x1, y1, x2, y2)。
2.4 霍夫圆变换
霍夫圆变换跟直线变换类似,它可以从图像中找出潜在的圆形结构,并返回它们的中心坐标和半径。只不过线是用(r,θ)表示,圆是用(x_center,y_center,r)来表示,从二维变成了三维,数据量变大了很多;所以一般使用霍夫梯度法减少计算量。
使用API
circles=cv2.HoughCircles(image, method, dp, minDist, param1, param2)
-
image
:输入图像,通常是灰度图像。 -
method
:使用的霍夫变换方法:霍夫梯度法,可以是cv2.HOUGH_GRADIENT
,这是唯一在OpenCV中用于圆检测的方法。 -
dp
:累加器分辨率与输入图像分辨率之间的降采样比率,用于加速运算但不影响准确性。设置为1表示霍夫梯度法中累加器图像的分辨率与原图一致 -
minDist
:检测到的圆心之间的最小允许距离,以像素为单位。在霍夫变换检测圆的过程中,可能会检测到许多潜在的圆心。minDist
参数就是为了过滤掉过于接近的圆检测结果,避免检测结果过于密集。当你设置一个较小的minDist
值时,算法会尝试找出尽可能多的圆,即使是彼此靠得很近的圆也可能都被检测出来。相反,当你设置一个较大的minDist
值时,算法会倾向于只检测那些彼此间存在一定距离的独立的圆。
案例
案例一:霍夫直线变换
import numpy as np
import cv2 as cv
img = cv.imread("images/huofu.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 边缘检测
dst = cv.Canny(gray, 30, 70)
# 霍夫直线变换:lienes=cv2.HoughLines(img,rho,theta,threshold) # threshold是阈值,rho和theta是精度
lines = cv.HoughLines(dst, 0.8, np.pi / 180, 90)
# 遍历lines,去取每条直线的rho和theta
for line in lines:
rho ,theta = line[0] # lines是二维数组,[[rho,theta]]
sin_theta = np.sin(theta)
cos_theta = np.cos(theta)
x1,x2 = 0,img.shape[1]
y1=int((rho-x1*cos_theta)/sin_theta)
y2=int((rho-x2*cos_theta)/sin_theta)
cv.line(img,(x1,y1),(x2,y2),(0,0,255),2)
cv.imshow("img",img)
cv.waitKey(0)
cv.destroyAllWindows()
案例二:统计概率霍夫直线变换
# 统计概率霍夫直线变换
import numpy as np
import cv2 as cv
img = cv.imread("images/huofu.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 边缘检测
dst = cv.Canny(gray, 30, 70)
# 统计概率霍夫直线变换
lines = cv.HoughLinesP(dst, 1, np.pi / 180, 10, minLineLength=10, maxLineGap=10)
for line in lines:
x1, y1, x2, y2 = line[0]
cv.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2,cv.LINE_AA)
cv.imshow("img", img)
cv.waitKey()
cv.destroyAllWindows()
案例三:霍夫圆变换
# 霍夫圆变换
import numpy as np
import cv2 as cv
img = cv.imread("images/huofu.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 边缘检测
dst = cv.Canny(gray, 30, 70)
# 霍夫圆变换
circles = cv.HoughCircles(dst, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
# 数据处理
circles = np.uint16(np.around(circles))
for circle in circles:
x,y,r = circle[0]
cv.circle(img, (x,y), r, (0,255,0), 2,cv.LINE_AA)
cv.imshow("img", img)
cv.waitKey()
cv.destroyAllWindows()