霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,它通过一种投票算法检测具有特定形状的物体。该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。霍夫变换于1962年由Paul Hough 首次提出[53],后于1972年由Richard Duda和Peter Hart推广使用[54],经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆.
经过几天的学习,发现各位大牛的理解方式之前都是有一些区别的,但是核心的思想没有变化,因此记录一下自己对霍夫变换直线检测的认识。
一、原理介绍:
1、对于直角坐标系中的任意一点A(x0,y0),经过点A的直线满足Y0=k*X0+b.(k是斜率,b是截距)
2、那么在X-Y平面过点A(x0,y0)的直线簇可以用Y0=k*X0+b表示,但对于垂直于X轴的直线斜率是无穷大的则无法表示。因此将直角坐标系转换到极坐标系就能解决该特殊情况。
3、在极坐标系中表示直线的方程为ρ=xCosθ+ySinθ(ρ为原点到直线的距离),如图所示:
4、如上图,
假定在一个88的平面像素中有一条直线,并且从左上角
(1,8)像素点开始分别计算θ为0°、45°、90°、135°、180°时的ρ,
图中可以看出ρ分别为*1、(9√2)/2、8、(7√2)/2、-1,并给这5个值分别记一票,
同理计算像素点(3,6)点θ为0°、45°、90°、135°、180°时的ρ,再给计算出来的5个ρ值分别记一票,此时就会发现ρ = (9√2)/2的这个值已经记了两票了,以此类推,遍历完整个88的像素空间的时候ρ = (9√2)/2就记了5票, 别的ρ值的票数均小于5票,所以得到该直线在这个88的像素坐标中的极坐标方程为 (9√2)/2=xCos45°+ySin45°,
到此该直线方程就求出来了。(PS:但实际中θ的取值不会跨度这么大,一般是PI/180)。
二、Opencv实现直线检测:
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat Image = imread(".//res//street.jpg", 0);
Mat CannyImg;
Canny(Image, CannyImg, 140, 250, 3);
imshow("CannyImg", CannyImg);
Mat DstImg;
cvtColor(Image, DstImg, CV_GRAY2BGR);
vector<Vec4i> Lines;
HoughLinesP(CannyImg, Lines, 1, CV_PI / 360, 170,30,15);
for (size_t i = 0; i < Lines.size(); i++)
{
line(DstImg, Point(Lines[i][0], Lines[i][1]), Point(Lines[i][2], Lines[i][3]), Scalar(0, 0, 255), 2, 8);
}
imshow("HoughLines_Detect", DstImg);
imwrite(".//res//HoughLines_Detect.jpg", DstImg);
waitKey(0);
return 0;
}
HoughLinesP(image, rho, theta, threshold)
- image:二值图(边缘检测器的输出);
- rho:距离分辨率,以像素为单位;
- theta:角度分辨率,单位为弧度;
- threshold:交点的最小曲线数量大于阈值,才被视为一条直线。
- maxLineGap:这是一个可选参数,表示两个线段之间的gap小于该值,则进行连接 ```python import cv2 import numpy as np img = cv2.imread(“/home/zxd/Pictures/lines.jpg”)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
detecting the edges
edges = cv2.Canny(gray, 50, 200)
apply probabilistic hough transform for line detection
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30)
maxLineGap 参数的值为200,则线之间的gap小于200像素就将其进行连接
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=30, maxLineGap=200)
得到所有线段的端点
for line in lines: x1, y1, x2, y2 = line[0] cv2.line(img, (x1, y1), (x2, y2), (0,0,255))
cv2.imshow(‘img’, img)
if cv2.waitKey(0) == ord(‘q’):
cv2.destroyAllWindows()
```
下面是输出的结果:
两者分别为不使用 maxLineGap 参数和使用 maxLineGap 参数的结果图。
所以即使遇到虚线或者被遮挡的直线,我们也可以使用霍夫线变换来进行直线检测。