1.霍夫变换原理
霍夫变换常用来提取图像中的直线和圆等几何形状
变换后的空间我们叫做霍夫空间,即:笛卡尔坐标系中的一条直线,对应于霍夫空间中的一个点。反过来,同样成立,霍夫空间中的一条线,对应笛卡尔坐标系中一个点,如图所示:
在极坐标下是一样的,极坐标中的点对应于霍夫空间的线,这时是霍夫空间是不在是参数(k,q)的空间,而是(,
)的空间,
是原点到直线的垂直距离,
表示直线的垂线与横轴顺时针方向的夹角,垂直线的角度为0度,水平线的角度是180度。
2.霍夫线检测
在Opencv中做霍夫线检测是使用的API是:
cv.HoughLines(img,rho,theta,threshold)
参数:
-img:检测的图像,要求是二值化的图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
-rho、theta:
和
的精确度
-threshold:阈值,只有累加器中的值高于该阈值是才被认为是直线
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
img=cv.imread('rili.png',0)
edges=cv.Canny(img,50,150)
plt.imshow(edges,cmap=plt.cm.gray)
lines=cv.HoughLines(edges,0.8,np.pi/180,150)
print(lines)
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(img,(x1,y1),(x2,y2),(0,255,0),)
plt.imshow(img[:,:-1])
plt.show()
注:出现AttributeError: module 'backend_interagg' has no attribute 'FigureCanvas'. Did you mean: 'FigureCanvasAgg'?是因为在使用matplotlib库时,后端模块没有找到正确的属性。你可以尝试更改matplotlib的后端设置,以解决这个问题。import matplotlib matplotlib.use('TkAgg')
3.霍夫圆检测
原则上霍夫变换可以检测任何形状,但复杂的形状需要的参数就多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准霍夫变换应用于实际复杂图像的检测中,霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。
在opencv中检测图像中的圆环使用的API是:
circles=cv.HoughCircles(image,method,dp,minDist,param1=100,param2=100,minRadius=0,maxRadius=0)
参数:
-image:输入图像,应输入灰度图像
-method:使用霍夫变换圆检测的算法
-dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推
-minDist:为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心
-param1:边缘检测时使用canny算子的高阈值,低阈值是高阈值的一半
-param2:检测圆心和确定半径时所共有的阈值
-minRadius和Radius为所检测到的圆半径的最小值和最大值
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
star=cv.imread('xingqiu2.jpg')
gray_img=cv.cvtColor(star,cv.COLOR_BGR2GRAY)
img=cv.medianBlur(gray_img,7)
plt.imshow(img,cmap=plt.cm.gray)
circles=cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,200,param1=100,param2=50,minRadius=0,maxRadius=100)
print(circles)
if circles is not None:
for i in circles[0,:]:
cv.circle(star, (i[0], i[1]), i[2], (0, 255, 0), 2)
cv.circle(star, (i[0], i[1]), 2, (0, 255, 0), -1)
else:
print("未检测到圆形")
# cv.circle(star,(i[0],i[1]),i[2],(0,255,0),2)
# cv.circle(star,(i[0],i[1]),2,(0,255,0),-1)
plt.imshow(star[:,:,::-1])
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.读取图像,并转换为灰度图
planets=cv.imread('xingqiu.jpg')
gay_img=cv.cvtColor(planets,cv.COLOR_BGR2GRAY)
#2.进行中值模糊,去噪点
img=cv.medianBlur(gay_img,7)
circles=cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,200,param1=100,param2=50,minRadius=0,maxRadius=100)
for i in circles[0,:]:
cv.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
cv.circle(planets,(i[0],i[1]),2,(0,255,0),-1)
#4.图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.imshow(img[:,:,::-1])
plt.title('霍夫变换线检测')
plt.xticks([]),plt.yticks([])
plt.show()
注:刚开始运行一直失败,后来发现调用
cv.circle()
函数时,传入的参数类型不正确。具体来说,center
参数应该是一个包含两个整数的元组,表示圆心的坐标。要用int型。改后代码如下所示:
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
star=cv.imread('xingqiu2.jpg')
gray_img=cv.cvtColor(star,cv.COLOR_BGR2GRAY)
img=cv.medianBlur(gray_img,7)
plt.imshow(img,cmap=plt.cm.gray)
circles=cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,50,param1=50,param2=25,minRadius=0,maxRadius=150)
print(circles)
if circles is not None:
for i in circles[0,:]:
center = (int(i[0]), int(i[1]))
radius = int(i[2])
cv.circle(star, center, radius, (0, 255, 0), 2)
cv.circle(star, center, 2, (0, 255, 0), -1)
else:
print("未检测到圆形")
# cv.circle(star,(i[0],i[1]),i[2],(0,255,0),2)
# cv.circle(star,(i[0],i[1]),2,(0,255,0),-1)
plt.imshow(star[:,:,::-1])
plt.show()
总结:
1.模版匹配
原理:在给定的图片中查找和模版最相似的区域
API:利用cv.matchTemplate()进行模版匹配,然后使用cv.minMaxLoc()搜索匹配的位置
2.霍夫线检测
原理:将要检测的内容转换到霍夫空间中,利用累加器统计最优解,将检测结果表示处理
API:cv.HoughLines()
注意:该3方法输入的是二值化图像,在进行检测前要将图像进行二值化处理
3.霍夫圆检测
方法:霍夫梯度法
API:cv.HoughCircles()
4.轮廓检测
轮廓检测指绘制图像中的对象边界,更偏向于关注上层语义对象。如opencv中的findContours()函数,它会得到每一个轮廓并以点向量方式存储,除此也得到一个图像的拓扑信息,即一个轮廓的后一个轮廓,前一个轮廓等的索引编号。
4.1查找轮廓
在opencv中查找轮廓的API:
binary,contours,hierarchy=cv2.findContours(img,mode,method)
参数:
-img:输入图像,二值图
-mode:轮廓的检索模式,主要有四种方式:
cv2.RETR_EXTERNAL:只检索外轮廓,所有子轮廓被忽略
cv2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廓属于同一等级
cv2.RETR_CCOMP:返回所有的轮廓,只建立两个等级的轮廓。一个对象的外轮廓为第1级组织结构。而对象内部中空洞的轮廓为第2级组织结构,空洞中的任何对象的轮廓又是第1级组织结构。
cv2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。
-method:轮廓的近似方法,主要有以下两种:
cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1。
cv2.CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
返回:
-binary:返回的二值图像
-contours:检测出的轮廓,所有轮廓的列表结构,每个轮廓是目标对象边界点的坐标的数组
-hierachy:轮廓的层次结构
4.2绘制轮廓
cv2.drawContours(img,contours,index,color,width)
参数:
-img:轮廓检测的原图像
-contours:检测出的轮廓
-index:轮廓的索引,绘制单个轮廓时指定其索引,绘制全部的轮廓时设为- 1即可
-color和width:绘制时轮廓的颜色及线型的宽度
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.图像读取
img=cv.imread('ditu.jpg')
imgray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#2.边缘检测
canny=cv.Canny(imgray,127,255,0)
#轮廓提取
#image,contours,hierarchy=cv.findContours(canny,cv.RETR_TREE,cv.CHAIN_APPROX_NONE)
contours, hierarchy = cv.findContours(canny, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
#4.将轮廓绘制在图像上
img=cv.drawContours(img,contours,-1,(0,0,255),2)
#5.图像显示
plt.imshow(img[:,:,::-1])
plt.xticks([]),plt.yticks([])
plt.show()
5.轮廓的特征
5.1轮廓面积
轮廓面积是轮廓所包围的区域的面积,在opencv中使用的API是;
area=cv.contourArea(cnt)
5.2轮廓周长
轮廓周长也被称为弧长,在opencv中使用API是:
perimeter=cv2.arcLength(cnt,isclosed)
参数:
-lsclosed:指定轮廓的形状是闭合的,还是开发的
5.3轮廓近似
轮廓近似是将轮廓形状近似为到另一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定
在opencv中使用的API是:
approx=cv.approxPoluDP(cnt,epsilon,isclosed)
参数:
-cnt:要进行轮廓近似的原始轮廓
-epsilon:从原始轮廓到近似轮廓的最大距离,是一个准确度参数,该参数对调整后的结果很重要
-lsclosed:指定轮廓是否闭合
返回;
-approx:返回的点集,绘制时将其连接起来绘制最终的近似轮廓
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.图像读取
img=cv.imread('lunkuo.png')
imgray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#转化为二进制
ret,thresh=cv.threshold(imgray,127,255,0)
#3.轮廓提取
contours,hierarchy=cv.findContours(thresh,cv.RETR_LIST,cv.CHAIN_APPROX_NONE)
#4.轮廓近似
epsilon=0.1*cv.arcLength(contours[0],True)
approx=cv.approxPolyDP(contours[0],epsilon,True)
#5.将轮廓绘制在图像上
#5.1原始轮廓
img1=cv.drawContours(img,contours,-1,(0,0,255),2)
#5.2轮廓近似后的结果
img2=cv.polylines(img,[approx],True,(0,0,255),2)
#4.图像显示
plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img[:,:,::-1]),plt.title('轮廓检测结果')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img[:,:,::-1]),plt.title('轮廓近似后结果')
plt.xticks([]),plt.yticks([])
plt.show()
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
img=cv.imread('lunkuo.png')
img_gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thresh=cv.threshold(img_gray,127,255,0)
contours,hi=cv.findContours(thresh,cv.RETR_LIST,cv.CHAIN_APPROX_NONE)
plt.imshow(img[:,:,::-1])
img=cv.drawContours(img,contours,0,(0,0,255),2)
plt.imshow(img[:,:,::-1])
cnt=contours[0]
area=cv.contourArea(cnt)
print(area)
length=cv.arcLength(cnt,True)
print(length)
esplion=0.1*length
approx=cv.approxPolyDP(cnt,esplion,True)
plt.imshow(img[:,:,::-1])
6.凸包
凸包是计算机几何图形学的概念,简单来说,给定二维平面点集,凸包就是将最外层的点连接起来构成的凸多边形,它能够包含物体中所有的点,物体的凸包常应用在物体识别,手势识别及边界检测等领域
在opencv中检测凸包的API是:
hull=cv2.convexHull(points,clockwise,returnPoints)
参数:
-points:传入的轮廓
-clockwise:方向标志。如果设置为True,输出的凸包是顺时针方向的。否则为逆时针方向
-returnPoints:默认值为True。它会返回凸包上点的坐标。如果设置为False,就会返回与凸包点对应的轮廓上的点的索引
返回:
-hull:输出的凸包的结果
import numpy as np
import cv2 as cv
import matplotlib
matplotlib.use('TkAgg') # 或者 'Qt5Agg'
import matplotlib.pyplot as plt
#1.图像读取
img=cv.imread('tubao.jpg')
img1=img.copy()
imgray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#2.边缘检测
canny=cv.Canny(imgray,127,255,0)
#轮廓提取
contours,hierarchy=cv.findContours(canny,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
#4.将轮廓绘制在图像上
img=cv.drawContours(img,contours,-1,(0,0,255),2)
plt.imshow(img[:,:,::-1])
#凸包检测
hulls=[]
for cnt in contours:
#寻找凸包使用cv.convexHull(contour)
hull=cv.convexHull(cnt)
hulls.append(hull)
draw_hulls=cv.drawContours(img1,hulls,-1,(0,255,0),2)
plt.imshow(img[:,:,::-1])