常用直线检测算法

📅2026/7/14 13:23:24 👁️次浏览
常用直线检测算法
在智慧交通等业务场景中通常需要使用到直线检测。本文对比较经典的直线检测算法进行了总结和分析并给出的相应的代码实战希望对各位读者有所帮助。1. 场景需求在计算机视觉领域我们经常需要做一些特殊的任务而这些任务中经常会用到直线检测算法比如车道线检测、长度测量等。尽管直线检测的任务看起来比较简单但是在具体的应用过程中你会发现这里面还是有很大的优化空间本文对常用的一些比较经典的直线检测算法进行汇总。2. Hough_line直线检测算法Hough变换是一个比较有名的计算机视觉处理算法该算法可以用来做很多的任务常用的任务包括直线检测、圆检测、椭圆检测等下面我们将对该算法进行简单的分析并进行代码实战。2.1. Hough_line实现步骤步骤1-首先它创建一个二维数组或累加器用于保存两个参数的值并将其初始设置为零步骤2-用r来表示行用θ来表示列步骤3-数组的大小取决于你所需要的精度。假设您希望角度的精度为1度则需要180列直线的最大度数为180步骤4-对于r可能的最大距离是图像的对角线长度。因此取一个像素精度行数可以是图像的对角线长度。2.2. Hough_line代码实战# codingutf-8 # 导入相应的python包 import cv2 import numpy as np # 读取输入图片 img cv2.imread(test3.jpg) # 将彩色图片灰度化 gray cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 使用Canny边缘检测 edges cv2.Canny(gray,50,200,apertureSize 3) # 进行Hough_line直线检测 lines cv2.HoughLines(edges,1,np.pi/180, 200) print(lines) # 遍历每一个r和theta for i in range(len(lines)): r,theta lines[i, 0, 0], lines[i, 0, 1] # 存储cos(theta)的值 a np.cos(theta) # 存储sin(theta)的值 b np.sin(theta) # 存储rcos(theta)的值 x0 a*r # 存储rsin(theta)的值 y0 b*r # 存储(rcos(theta)-1000sin(theta))的值 x1 int(x0 1000*(-b)) # 存储(rsin(theta)1000cos(theta))的值 y1 int(y0 1000*(a)) # 存储(rcos(theta)1000sin(theta))的值 x2 int(x0 - 1000*(-b)) # 存储(rsin(theta)-1000cos(theta))的值 y2 int(y0 - 1000*(a)) # 绘制直线结果 cv2.line(img,(x1,y1), (x2,y2), (0,255,0),2) # 保存结果 cv2.imwrite(test3_r.jpg, img) cv2.imshow(result, img) cv2.waitKey(0)2.3. 效果展示与分析上图展示了一些Hough_line算法的直线检测效果。为了验证该算法的有效性我选择了3个不同的具有挑战性的场景建筑物、答题卡和门。通过观察上面的结果我们可以知道该算法基本上能够检测出图中的直线但是检测的结果并不是很好有很多重复和漏检的情况。除此之外该算法最大的缺点就是需要根据图片去调节参数关键的参数是lines cv2.HoughLines(edges, 1, np.pi/180, 200) 中的200该值设置的越大图片中检测出来的直线数量会越少你需要根据你自己的测试场景进行调节。2.4. HoughP_line代码实战HoughP_line是Hough_line算法的改进版具有更快的速度和更好的效果。# codingutf-8 # 导入相应的python包 import cv2 import numpy as np # 读取输入图片 img cv2.imread(test3.jpg) # 将彩色图片灰度化 gray cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 使用Canny边缘检测 edges cv2.Canny(gray,50,200,apertureSize 3) # 进行Hough_line直线检测 lines cv2.HoughLinesP(edges,1,np.pi/180, 80, 30, 10) # 遍历每一条直线 for i in range(len(lines)): cv2.line(img,(lines[i, 0, 0],lines[i, 0, 1]), (lines[i, 0, 2],lines[i, 0, 3]), (0,255,0),2) # 保存结果 cv2.imwrite(test3_r.jpg, img) cv2.imshow(result, img) cv2.waitKey(0)2.5. 效果展示与分析上图展示了一些HoughP_line算法的直线检测效果。上图都是使用lines cv2.HoughLinesP(edges, 1, np.pi/180, 80, 30, 10) 这个固定的参数来计算出结果的通过观察我们可以发现HoughLinesP不仅使用起来比较方便基本上不需要进行调节参数除此之外该算法能够获得更好的直线检测效果。因此当你想用Hough直线检测算法建议你优先使用HoughP_line算法。3. LSD直线检测算法LSD是OpenCV中集成的一个直线检测算法该算法的直线检测效果优于Hough算法而且具有较好的检测速度推荐使用。3.1. LSD算法简介LSD快速直线检测算法是由Rafael Grompone、Jeremie Jackbowicz、Jean-Michel Morel于2010年发表在PAMI上的文献《LSD: a Line Segment Dectctor》中提出的该算法时间复杂度较霍夫变换低。LSD算法通过对图像局部分析得出直线的像素点集再通过假设参数进行验证求解将像素点集合与误差控制集合合并进而自适应控制误检的数量。一般来说要检测图像中的直线最基本的思想是检测图像中梯度变化较大的像素点集LSD算法也正是利用梯度信息和行列线level-line来进行直线检测的。3.2. LSD代码实战# codingutf-8 import cv2 import numpy as np # 读取输入图片 img0 cv2.imread(test3.jpg) # 将彩色图片转换为灰度图片 img cv2.cvtColor(img0,cv2.COLOR_BGR2GRAY) # 创建一个LSD对象 lsd cv2.createLineSegmentDetector(0) # 执行检测结果 dlines lsd.detect(img) # 绘制检测结果 for dline in dlines[0]: x0 int(round(dline[0][0])) y0 int(round(dline[0][1])) x1 int(round(dline[0][2])) y1 int(round(dline[0][3])) cv2.line(img0, (x0, y0), (x1,y1), (0,255,0), 1, cv2.LINE_AA) # 显示并保存结果 cv2.imwrite(test3_r.jpg, img0) cv2.imshow(LSD, img0) cv2.waitKey(0) cv2.destroyAllWindows()3.3. 效果展示与分析上图展示了一些LSD算法的直线检测效果。通过观察上面的结果我们可以发现该算法的检测结果远远优于Hough和HoughP算法除此之外上述的检测结果都是使用LSD算法的默认参数进行执行如果针对特定的参数进行调节可以取得更好的结果这种情况一般是在你的特定需求场景中对默认的一些参数进行微调操作往往能获得意想不到的结果。上图展示了LSD直线检测算法的一些超参数具体的细节请看该链接。需要说明的是该算法具有3中不同的模式具体的模式如下图所示默认情况下使用模式2即1但是经过测试我发现模式1即0通常输出的效果会更好一些具体的情况需要你根据你的场景进行分析。4. FLD直线检测算法4.1. FLD算法简介FLD直线检测算法是在该论文中被引入的该论文中尝试着使用直线特征来代替原始的SURF点特征进行建筑物识别。与点特征进行相比线特征具有更容易发现和更好的鲁棒性线特征基本上不会受到光照、遮挡、视角变化的影响。下面展示了该算法的直线检测效果从图中我们可以看出线特征比点特征更好一些。4.2. FLD算法代码实战# codingutf-8 import cv2 import numpy as np # 读取输入图片 img0 cv2.imread(test3.jpg) # 将彩色图片转换为灰度图片 img cv2.cvtColor(img0,cv2.COLOR_BGR2GRAY) # 创建一个LSD对象 fld cv2.ximgproc.createFastLineDetector() # 执行检测结果 dlines fld.detect(img) # 绘制检测结果 # drawn_img fld.drawSegments(img0,dlines, ) for dline in dlines: x0 int(round(dline[0][0])) y0 int(round(dline[0][1])) x1 int(round(dline[0][2])) y1 int(round(dline[0][3])) cv2.line(img0, (x0, y0), (x1,y1), (0,255,0), 1, cv2.LINE_AA) # 显示并保存结果 cv2.imwrite(test3_r.jpg, img0) cv2.imshow(LSD, img0) cv2.waitKey(0) cv2.destroyAllWindows()4.3. 效果展示与分析上图展示了FLD直线检测算法的检测效果。通过观察我们可以发现该算法具有很好的检测效果基本上可以检测出图中所有的直线和LSD的性能类似具体使用哪种算法需要你根据自己的应用场景去进行选择。5. EDlines直线检测算法5.1. EDlines算法简介EDlines直线检测算法是在该论文中提出的。本文提出了一个快速、无参数的线段检测器命名为EDLines (Akinlar and Topal, 2011)它产生强大的和准确的结果比最快的已知线段检测器速度更快达到11倍换句话说the LSD by Grompone von Gioi et al. (2008a,b, 2010). 我们的探测器还包括一个线的验证步骤定于亥姆霍兹原理 Helmholtz principle (Desolneux et al., 2008)这让它控制错误检测的数量。EDLines得到的结果我们看到的是LSD非常相似有所有主要的线段检测并有极少数误报。此外EDLines运行实时以炫目的速度为9.45毫秒约10倍的速度比LSD对给定的图像。5.2. EDlines算法实现步骤步骤1-首先给定一个灰度图像运行新的边缘检测、边缘绘制ED算法产生一套干净的像素相邻的链我们称之为边缘。边缘线段直观地反应对象的边界。步骤2-然后利用直线度准则即最小二乘直线拟合法从生成的像素链中提取线段。步骤3-最后线的验证步骤定于亥姆霍兹原理 Helmholtz principle (Desolneux et al., 2008; Grompone von Gioi et al.,2008a) 是用来消除虚假线段的检测。5.3. 效果展示与分析上图展示了EDlines直线检测算法的检测效果。通过上面的观察我们可以发现1该算法能获得和LSD类似的检测结果2该算法抑制了一部分小的误检的直线3该算法具有更快的运行速度是LSD的10倍左右。6. LSWMS直线检测算法LSWMS是一个直线检测算法。本文介绍了一种精确且实时的直线检测方法。以前的直线检测方法都没有使用到图像场景的先验知识因而不需要对输入的参数进行微调。该算法在检测精度和检测速度之间进行了折中文中使用了一个高效的采样方法来进行加速处理然后文中使用一种快速的直线增长算法基于bresenham算法用改进的mean-shift算法提供精确的线段同时保持稳健对抗噪音。测试了该策略的性能对于各种各样的图像将其结果与流行的最新线段检测方法。结果表明我们的建议优于这些工作同时考虑了结果和处理速度。上图展示的是LSWMS论文中的结果。如果感兴趣的读者可以去运行在本文的3张测试图片上面的效果。7. CannyLines直线检测算法7.1. CannyLines算法简介CannyLines算法在该论文中被提出。本文提出了一种鲁棒的线段检测算法有效地检测出输入图像中的线段。首先提出了一种无参数canny算子cannypf通过自适应地设置传统canny算子的低阈值和高阈值从输入图像中稳健地提取边缘映射。其次提出了直接从边缘地图中提取共线点簇的有效像素连接和分割技术并基于最小二乘法对初始线段进行拟合。第三通过有效的扩展和合并生成更长、更完整的线段。最后根据helmholtz原理对检测到的所有线段进行了验证该原理同时考虑了梯度方向和幅度信息。在一组有代表性的图像上的实验结果表明与常用的两种线段检测器lsd和edline相比我们提出的cannyline线段检测器能够提取出更有意义的线段特别是在人造场景中。7.2. 效果展示与分析上图展示了CannyLines直线检测算法的检测效果。通过观察上图我们可以发现该算法能够获得更加准确的检测结果具有更少的误检。该算法主要是提高了边缘检测的效果具体的效果如下所示8. MCMLSD直线检测算法8.1. MCMLSD算法简介MCMLSD算法出自于该论文。论文中提出了一个融合两者优点的概率算法。在第一阶段使用全局概率hough方法。在第二阶段在图像域中分析每个检测到的行以定位在霍夫图中生成峰值的线段。通过将搜索限制在一条直线上线段的分布线上的点序列可以被建模为马尔可夫链和概率最优标签使用标准动态规划算法精确计算在线性时间内。马尔可夫假设同时也产生了一种直观的排名方法它使用估计期望值的边际后验概率线段上正确标记的点的数目。评估由此产生的马尔可夫链边缘线段检测器mcmlsd我们开发并应用了一种新的定量方法控制分段不足和分段过量的评估方法。在YorkUrbanDB数据集的评价结果表明所提出的MCMLSD方法优于以相当大的优势达到最先进水平。8.2. 效果展示与分析上图展示了MCMLSD算法的检测效果。通过上面的观察我们可以发现该算法取得了很好的检测效果但是美中不足的是该算法的运行速度比较慢可能也和matlab代码有关吧。9. LSM直线检测算法9.1. LSM算法简介LSM算法不仅仅是一个直线检测算法同时也是一个直线合并算法。论文中提出了一种合并这些断开的线段的算法以恢复原始的感知准确的线段。该算法根据角度和空间接近度对线段进行分组。然后将每组中满足新的自适应合并准则的线段对依次合并成一条线段。重复此过程直到不再合并行段。我们还提出了一种定量比较线段检测算法的方法。在york-urban数据集上的结果表明与最新的线段检测算法相比我们的合并线段更接近人类标记的地面真线段。9.2. 效果展示与分析上图展示了直线检测算法LSM的检测效果。左边一列表示的是LSD的检测结果右边一列表示的是LSM算法的优化效果图中不同的颜色表示不同的直线。通过上面的观察我们可以发现LSM可以将一些间断的直线合并成一条更长的直线这在现实场景中具有很大的用处但是我们也会发现LSM算法会错误的将一些直线进行合并会造成一些误差。10. Wireframewireframe是随数据集提出的直线检测网络。其思路是一路检测直线的两个端点(junction)一路对直线像素做分割。其中junction路需要去回归端点的位置(junction center decoders)和端点对应的直线方向、置信度信息(junction branch decoders)而line路则是要判断每个点是否是直线像素。wireframe架构对于端点需要注意其所对应的直线不一定只有一条如矩形顶点都对应两条边。对此wireframe首先将可能的方向分为K份每份360/K度作为一个bin。文章假设在端点每个bin的方向上只包含一条线段。因此网络需要预测端点在K个方向上有直线的概率同时对直线的精确角度进行回归精确角度为相对bin起点的角度偏移量。另一方面对于直线像素的分割wireframe采用级联沙漏网络Stacked Hourglass Networks作为backbone。级联沙漏网络最初应用于人体姿态检测任务其名称由来是在网络架构上不断地将bottom-up,top-down的沙漏型结构子网络级联从而不断地整合全局和局部信息有利于对人体关节、四肢、人体位置等各个尺度上的信息进行整合。直线检测任务与人体姿态检测任务在全局、局部信息的利用上是类似的从直线跨度上看是宏观的但从直线像素本身的定位来看则是微观的因此也需要不断整合各个尺度上的信息。wireframe网络并非端到端的网络其需要后处理来将分割结果和端点检测结果进行融合才能得到最终检测结果。之后提到的几篇文章都是端到端的检测网络。11. LCNNLCNNLine-CNN是双阶段的检测网络它可以看成是RCNN从二维到一维上的迁移。名字和网络架构都可体现LCNN网络架构LCNN首先进行特征提取采用的backbone也是级联沙漏网络。随后得到的特征图送入junction header来预测可能的端点位置。在推理时对预测的所有端点两两生成一个line proposal类比RCNN region proposal随后通过proposal的两个端点位置去特征图上采样得到该proposal对应的特征向量line feature采样的过程为LoI Pooling类比RCNN RoI pooling。最终将line feature送入全连接层得到该proposal的分数从而判定是否为一条直线。值得注意的是由于边的数目是远小于所有端点的两两组合数的因此proposal中会生产大量的负样本造成正负样本数的严重不平衡会影响后续网络的训练。因而在训练时Line Sampler并非生成所有的proposal而是分别从正负样本中采样数目相等的proposal进行训练。同时Line Sampler还会保证一些难样本如一些与正样本有重合部分的负样本的数目来增加鲁棒性。12. TP-LSDTP-LSD 是单阶段的直线检测网络。TP表示“Tri-points”表示其对直线的三点式建模方式这也是它能做到single stage的原因。不同的直线建模方式将直线表示成中点及到两端点的方向和距离就可以同时去回归中点位置、直线方向、中点到两侧的距离。如此一来就可以避免预测端点再对端点两两组合预测分数的过程。TP-LSD网络架构从其网络架构看出它也是先利用通用的特征提取器提取多尺度特征随后通过不同的解码层分别进行直线像素语义分割、中点检测中点到两端点的位移向量预测。直线语义分割作为辅助信息帮助中点定位位移向量求解以及最终的融合。一般来说在detection任务中做segmentation分支都能提升检测效果。13. HAWP模型结构图如下所示HAWP 主要分为三个部分Proposal Initialization主要是根据输入图像经过某种网络论文中使用了堆叠沙漏网络 Stacked Hourglass Network得到的特征图预测 junctions 和 line segmentsProposal Refinement对线段和连接点进行匹配将不能匹配的线段和连接点舍弃掉Proposal Verification将上一步保留的线段和连接点进行分类这里使用的是 L-CNN 当中相同的方法结果展示总结本文对比较经典的直线检测算法进行了总结和分析。对于直线检测这个任务而言它在现实场景中具有很多的应用对于一个具体的场景你可以根据自己的需要从本文中选择出一个合适的直线检测算法进行应用如果你的场景比较简单HoughP_line算法可能就可以满足你的要求如果你同时对速度和精度有要求可以选择使用EDlines等如果你需要获得尽可能长的直线那么建议你使用LSM直线检测算法。总而言之最适合你的场景的算法才是最好的算法。参考文献直线检测算法汇总_技术挖掘者的博客-CSDN博客_直线检测算法基于深度学习的直线检测算法 - 知乎HAWP使用预训练模型实现线框解析_AI Studio的博客-CSDN博客