霍夫变换是一种特征提取,被普遍应用在图像分析、电脑视觉以及数位影像处理。霍夫变换是用来辨别找出物件中的特征,例如:线条。他的算法流程大体以下,给定一个物件、要辨别的形状的种类,算法会在参数空间中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值来决定。javascript
理论上,霍夫变换就是对于原图上的每个直线都在参数空间画一条线,最终找出参数空间变换线比较密集的地方在对应回到xy 空间坐标系。为了方便理解,下面简单写了一下草稿,但愿对你有帮助。html
注意:建正交直角坐标系过程当中, 要选取好以图片的某个方位左起始点,以像素做为标度。java
下图所示:
python
图像是一个 2D 矩阵,超过一些 x 和 y 坐标系,一条线能够描述为y = mx + b
算法
霍夫空间的造成:
编程
输入的图片中有两条粗直线,通过霍夫变换后的结果获得accumaltor矩阵,右图就是把accumaltor矩阵画出来,越亮值越大,越黑值越小。在右图中,有两个很明显的亮点, 这两个亮点分别表明两条不一样参数的直线,与输入的图片(下图)吻合。而后读取矩阵的两个最大值就能够得出这两条线距画面中心距离以及角度。微信
相似地,若是给的点坐标越多,造成的霍夫空间为:
app
图像如何使用霍夫变换?
Hough 变换是一种用于检测图像中简单形状(如圆、线等)的特征提取方法。函数
"简单"特征由形状表示以参数表示派生。"简单"形状仅由几个参数表示,例如,一条线能够由其斜率和截距表示,也能够用 x、y 和半径表示。测试
在咱们下面的行示例中,Hough 变换将负责处理图像上的点并计算霍夫空间中的值。在 OpenCV 中,使用霍夫变换的线路检测在函数和(几率霍夫变换)中实现。
直线检测cv2.HoughLinesP()函数原型:
HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
image:必须是二值图像,推荐使用canny边缘检测的结果图像;rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0theta:线段以弧度为单位的角度精度,推荐用numpy.pi/180threshod: 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据状况推荐先用100试试lines:这个参数的意义未知,发现不一样的lines对结果没影响,可是不要忽略了它的存在 minLineLength:线段以像素为单位的最小长度,根据应用场景设置 maxLineGap:同一方向上两条线段断定为一条线段的最大容许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,容许线段上的断裂越大,越有可能检出潜在的直线段
import cv2
import numpy as np
original_img = cv2.imread("lane.png", 0)
img = cv2.resize(original_img, None, fx=0.8, fy=0.8,
interpolation=cv2.INTER_CUBIC)
img = cv2.GaussianBlur(img, (3, 3), 0)
edges = cv2.Canny(img, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi / 180, 118) # 这里对最后一个参数使用了经验型的值
result = img.copy()
for line in lines:
rho = line[0][0] # 第一个元素是距离rho
theta = line[0][1] # 第二个元素是角度theta
print(rho)
print(theta)
if (theta < (np.pi / 4.)) or (theta > (3. * np.pi / 4.0)): # 垂直直线
pt1 = (int(rho / np.cos(theta)), 0) # 该直线与第一行的交点
# 该直线与最后一行的焦点
pt2 = (int((rho - result.shape[0] * np.sin(theta)) / np.cos(theta)), result.shape[0])
cv2.line(result, pt1, pt2, (255)) # 绘制一条白线
else: # 水平直线
pt1 = (0, int(rho / np.sin(theta))) # 该直线与第一列的交点
# 该直线与最后一列的交点
pt2 = (result.shape[1], int((rho - result.shape[1] * np.cos(theta)) / np.sin(theta)))
cv2.line(result, pt1, pt2, (255), 1) # 绘制一条直线
cv2.imshow('Canny', edges)
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 另外一解法:
import cv2import numpy as np# Read imageimg = cv2.imread('lane.jpg', cv2.IMREAD_COLOR)# Convert the image to gray-scalegray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# Find the edges in the image using canny detectoredges = cv2.Canny(gray, 50, 200)# Detect points that form a linelines = cv2.HoughLinesP(edges, 1, np.pi/180, 100,minLineLength=10, maxLineGap=250)# Draw lines on the imagefor line in lines: x1, y1, x2, y2 = line[0] cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 3)# Show result
cv2.imshow("Result Image", img) cv2.waitKey() ##记得写上,不然闪退cv2.destroyAllWindows()
相似地还有圆形检测,这里就不介绍了,感兴趣的替换一下面的代码,而且找有圆形照片测试一下函数就能够。
霍夫圆形检测method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) → circles
:8位,单通道, 灰度输入图像。 找到的圆的输出向量。每一个向量被编码为3元素的浮点向量 (x,y,半径)。 circle_storage - 在C函数中,这是一个将包含找到的圆的输出序列的内存存储。使用检测方法。目前,惟一实现的方法是 CV_HOUGH_GRADIENT,基本上是 21HT,在[Yuen90]中有描述 。 dp - 累加器分辨率与图像分辨率的反比。例如,若是 dp = 1,则累加器具备与输入图像相同的分辨率。若是 dp = 2,则累加器的宽度和高度都是一半。minDist -检测到的 圆的中心之间的最小距离。若是参数过小,除了真正的参数外,可能会错误地检测到多个邻居圈。若是太大,可能会错过一些圈子。param1 - 第一个方法特定的参数。在CV_HOUGH_GRADIENT的状况下, 两个传递给Canny()边缘检测器的阈值较高(较小的两个小于两倍)。param2 - 第二种方法参数。在CV_HOUGH_GRADIENT的状况下,它是检测阶段的圆心的累加器阈值。越小,可能会检测到越多的虚假圈子。首先返回对应于较大累加器值的圈子。minRadius -最小圆半径。maxRadius - 最大圆半径。
参考文献
https://zhuanlan.zhihu.com/p/47649796https://docs.opencv.org/2.4/modules/imgproc/doc/feature_detection.html?highlight=houghlines#houghlineshttps://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html
本文分享自微信公众号 - AI科技与算法编程(kangsinx)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。