[图像识别]8.OpenCV的模板匹配和霍夫检测

回顾,上节课你学了什么?

 Sobel_x_or_y=cv.Sobel(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

常用 Sobel_x_or_y=cv.Sobel(img,cv.CV_ 16S,dx,dy,ksize)

格式转换Scale_abs=cv.convertScaleAbs(x)

result=cv.addWeighted(img1,p1,img2,p2,k)

laplacian=cv.Laplacian(img,ddepth,dx,dy,dst,ksize,scale,delta,borderType)

canny=cv.Canny(img,threshold1,threshold2)

目录

模板匹配

霍夫变换

一、霍夫线检测

 二、霍夫圆检测

 总结,这节课你学到了什么?


模板匹配

1.原理

建立一个模板图像,不断移动模板图像来检测匹配程度,找到最高的匹配区域

2.步骤

【1】将原图像(W x H)与模板图像(w x h)计算匹配程度,将结果保存在矩阵R(W-w+1 x H-h+1)里面

【2】找到R矩阵中像素最大(即匹配度最大)的点位置,则这个点为顶点长宽为模板大小的区域就是匹配区域。

3.API代码

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

img:原图像

template:模板图像

method:匹配算法

1.平方差匹配(cv.TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。
2.相关匹配(cv.TM _CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度较高,越小表示匹配效果差。
3.利用相关系数匹配(cv.TM_CCOEFF):利用模板与图像间的相关系数匹配,1表示完美的匹配,-1表示最差的匹配。

匹配完成后得到矩阵使用函数

minVal,maxVal,minLoc,maxLoc=cv.minMaxLoc(R)

minVal:最小值

maxVal:最大值

minLoc:最小值位置

maxLoc:最大值位置

找到最大值所在位置;如果是CV_ TM_ SQDIFF,则找到最小值

举例:

#7.1

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
#解决中文显示问题,固定格式,直接复制下面俩行代码就行
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

#1.读取图像
pic1 = cv.imread("8.jpeg")
template = cv.imread("8tem.jpeg")
#2.获得匹配矩阵R
R=cv.matchTemplate(pic1,template,cv.TM_SQDIFF)
#3.获得矩阵R的最好匹配位置,即最小值位置
minVal,maxVal,minLoc,maxLoc=cv.minMaxLoc(R)
#4.进行绘制矩形框作图
h,w,l=template.shape;
pic2=pic1.copy()
top_left=minLoc
bottom_right=(top_left[0]+w,top_left[1]+h)
cv.rectangle(pic2,top_left,bottom_right,(255,0,0),5)
#绘制图像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原图")
axes[0,0].imshow(pic1)
axes[0,1].set_title("模板")
axes[0,1].imshow(template)
axes[1,0].set_title("cv.TM_SQDIFF平方差匹配矩阵")
axes[1,0].imshow(R,plt.cm.gray)
axes[1,1].set_title("绘制矩阵")
axes[1,1].imshow(pic2,plt.cm.gray)

plt.show()
cv.waitKey(0)

结果:

[图像识别]8.OpenCV的模板匹配和霍夫检测_第1张图片

 模板匹配不适用于尺度变换等各种条件改变的情况,只能很好匹配完全一样的模板图。视角变换,尺度大小变换,光照改变的图像需要用关键点匹配算法SIFT和SURF等

霍夫变换

常用来提取图像中的直线,圆形等几何图形。

一、霍夫线检测

1.原理:

一条直线的函数为y=kx+q,俩个点(x1,y1)(x2,y2)能确定一个(k1,q1)

[图像识别]8.OpenCV的模板匹配和霍夫检测_第2张图片

 坐边是笛卡尔坐标系的一条直线,对应右边霍夫坐标系的一个点,反过来同样照应

[图像识别]8.OpenCV的模板匹配和霍夫检测_第3张图片

如果是俩个点,对应霍夫空间

[图像识别]8.OpenCV的模板匹配和霍夫检测_第4张图片

 三点共线情况

[图像识别]8.OpenCV的模板匹配和霍夫检测_第5张图片

不止有一条直线

[图像识别]8.OpenCV的模板匹配和霍夫检测_第6张图片

我们在霍夫空间选择最多的直线汇聚的点,再投影到笛卡尔坐标系

[图像识别]8.OpenCV的模板匹配和霍夫检测_第7张图片

同理,还可以通过极坐标系来求,极坐标系和霍夫空间(ρ,theta)只是变量公式不同而已

[图像识别]8.OpenCV的模板匹配和霍夫检测_第8张图片

 只要已知霍夫空间交点,就能知道直线位置方程

OpenCV中霍夫变换坐标系:ρ=xcosθ+ysinθ

[图像识别]8.OpenCV的模板匹配和霍夫检测_第9张图片

2.步骤

【1】霍夫空间,创建一个2维数组叫做累加器,行列分别表示极坐标的俩个参数。该数组大小表示了结果的准确性,如果希望角度设置精度为1度,那么为180列;ρ最大为图片对角线距离

[图像识别]8.OpenCV的模板匹配和霍夫检测_第10张图片

 【2】每遍历直线上的一个点,就能得到极坐标霍夫空间ρ和theta的俩个确定值,在累加器相应的ρ和seita格子上加1

【3】设定阈值threshold,遍历累加器,找到大于threshold的ρ和seita,说明这个ρ和theta值在霍夫空间上相交的直线的最多,就可以将图像中的直线显示出来

3.API代码

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

lines:[[[rho1,theta1],[rho2,theta2],[rho3,theta3]....]]霍夫空间的交点集合

img:为2值图像,只有0和1

rho,theta:ρ和theta的精度,theta单位为弧度

threshold:阈值,累加器的值高于阈值时认为直线

举例:

#7.2

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
#解决中文显示问题,固定格式,直接复制下面俩行代码就行
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

#1.读取单通道图像
pic1 =cv.imread("line.jpg")
pic2=pic1.copy()
#2.霍夫变换直线
gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)
edge=cv.Canny(gray,150,200)#Canny边缘检测
lines=cv.HoughLines(edge,1,np.pi/180,100)
#3.绘制检测得到的直线
for line in lines:
    rho,theta=line[0]
    a=np.cos(theta)
    b=np.sin(theta)
    x0=rho*a
    y0=rho*b
    #延长线
    x1=int(x0+1000*(-b))
    y1=int(y0+1000*a)
    x2=int(x0-1000*(-b))
    y2=int(y0-1000*a)
    cv.line(pic2,(x1,y1),(x2,y2),(255,0,255),2)
#绘制图像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原图")
axes[0,0].imshow(pic1[:,:,::-1])
axes[0,1].set_title("Canny边缘检测进行二值化")
axes[0,1].imshow(edge,plt.cm.gray)
axes[1,1].set_title("霍夫直线到原图")
axes[1,1].imshow(pic2[:,:,::-1])

plt.show()
cv.waitKey(0)

结果

[图像识别]8.OpenCV的模板匹配和霍夫检测_第11张图片

 二、霍夫圆检测

霍夫圆检测需要三个变量圆心坐标a,b和半径r

(x-a)^2+(y-b)^2=r^2

在三维空间上进行霍夫变换,霍夫检测其他越复杂形状需要的维数更多

霍夫圆检测先确定圆心,再确定半径

圆心检测的原理:圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
圆半径确定原理:圆心到圆周上的距离(半径)是相同的,确定一个阈值,只要相同距离的数量大于该阈值,就认为该距离是该圆心的半径。

circles=cv.HoughCircles(img,method,dp,minDist,param1=100,param2=100

,minRadius=0,maxRadius=0)

circlrs:[[[x1,y1,r1],[x2,y2,r2]....]]圆的三个参数集合

img:灰度图像

method:算法,cv.HOUGH_GRADIENT霍夫梯度算法

dp:霍夫空间分辨率1代表与原图一样,2代表是原图一半

minDist:圆心之间最小距离,如果小于该值代表同一个圆心,圆心容差

param1:边缘检测使用的Canny算子高阈值,低阈值是这个值的一半

param2:检测圆心和确定半径阈值

minRadius,maxRadius:检测圆半径的最大值和最小值

举例

#7.3

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
#解决中文显示问题,固定格式,直接复制下面俩行代码就行
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

#1.读取单通道图像
pic1 =cv.imread("circle.jpg")
gray=cv.cvtColor(pic1,cv.COLOR_BGR2GRAY)
#2.中值去噪
pic2=cv.medianBlur(gray,3)
#3.霍夫圆检测
circles=cv.HoughCircles(pic2,cv.HOUGH_GRADIENT,1,minDist=200,param1=100,param2=30,minRadius=0,maxRadius=0)
circles=np.uint16(np.around(circles))#圆心和半径都为整数
#4.绘制圆
pic3 = pic1.copy()
for i in circles[0,:]:#遍历每一行
    #绘制圆
    cv.circle(pic3,(i[0],i[1]),i[2],(255,0,0),2)
#绘制图像
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,10))
axes[0,0].set_title("原图")
axes[0,0].imshow(pic1[:,:,::-1])
axes[0,1].set_title("灰度图")
axes[0,1].imshow(gray,plt.cm.gray)
axes[1,0].set_title("中值去噪")
axes[1,0].imshow(pic2,plt.cm.gray)
axes[1,1].set_title("霍夫圆到原图")
axes[1,1].imshow(pic3[:,:,::-1])

plt.show()
cv.waitKey(0)

结果:

[图像识别]8.OpenCV的模板匹配和霍夫检测_第12张图片

 总结,这节课你学到了什么?

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

minVal,maxVal,minLoc,maxLoc=cv.minMaxLoc(R)

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

circles=cv.HoughCircles(img,method,dp,minDist,param1=100,param2=100

,minRadius=0,maxRadius=0)

你可能感兴趣的:(黑马python图像识别笔记,opencv,计算机视觉,人工智能,图像处理,pycharm)