霍夫变换直线检测(Line Detection)原理及示例
微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, … 问题或建议,请公众号留言;
霍夫变换是图像处理必然接触到的一个算法,它通过一种投票算法检测具有特定形状的物体,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果,该方法可以进行圆,直线,椭圆等形状的检测。在车道线检测中,当初考虑的一个方案便是采用霍夫变换检测直线进行车道线提取。
目录
文章目录
霍夫变换(Hough Transform)
霍夫直线检测(Hough Line Detection)
霍夫直线检测的基本原理
关于对偶性
1)图像空间中的点与参数空间中的直线一一对应。
在图像空间x-y中,一条直线在直角坐标系下可以表示为:
y = k x + b y=kx+b y=kx+b
其中k和b是参数,表示直线的斜率和截距。
过某一点 A ( x 0 , y 0 ) A(x_0, y_0) A(x0,y0)的所有直线的参数均满足方程 y 0 = k ∗ x 0 + b y_0=k*x_0+b y0=k∗x0+b,即点 A ( x 0 , y 0 ) A(x_0, y_0) A(x0,y0)确定了一族直线.
如果我们将方程改写为:b=-kx0+y0
以上就是在直线检测任务中关于对偶性的直观解释。这个性质也为我们解决直线检测任务提供了方法,也就是把图像空间中的直线对应到参数空间中的点,最后通过统计特性来解决问题。假如图像空间中有两条直线,那么最终在参数空间中就会对应到两个峰值点,依此类推。
如图3所示,图像空间中有5个点,将这5个点转换到参数空间k-b中对应着5条直线,每两条直线的交点可以确定图像空间中的一条直线,我们可以选择由尽可能多直线汇成的点,如A和B,将其参数空间中的坐标值作为图像空间中两条直线方程参数,由此便确定了两条直线,
参数空间的选择
这样就把在图像空间中检测直线的问题转化为在极坐标参数空间中找通过点(r,θ)的最多正弦曲线数的问题。霍夫空间中,曲线的交点次数越多,所代表的参数越确定,画出的图形越饱满。
利用霍夫变换检测直线
如前所述,霍夫直线检测就是把图像空间中的直线变换到参数空间中的点,通过统计特性来解决检测问题。具体来说,如果一幅图像中的像素构成一条直线,那么这些像素坐标值(x, y)在参数空间对应的曲线一定相交于一个点,所以我们只需要将图像中的所有像素点(坐标值)变换成参数空间的曲线,并在参数空间检测曲线交点就可以确定直线了。
霍夫变换直线检测步骤示例

总结:使用霍夫变换检测直线具体步骤:
1.彩色图像->灰度图
2.去噪(高斯核)
3.边缘提取(梯度算子、拉普拉斯算子、canny、sobel)
4.二值化(判断此处是否为边缘点,就看灰度值==255)
5.映射到霍夫空间(准备两个容器,一个用来展示hough-space概况,一个数组hough-space用来储存voting的值,因为投票过程往往有某个极大值超过阈值,多达几千,不能直接用灰度图来记录投票信息)
6.取局部极大值,设定阈值,过滤干扰直线
7.绘制直线、标定角点
霍夫直线检测的优缺点
优点:Hough直线检测的优点是抗干扰能力强,对图像中直线的殘缺部分、噪声以及其它共存的非直线结构不敏感,能容忍特征边界描述中的间隙,并且相对不受图像噪声的影响
缺点:Hough变换算法的特点导致其时间复杂度和空间复杂度都很高,并且在检测过程中只能确定直线方向,丢失了线段的长度信息。由于霍夫检测过程中进行了离散化,因此检测精度受参数离散间隔制约
霍夫直线检测的OpenCV实现
霍夫直线检测函数定义
CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn = 0, double stn = 0, double min_theta = 0, double max_theta = CV_PI ); //InputArray image:输入图像,必须是8位单通道图像。 //OutputArray lines:检测到的线条参数集合。 //double rho:以像素为单位的距离步长。 //double theta:以弧度为单位的角度步长。 //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 //double srn:默认值为0,用于在多尺度霍夫变换中作为参数rho的除数,rho=rho/srn。 //double stn:默认值为0,用于在多尺度霍夫变换中作为参数theta的除数,theta=theta/stn。 //如果srn和stn同时为0,就表示HoughLines函数执行标准霍夫变换,否则就是执行多尺度霍夫变换。
2)HoughLinesP:渐进概率式霍夫变换
CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0 ); //InputArray image:输入图像,必须是8位单通道图像。 //OutputArray lines:检测到的线条参数集合。 //double rho:直线搜索时的距离步长,以像素为单位。 //double theta:直线搜索时的角度步长,以弧度为单位。 //int threshold:累加计数值的阈值参数,当参数空间某个交点的累加计数的值超过该阈值,则认为该交点对应了图像空间的一条直线。 //double minLineLength:默认值为0,表示最小线段长度阈值(像素)。 //double maxLineGap:线段上最近两点之间的阈值.默认值为0,表示直线断裂的最大间隔距离阈值。即如果有两条线段是在一条直线上,但它们之间有间隙,那么如果这个间隔距离小于该值,则被认为是一条线段,否则认为是两条线段。
OpenCV霍夫直线检测函数使用
// // Created by liheng on 2019/2/24. // Program:霍夫直线检测示例 //Data:2019.2.24 //Author:liheng //Version:V1.0 // #include
#include
#include
int main() { std::string img_path; cv::Mat mat_color; cv::Mat mat_gray; cv::Mat mat_binary; cv::Mat mat_canny; img_path = "../pictures/000177.png"; mat_color = cv::imread(img_path, 1); mat_gray = cv::imread(img_path, 0); //形态学闭运算 cv::Mat elementRect; elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1)); cv::morphologyEx(mat_gray,mat_gray,cv::MORPH_CLOSE,elementRect); // binary cv::threshold(mat_gray, mat_binary, 125, 255.0, cv::THRESH_BINARY); // detect edge cv::Canny(mat_binary, mat_canny, 50, 125, 3); // detect line std::vector
lines; cv::HoughLines(mat_canny, lines, 1, CV_PI / 180, 150, 0, 0); // draw line std::cout << "line number: " << lines.size() << std::endl; for (size_t i = 0; i < lines.size(); i++) { cv::Vec2f linex = lines[i]; std::cout << "radius: " << linex[0] <<", angle: " << 180 / CV_PI * linex[1] << std::endl; float rho = lines[i][0], theta = lines[i][1]; cv::Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a * rho, y0 = b * rho; pt1.x = cvRound(x0 + 1000 * (-b)); pt1.y = cvRound(y0 + 1000 * (a)); pt2.x = cvRound(x0 - 1000 * (-b)); pt2.y = cvRound(y0 - 1000 * (a)); line(mat_color, pt1, pt2, cv::Scalar(255, 0, 0), 1); } cv::imshow("gray", mat_gray); cv::imshow("binary", mat_binary); cv::imshow("canny", mat_canny); cv::imshow("color", mat_color); cv::waitKey(0); return 0; }
// // Created by liheng on 2019/2/24. // Program:霍夫P直线检测示例 //Data:2019.2.24 //Author:liheng //Version:V1.0 // #include
#include
#include
int main() { std::string img_path; cv::Mat mat_color; cv::Mat mat_gray; cv::Mat mat_binary; cv::Mat mat_canny; img_path = "../pictures/000177.png"; mat_color = cv::imread(img_path, 1); mat_gray = cv::imread(img_path, 0); //形态学闭运算 cv::Mat elementRect; elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1)); cv::morphologyEx(mat_gray,mat_gray,cv::MORPH_CLOSE,elementRect); // binary cv::threshold(mat_gray, mat_binary, 125, 255.0, cv::THRESH_BINARY); // detect edge cv::Canny(mat_binary, mat_canny, 50, 125, 3); // detect line std::vector
lines; HoughLinesP(mat_canny,lines,1,CV_PI/180,100,10,50); // draw line for (size_t i = 0; i < lines.size(); i++) { cv::Vec4i& linex = lines[i]; int dx=linex[2]-linex[0]; int dy=linex[2]-linex[1]; double angle = atan2(double(dy),dx) * 180 /CV_PI; //if (abs(angle) <= 20) // continue; line(mat_color, cv::Point(linex[0], linex[1]), cv::Point(linex[2], linex[3]), cv::Scalar(255, 0, 0), 1); } cv::imshow("gray", mat_gray); cv::imshow("binary", mat_binary); cv::imshow("canny", mat_canny); cv::imshow("color", mat_color); cv::waitKey(0); return 0; }
如果将HoughLines和HoughLinesP函数用于车道线检测,从上述结果来看,仍需一定的处理方法,以提高准确性。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202504.html原文链接:https://javaforall.net
