再当前图像A 内寻找图像B 最相似的部分,A为输入图像,B为模板图像,操作方法是将模板图B再A 图上滑动,历遍所有像素以完成匹配。
result = cv2.matchTemplate(image , templ, method, [mark])
返回值是由每个位置的比较结果组合构成的一个结果集,类型是单通道32位浮点型,如果输入图像的尺寸是 WH 模板尺寸 wh ,返回值的尺寸为 (W-w+1) * (H-h+1)。进行模板匹配时,模板再原始图内历遍,水平方向上:
另外,参数method 决定使用不同的查找方法,对于不同的查找方法,返回值也具有不同的含义:
不管使用哪种方法,最后要使用 minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc( src [, mask] )
来查找最值的位置
# 举个栗子,method 的值为cv2.TM_SQDIFF,0表示最佳匹配,就要找最小值的位置。
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(matchTemplate 函数的返回值)
topLeft = minLoc # 查找最小值所在的位置
# topLeft 就是匹配位置的左上角,然后使用,w,h 来获得右下角坐标。
bottomRight = (topLeft[0] + w, topLeft[1] + h) #w 和 h 是模板图像的宽度和高度
通过上述方式得到了模板匹配的矩形对角坐标的位置,然后使用Img = cv.rectangle( img, pt1, pt2, color[, thickness])
将该位置标记出来,,就是画个矩形,参数就是图像,两个点,颜色,矩形线条的宽度
左图那个黑点就是最值了吧。。参数 method 的值为 cv2.TM_CCOEFF,查找的是最大值所在的位置。
有些情况下,要搜索的模板可能再输入图像内出现了多次,就需要找出多个匹配结果,但是 cv2.minMaxLoc() 仅可以找出最值,无法匹配所有的位置信息,这就需要利用阈值进行处理
am=np.array([[3,6,8,77,66],[1,2,88,3,98],[11,2,67,5,2]])
b=np.where(am>5)
print(b)
(array([0, 0, 0, 0, 1, 1, 2, 2], dtype=int64), # 两个数组构成索引
array([1, 2, 3, 4, 2, 4, 0, 2], dtype=int64))
loc = np.where( res >= threshold) # 找出函数cv2.matchTemplate()返回值中,那些位置的值大于阈值 threshold
霍夫变换是一种再图像中寻找直线,圆形集其他简单形状的方法,采用类似于投票的方式获取当前图像内的形状集合,
OpenCV 提供了函数 cv2.HoughLines()和函数 cv2.HoughLinesP()用来实现霍夫直线变换。
使用笛卡尔坐标系来说明霍夫变换的基本原理,与普通坐标系对象,构造霍夫坐标系,霍夫坐标系中,横坐标是笛卡尔坐标系中直线的斜率k,纵坐标使用笛卡尔坐标系中直线的截距b。可以说笛卡尔空间内的一条直线确定了霍夫空间的一个点,霍夫空间内的一点确定了笛卡尔空间的一条直线。
对于笛卡尔的一个点,通过该点的直线表示为 y=kx+b ,其中 kb 为任意量,映射到霍夫空间中就是一条直线了。
笛卡尔空间内两个点映射到霍夫空间的情况。
推广到N个点,笛卡尔空间内一条直线上由N个点,霍夫空间中就有穿过 (k,b) 点的N条直线。
综上,霍夫空间内,经过一个点的直线越多,说明其再笛卡尔空间内映射的直线是由越多的点构成的。计算中,我们希望用更多的点构造一条直线,提高直线的可靠性。也就是说一条直线由越多的点构成,它实际存在的可能性越大,可靠性越高。霍夫变换选择直线的基本思路是:选择尽可能多直线交汇的点。
对于垂直的情况,k无穷大,b无法取值,也无法映射到霍夫空间中,那就映射到极坐标系中。。 = cos + sin
可以这么想,原来 x,y 做直角边 ,r 做斜边sinθ=y/r cosθ=x/r, 第一个两边乘以sinθ,第二个两边乘cosθ,再相加得
极径r 表示与坐标原点的距离,参数 垂线和轴的角度,这种可以表示笛卡尔下所有的直线,并且映射到霍夫空间中的对应关系也一样,极坐标中一点映射到霍夫空间中就是一条线。。。
lines=cv2.HoughLines(image, rho, theta, threshold)
绘制直线的方法,对于垂直方向上各种角度的直线,计算与图像水平边界(图像第一行和最后一行)的交叉点,然后再这两个交叉点之间画线。水平方向上计算第一列和最后一列。然后使用cv2.line() 画线,即使坐标点不再图像范围内,也可以画出来。
img = cv2.imread('gonglu.jpg')
print(img.shape)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3) # 边缘检测,两个阈值,算子孔洞
orgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
oShow=orgb.copy()
lines = cv2.HoughLines(edges,1,np.pi/180,200) # (r,)返回值
for line in lines:
rho,theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho # x=cos()*r
y0 = b*rho
x1 = int(x0 + 1000*(-b)) # 由参数空间向实际坐标点转换,,就是扩一下坐标1000*(-b) 是个常数。。。
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(orgb,(x1,y1),(x2,y2),(0,0,255),2)
plt.subplot(121)
plt.imshow(oShow)
plt.axis('off')
plt.subplot(122)
plt.imshow(orgb)
plt.axis('off')
如果阈值设小了,就满图蓝线了。。那些看起来较粗的,就是几条混在一起了。使用霍夫变换可能将图像中有限个点碰巧对齐的非直线关系检测为直线,而导致误检测,尤其是一些复杂背景的图像,误检测会很明显,于是就有了改进版 概率霍夫变换。
是霍夫变换算法的优化。它没有考虑所有的点。相反,它只需要一个足以进行线检测的随机点子集即可。另外,它接受直线的最小长度,超过了阈值但是如果直线太短就忽略了。接受直线中允许的最大像素点间距,超过了阈值但是像素点距离很远也忽略。。
lines =cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap)
img = cv2.imread('house.jpg')
print(img.shape)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
orgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
oShow=orgb.copy()
lines = cv2.HoughLinesP(edges,1,np.pi/180,1,minLineLength=60,maxLineGap=10)
for line in lines:
x1,y1,x2,y2 = line[0] # 为啥这就不用那莫名其妙的变换。。
cv2.line(orgb,(x1,y1),(x2,y2),(255,0,0),5)
plt.subplot(121)
plt.imshow(oShow)
plt.axis('off')
plt.subplot(122)
plt.imshow(orgb) # 额 我找的图可能不太好。。。。
plt.axis('off')
只要是能够用一个参数方程表示的对象,都适合用霍夫变换来检测。
用霍夫圆变换来检测图像中的圆,与使用霍夫直线变换检测的直线的原理类似,不管需要考虑 半径,圆心(x,y)三个参数,方法就是使用两轮筛选,第一轮找到可能存在圆心的位置,第二轮再根据第一轮的结果筛选出半径大小。
circles=cv2.HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)
img = cv2.imread('qipan.jpg',0)
imgo=cv2.imread('qipan.jpg',-1)
o=cv2.cvtColor(imgo,cv2.COLOR_BGR2RGB)
oshow=o.copy()
img = cv2.medianBlur(img,5) # 进行平滑操作,
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,10, # 这个参数是非常不好调的,慢慢试试吧。。
param1=50,param2=40,minRadius=20,maxRadius=40)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(o,(i[0],i[1]),i[2],(0,0,255),4) # 圆
cv2.circle(o,(i[0],i[1]),2,(255,0,0),2) # 圆心
plt.subplot(121)
plt.imshow(oshow)
plt.axis('off')
plt.subplot(122)
plt.imshow(o)
plt.axis('off')