opencv中两个LSD直线检测算法的区别与应用

39 篇文章 2 订阅
12 篇文章 1 订阅

opencv中两个LSD直线检测算法的区别与应用

同样是Line Segment Detector(lsd)算法,opencv中提供了两种实现,并且位于不同的模块。下面分别介绍它们的使用方法:

1. LineSegmentDetector

由于源码许可证问题 OpenCV 3.4.6-3.4.15、4.1.0-4.5.3中无法使用这个方法

使用该类检测直线并显示的代码如下:

import cv2

 if __name__ == '__main__':
    img = cv2.imread("test.jpg")
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_img = cv2.GaussianBlur(gray_img, (3,3), 2.0)
    #LineSegmentDetector
    lsd = cv2.createLineSegmentDetector(refine=cv2.LSD_REFINE_NONE, scale=0.8, ang_th=35)
    lines_detected, width, prec, nfa = lsd.detect(gray_img)
    #lsd.drawSegments(img,lines_detected)
    #绘制检测结果
    for dline in lines_detected:
        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(mask, (x0, y0), (x1,y1), 255, 1, cv2.LINE_AA)
    cv2.imshow("Detected lines", img)
    cv2.waitKey(0)
    cv.destroyAllWindows()

c++示例代码如下(lsd_lines.cpp):

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    cv::CommandLineParser parser(argc, argv,
                                 "{input   i|../data/building.jpg|input image}"
                                 "{refine  r|false|if true use LSD_REFINE_STD method, if false use LSD_REFINE_NONE method}"
                                 "{canny   c|false|use Canny edge detector}"
                                 "{overlay o|false|show result on input image}"
                                 "{help    h|false|show help message}");
    if (parser.get<bool>("help"))
    {
        parser.printMessage();
        return 0;
    }
    parser.printMessage();
    String filename = parser.get<String>("input");
    bool useRefine = parser.get<bool>("refine");
    bool useCanny = parser.get<bool>("canny");
    bool overlay = parser.get<bool>("overlay");
    Mat image = imread(filename, IMREAD_GRAYSCALE);
    if( image.empty() )
    {
        cout << "Unable to load " << filename;
        return 1;
    }
    imshow("Source Image", image);
    if (useCanny)
    {
        Canny(image, image, 50, 200, 3); // Apply Canny edge detector
    }
    // Create and LSD detector with standard or no refinement.
    Ptr<LineSegmentDetector> ls = useRefine ? createLineSegmentDetector(LSD_REFINE_STD) : createLineSegmentDetector(LSD_REFINE_NONE);
    double start = double(getTickCount());
    vector<Vec4f> lines_std;
    // Detect the lines
    ls->detect(image, lines_std);
    double duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency();
    std::cout << "It took " << duration_ms << " ms." << std::endl;
    // Show found lines
    if (!overlay || useCanny)
    {
        image = Scalar(0, 0, 0);
    }
    ls->drawSegments(image, lines_std);
    String window_name = useRefine ? "Result - standard refinement" : "Result - no refinement";
    window_name += useCanny ? " - Canny edge detector used" : "";
    imshow(window_name, image);
    waitKey();
    return 0;
}

2. cv::line_descriptor::LSDDetector

这个类在opencv_contrib中实现。源码目录结构示例如下:在这里插入图片描述
如果c++编译opencv时未包含contrib模块;或在python中用pip安装了opencv-python而不是opencv-contrib-python,均无法使用该LSD直线检测方法。
python用户只管卸载opencv-python,安装opencv-contrib-python,前者是后者的子集。

pip uninstall opencv-python
pip install opencv-contrib-python

使用该类检测直线并显示的python代码如下:

import cv2

 if __name__ == '__main__':
    img = cv2.imread("test.jpg")
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_img = cv2.GaussianBlur(gray_img, (3,3), 2.0)
    #LSDDetector
    lsd = cv2.line_descriptor_LSDDetector.createLSDDetector()
    lines = lsd.detect(gray, 2, 1)
    for kl in lines:#绘制检测结果
        if kl.octave == 0:
            # cv.line only accepts integer coordinate
            pt1 = (int(kl.startPointX), int(kl.startPointY))
            pt2 = (int(kl.endPointX), int(kl.endPointY))
            cv.line(img, pt1, pt2, [255, 0, 0], 2)
    cv.imshow('Detected lines', img)
    cv.waitKey(0)
    cv.destroyAllWindows()

c++示例代码如下(lines_extraction.cpp):

#include <iostream>
#include <opencv2/opencv_modules.hpp>
#include <opencv2/line_descriptor.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace cv::line_descriptor;
using namespace std;

static const char* keys =
{ "{@image_path | | Image path }" };

static void help()
{
  cout << "\nThis example shows the functionalities of lines extraction " << "furnished by BinaryDescriptor class\n"
       << "Please, run this sample using a command in the form\n" << "./example_line_descriptor_lines_extraction <path_to_input_image>" << endl;
}

int main( int argc, char** argv )
{
  /* get parameters from comand line */
  CommandLineParser parser( argc, argv, keys );
  String image_path = parser.get<String>( 0 );

  if( image_path.empty() )
  {
    help();
    return -1;
  }

  /* load image */
  cv::Mat imageMat = imread( image_path, 1 );
  if( imageMat.data == NULL )
  {
    std::cout << "Error, image could not be loaded. Please, check its path" << std::endl;
    return -1;
  }

  /* create a random binary mask */
  cv::Mat mask = Mat::ones( imageMat.size(), CV_8UC1 );

  /* create a pointer to a BinaryDescriptor object with deafult parameters */
  Ptr<LSDDetector> bd = LSDDetector::createLSDDetector();

  /* create a structure to store extracted lines */
  vector<KeyLine> lines;

  /* extract lines */
  cv::Mat output = imageMat.clone();
  bd->detect( imageMat, lines, 2, 1, mask );

  /* draw lines extracted from octave 0 */
  if( output.channels() == 1 )
    cvtColor( output, output, COLOR_GRAY2BGR );
  for ( size_t i = 0; i < lines.size(); i++ )
  {
    KeyLine kl = lines[i];
    if( kl.octave == 0)
    {
      /* get a random color */
      int R = ( rand() % (int) ( 255 + 1 ) );
      int G = ( rand() % (int) ( 255 + 1 ) );
      int B = ( rand() % (int) ( 255 + 1 ) );

      /* get extremes of line */
      Point pt1 = Point2f( kl.startPointX, kl.startPointY );
      Point pt2 = Point2f( kl.endPointX, kl.endPointY );

      /* draw line */
      line( output, pt1, pt2, Scalar( B, G, R ), 3 );
    }

  }

  /* show lines on image */
  imshow( "LSD lines", output );
  waitKey();
}

3. 区别与应用

这两种LSD实现的处理结果基本一致,但是获取检测到的直线的端点坐标的方式有所不同:
前者的直线检测结果是numpy array类型,每个直线由4个浮点数表示(x1, y1, x2, y2);后者的检测结果的直线类型,具有起点和端点成员变量,分别是(startPointX,startPointY,endPointX,endPointY),并且还具有直线的方向(角度)和长度成员变量。
具体从上面两个代码片段的可视化部分展示的清清楚楚。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值