LSD快速直线检测的原理概要及OpenCV代码实现(CV类LineSegmentDetector)

LSD快速直线检测算法是由Rafael Grompone、Jeremie Jackbowicz、Jean-Michel Morel于2010年发表在PAMI上的文献《LSD:a Line Segment Dectctor》中提出的,该算法时间复杂度较霍夫变换低。LSD算法通过对图像局部分析,得出直线的像素点集,再通过假设参数进行验证求解,将像素点集合与误差控制集合合并,进而自适应控制误检的数量 。由于LSD算法是对图像的局部分析,所以对于特别模糊的目标,或小目标,LSD是具有较大优势的。

LSD算法与FLD直线检测算法相比较的一个实例的链接如下:
https://blog.csdn.net/WZZ18191171661/article/details/101116949

一般来说,要检测图像中的直线,最基本的思想是检测图像中梯度变化较大的像素点集,LSD算法也正是利用梯度信息和行列线(level-line)来进行直线检测的。

下面是LSD算法的相关基础知识:

 

 关于LSD快速直线检测算法的原理,除了上面博主从书本上的摘录,大家还可以参考下面的博文:

关于LSD快速直线检测算法的原理,可以参考下面这篇博文:

https://blog.csdn.net/polly_yang/article/details/10085401

关于LSD快速直线检测算法的算法实现和相关代码,可以参考下面这篇博文:
https://blog.csdn.net/tianwaifeimao/article/details/17678669

OpenCV提供了类LineSegmentDetector用于进行LSD快速直线检测,下面介绍其主要的成员函数。

①成员函数cv::LineSegmentDetector::createLineSegmentDetector()

可使用该成员函数创建类LineSegmentDetector的对象指针,并实始化对象。

该成员函数的原型如下:

Ptr<LineSegmentDetector> cv::createLineSegmentDetector	(	int _refine = LSD_REFINE_STD,
															double 	_scale = 0.8,
															double 	_sigma_scale = 0.6,
															double 	_quant = 2.0,
															double 	_ang_th = 22.5,
															double 	_log_eps = 0,
															double 	_density_th = 0.7,
															int 	_n_bins = 1024 
														)	

这里介绍下其第一个参数_refine:

_refine---OpenCV中提供三种LSD对象初始化参数,如下:
               LSD_REFINE_NONE,没有改良的方式;
               LSD_REFINE_STD,标准改良方式,将带弧度的线(拱线)拆成多个可以逼近原线段的直线度;
              LSD_REFINE_ADV,进一步改良方式,计算出错误警告数量,通过增加精度,减少尺寸进一步精确直线。

其它参数一般用默认值就好。

②成员函数cv::LineSegmentDetector::detect()

该成员函数对输入图像进行线检测,其函数原型如下:

void detect(InputArray _image, OutputArray _lines,
                        OutputArray width = noArray(), OutputArray prec = noArray(),
                        OutputArray nfa = noArray()) = 0;

通常使用时只需要填第一个参数输入图像和第二个参数输出图像,所以后面几个参数的意义这里就不介绍了,有兴趣想进一步了解的同学看下面这段描述吧。

/**
 * Detect lines in the input image.
 *
 * @param _image    A grayscale(CV_8UC1) input image.
 *                  If only a roi needs to be selected, use
 *                  lsd_ptr->detect(image(roi), ..., lines);
 *                  lines += Scalar(roi.x, roi.y, roi.x, roi.y);
 * @param _lines    Return: A vector of Vec4i or Vec4f elements specifying the beginning and ending point of a line.
 *                          Where Vec4i/Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
 *                          Returned lines are strictly oriented depending on the gradient.
 * @param width     Return: Vector of widths of the regions, where the lines are found. E.g. Width of line.
 * @param prec      Return: Vector of precisions with which the lines are found.
 * @param nfa       Return: Vector containing number of false alarms in the line region, with precision of 10%.
 *                          The bigger the value, logarithmically better the detection.
 *                              * -1 corresponds to 10 mean false alarms
 *                              * 0 corresponds to 1 mean false alarm
 *                              * 1 corresponds to 0.1 mean false alarms
 *                          This vector will be calculated _only_ when the objects type is REFINE_ADV
 */

③成员函数cv::LineSegmentDetector::drawSegments()

该成员函数用于将检测到的线绘制出来。其原型如下:

void drawSegments(InputOutputArray _image, InputArray lines)

从原型中可以看出,这个函数的使用很简单,参数的意义就不说了。

下面上利用OpenCV的类LineSegmentDetector实现LSD直线检测的示例代码:

注意:由于OpenCV4已经移除了类LineSegmentDetector,所以请大家将自己的OpenCV代码版本切换到OpenCV3.x再运行下面的代码。

代码中用到的图像下载链接:https://pan.baidu.com/s/1AcT_pNXGy7w7E2t1qx2xBQ?pwd=dt3g 

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术

//OpenCV版本 OpenCV3.0

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;


int main()
{
	
	cv::Mat srcImage = cv::imread("F:/material/images/P0041-building.jpg", 0);
  	if (!srcImage.data)   
       return -1;
	// canny边缘检测
	Canny(srcImage, srcImage, 50, 200, 3);
	// 创建LSD检测类
#if 1
	Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_STD);
#else
	Ptr<LineSegmentDetector> ls = createLineSegmentDetector(LSD_REFINE_NONE);
#endif
	double start = double(getTickCount());
	vector<Vec4f> lines_std;
	// 线检测
	ls->detect(srcImage, lines_std);
	double duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency();
	std::cout << "It took " << duration_ms << " ms." << std::endl;

	// 绘图线检测结果
	Mat drawnLines(srcImage);
	ls->drawSegments(drawnLines, lines_std);
	cv::imshow("Standard refinement", drawnLines);
	cv::waitKey();
	return 0;
}

运行结果如下图所示

个人感觉这个结果要优于Hough_line(霍夫线检测)的结果,如果要对比,请点击下面的链接:

https://blog.csdn.net/wenhao_ir/article/details/51774444

  • 17
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值