标签:python opencv 图像处理 霍夫变换 数字图像
在数字图像中,往往存在着一些特殊形状的几何图形,像检测马路边一条直线,检测人眼的圆形等等,有时我们需要把这些特定图形检测出来,hough变换就是这样一种检测的工具。
Hough变换的原理是将特定图形上的点变换到一组参数空间上,根据参数空间点的累计结果找到一个极大值对应的解,那么这个解就对应着要寻找的几何形状的参数(比如说直线,那么就会得到直线的斜率k与常熟b,圆就会得到圆心与半径等等)。
关于hough变换,核心以及难点就是关于就是有原始空间到参数空间的变换上。以直线检测为例,假设有一条直线L,原点到该直线的垂直距离为p,垂线与x轴夹角为
可以看到的是这条直线在极坐标系下只有一个
可以看到,光是空间上的一个点在极坐标系下就可能在很多极坐标对所对应的直线上,具体有多少个极坐标对呢?那得看你的
ok前面说的是单单这一个点对应的极坐标系下的参数对,那么如果每个点都这么找一圈呢?也就是每个点在参数空间上都对应一系列参数对吧,现在把它们华仔同一个坐标系下会怎么样呢?为了方便,假设在这个直线上取3个点画一下:
那么可以看到,首先对于每一个点,在极坐标下,会存在一个周期的曲线来表示通过这个点,其次,这三个极坐标曲线同时经过一个点,要搞清楚的是,极坐标上每一个点对
再来分析这个算法。可以看到hough变换就是参数映射变换。对每一个点都进行映射,并且每一个映射还不止一次,
继续算法,分析这么多,可想而知那么一个hough变换在算法设计上就可以如下步骤:
(1)将参数空间
(2)然后对图像边界上的每一个点进行变换,变换到属于哪一组
(3)当所有点处理完成后,就来分析得到的
(4)有了
说了这么多,这就是原理上hough变换的最底层原理,事实上完全可以自己写程序去实现这些,然而,也说过,hough变换是一个耗时耗力的算法,自己写循环实现通常很慢,曾经用matlab写过这个,也有实际的hough变换例子可以看看:
那么我们在实际中大可不必自己写,opencv已经集成了hough变换的函数,调用它的函数效率高,也很简单。
Opencv中检测直线的函数有cv2.HoughLines(),cv2.HoughLinesP()
函数cv2.HoughLines()返回值有三个(opencv 3.0),实际是个二维矩阵,表述的就是上述的
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(‘line.jpg‘)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度图像
#open to see how to use: cv2.Canny
#http://blog.csdn.net/on2way/article/details/46851451
edges = cv2.Canny(gray,50,200)
plt.subplot(121),plt.imshow(edges,‘gray‘)
plt.xticks([]),plt.yticks([])
#hough transform
lines = cv2.HoughLines(edges,1,np.pi/180,160)
lines1 = lines[:,0,:]#提取为为二维
for rho,theta in lines1[:]:
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))
cv2.line(img,(x1,y1),(x2,y2),(255,0,0),1)
plt.subplot(122),plt.imshow(img,)
plt.xticks([]),plt.yticks([])
测试一个新的图,不停的改变 cv2.HoughLines最后一个阈值参数到合理的时候如下:
可以看到检测的还可以的。
函数cv2.HoughLinesP()是一种概率直线检测,我们知道,原理上讲hough变换是一个耗时耗力的算法,尤其是每一个点计算,即使经过了canny转换了有的时候点的个数依然是庞大的,这个时候我们采取一种概率挑选机制,不是所有的点都计算,而是随机的选取一些个点来计算,相当于降采样了。这样的话我们的阈值设置上也要降低一些。在参数输入输出上,输入不过多了两个参数:minLineLengh(线的最短长度,比这个短的都被忽略)和MaxLineCap(两条直线之间的最大间隔,小于此值,认为是一条直线)。输出上也变了,不再是直线参数的,这个函数输出的直接就是直线点的坐标位置,这样可以省去一系列for循环中的由参数空间到图像的实际坐标点的转换。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(‘room.jpg‘)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度图像
#open to see how to use: cv2.Canny
#http://blog.csdn.net/on2way/article/details/46851451
edges = cv2.Canny(gray,50,200)
plt.subplot(121),plt.imshow(edges,‘gray‘)
plt.xticks([]),plt.yticks([])
#hough transform
lines = cv2.HoughLinesP(edges,1,np.pi/180,30,minLineLength=60,maxLineGap=10)
lines1 = lines[:,0,:]#提取为二维
for x1,y1,x2,y2 in lines1[:]:
cv2.line(img,(x1,y1),(x2,y2),(255,0,0),1)
plt.subplot(122),plt.imshow(img,)
plt.xticks([]),plt.yticks([])
可以看到这个方法似乎更好些,速度还快,调参数得到较好的效果就ok了。
Ok说完了直线的检测,再来说说圆环的检测,我们知道圆的数学表示为:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(‘eye.jpg‘)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度图像
plt.subplot(121),plt.imshow(gray,‘gray‘)
plt.xticks([]),plt.yticks([])
#hough transform
circles1 = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,
100,param1=100,param2=30,minRadius=200,maxRadius=300)
circles = circles1[0,:,:]#提取为二维
circles = np.uint16(np.around(circles))#四舍五入,取整
for i in circles[:]:
cv2.circle(img,(i[0],i[1]),i[2],(255,0,0),5)#画圆
cv2.circle(img,(i[0],i[1]),2,(255,0,255),10)#画圆心
plt.subplot(122),plt.imshow(img)
plt.xticks([]),plt.yticks([])
把半径范围调小点,检测内圆:
至此圆的检测就是这样。
版权声明:本文为博主原创文章,未经博主允许不得转载。
Python下opencv使用笔记(十一)(详解hough变换检测直线与圆)
标签:python opencv 图像处理 霍夫变换 数字图像
原文地址:http://blog.csdn.net/on2way/article/details/47028969