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(霍夫线检测)的结果,如果要对比,请点击下面的链接: