基于Hough变换的直线检测(Matlab)

 
 

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

1、引言

该程序实现了一些基本的图像处理算法,并将它们组合在一起,构建了一个基于霍夫变换的直线检测器。该程序能够在图像中找到直线段的起始点和结束点。

像大多数视觉算法一样,Hough变换使用了一些参数,它们的最优值是具有数据依赖性(即一组参数值在一幅图像上工作得很好,可能对另一幅图像来说不是最好的)。通过在测试图像上运行代码和调优参数,它获得了每个图像的最佳值,从而获得了良好的性能。

  • Hough Transform based line detector :基于Hough变换的直线检测器。

  • straight line segments in images:图像中的直线。

  • optimal values are data dependent:最优参数具有数据依赖性。

2、实施

2.1卷积

编写一个函数,将图像与给定的卷积滤波器进行变换。

function [img1]=myImageFilter(img0,h)

作为输入,该函数接受存储在矩阵h中的卷积滤波器和灰度图像(img0)。函数的输出应该是与img0相同大小的图像img1,它是由img0和h卷积得到。您可以假设滤波器h沿两个维度都是奇数大小。您将需要处理图像边缘的边界情况。

例如,当您在图像的左上角放置卷积掩膜时,大多数滤波器掩膜将位于图像之外。一种可能的解决方案是对图像进行处理,使位于图像边界之外的像素与位于图像内部的最近像素具有相同的强度值。

2.2用一个For循环进行卷积

请编写一个只使用一个for循环进行卷积的函数,并将其保存到ec/目录。(如果您在Q3.1中已经这样做了,好的,只需复制一个并保存到EC/。)

此外,简单地描述一下你在写作中是如何实现的。插图有助于理解是高度鼓励的。

function [img1]=myImageFilterX(img0,h)

为了只使用一个循环,我将2D数组转换成了1D数组,然后使用它们的映射关系。其他代码与2.1完全相同。看.m文件夹ec下。

2.3边缘检测

编写一个函数,以查找图像中的边缘强度和方向。在您的写作中包含给定图像之一的功能输出。

function [Im Io Ix Iy]=myEdgeFilter(img,sigma)

该函数将输入灰度图像(img)和σ(标量)。Sigma是高斯平滑核在边缘检测前使用的标准差,函数将输出边缘幅值图像Im,边缘方向图像Io,以及x方向和y方向上的滤波响应Ix和Iy。

3e85d84f9c88cc402143f7fb6760fa84.png

2.4Hough变换

编写将Hough变换应用于边缘幅值图像的函数。

function [H, rhoScale, thetaScale] = myHoughTransform(Im, threshold, rhoRes, thetaRes)


Im是边缘幅值图像, threshold(标量)是用来忽略像素的边缘强度阈值,该类像素具有低边缘滤波器响应。rhoRes(标量)和ThetaRes(标量)分别是HoughTransform累加器沿ρ轴和θ 轴的分辨率。例如,如果theaRes=5°和,则沿θ轴的线带数为360/5=72。

H是Hough变换累加器,包含图像中所有可能的直线“选票”数。rhoscale和thetaScale是myHoughTransform生成Hough变换矩阵H的p和θ 值数组。例如,

843501656d3f22076527e1c8ef270be9.png

87da85e874f863e5386f0b0c7cad3750.png

2.5找直线

function [rhos, thetas] = myHoughLines(H, nLines)

H是Hough变换累加器;RhoRes和taRes是累加器分辨率参数,nLine是返回的行数。Output lineRho和lineTheta都是nline x 1向量,它们分别包含图像中所找到的线条的参数(p和θ)。

f80d41d7b772211527853c20e95844c0.png

(1) Fillgap:如果有不连续的线条需要连接在一起,则将Fillgap设置为相对较高的价值。另一方面,如果有一些不应该在一起的线连接,然后将fillgap设置为一个小值,就像我们在图6中所做的那样。

(2) Minlength:如果图像只有较长的线条,而不是几条较短的线条,则Minlength应该是大的,反之亦然。

(3) 变化”最小长度”: Minlength = 10(左)和Minlength = 30(右),通过增加线的最小长度可以消除图片中的短噪声线。根据不同的图片,情况也不同。

c751563ee9d4c38e698340eacd50ba19.png

3、讨论

我的代码可以用一个参数对所有的图像,但结果并不理想。


从上图可以看出: 

(3)阈值:如果边缘图像中图像的线条不清晰,我们应该将阈值设置为 一个相对较低的值来增强它。同样,我们应该设置一个更高的阈值来降低噪音,如果边缘已经足够清晰。


(4) thetaRes和rhoRes:增加这些值可以在Hough投票中获得更好的分辨率图片,在我的代码中rhoRes=pi/180和thetaRes=2工作得最好。


(5) nLine:如果图像中有很多直线需要匹配,那么应该选择一个较大的nLine。如果有一些线,但大部分是曲线,nLines不应该设置太高。

(6) Fillgap:如果有不连续的线条需要连接在一起,则将Fillgap设置为a 相对较高的价值。另一方面,如果有一些不应该在一起的线连接,然后将fillgap设置为一个小值,就像我们在图6中所做的那样。


(7) Minlength:如果图像只有较长的线条,而不是几条较短的线条,则Minlength应该是大的,反之亦然。在改变分辨率之前,强制条款部分造成的问题最多。

因为如果分辨率较低,应在附近的霍夫峰仅视为一个峰。所以,有些线找不到。改变分辨率后,问题解决了。

但是,对于每个元素在霍夫矩阵中,仍然存在一个问题它的外围可能存在相同的值。我们只能将值设置为0时,有一个值大于它在邻域。所以它可能导致在最后的线拟合过程中有双线。

有一种解决方法,就是检查是否有相邻元素中相同的元素只保留其中一个,但它需要一个循环。我的最佳性能参数包括在上面的记录中,还有另一对不同图像的参数。如果对所有的图像只应用一对参数,那将是:

Sigma = 2; threshold = 0.03;
rhoRes = 2; thetaRes = pi/180;
nLines = 50; ‘FillGap’ = 6; ‘MinLength’ = 15;
The effect of single parameter has already been stated above.

4、代码结构图

355ecc4d3ad7d4cb62ccc6fa7d23254f.jpeg

clc;
clear;


datadir     = '../data';    %the directory containing the images
resultsdir  = '../results'; %the directory for dumping results


%parameters
sigma     = 2;
threshold = 0.005;  %0.03
rhoRes    = 2;
thetaRes  = pi/90;
nLines    = 50;
%end of parameters


imglist = dir(sprintf('%s/*.jpg', datadir));


for i = 1:numel(imglist)


    %read in images%
    [path, imgname, dummy] = fileparts(imglist(i).name);
    img = imread(sprintf('%s/%s', datadir, imglist(i).name));


    if (ndims(img) == 3)
        img = rgb2gray(img);
    end


    img = double(img) / 255;


    %actual Hough line code function calls%  
    [Im Io Ix Iy] = myEdgeFilter(img, sigma);   
    [H,rhoScale,thetaScale] = myHoughTransform(Im, threshold, rhoRes, thetaRes);
    [rhos, thetas] = myHoughLines(H, nLines);
    lines = houghlines(Im>threshold, 180*(thetaScale/pi),...
        rhoScale, [rhos,thetas],'FillGap',5,'MinLength',10);


    %everything below here just saves the outputs to files%
    fname = sprintf('%s/%s_01edge.png', resultsdir, imgname);
    imwrite(Im/max(Im(:)), fname);
    fname = sprintf('%s/%s_02threshold.png', resultsdir, imgname);
    imwrite(Im > threshold, fname);
    fname = sprintf('%s/%s_03hough.png', resultsdir, imgname);
    imwrite(H/max(H(:)), fname);
    fname = sprintf('%s/%s_04lines.png', resultsdir, imgname);


    img2 = img;
    for j=1:numel(lines)
       img2 = drawLine(img2, lines(j).point1, lines(j).point2); 
    end     
    imwrite(img2, fname);
end

5、测试结果

从左往右依次为原图、边缘检测图、二值化图、Hough变换图、最终结果


3d25d42cee9893f122b669e43d26b7b7.jpeg5bb44ddfff33a5b3429a42d1b5849ec6.jpeg

本文仅做学术分享,如有侵权,请联系删文。

 
 

好消息!

小白学视觉知识星球

开始面向外开放啦👇👇👇

 
 

2b8f6389f7a10a7a421789f81d8bfad4.jpeg

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。


下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。


下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。


交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值