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


    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    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
    
    • 1
    • 2

    使用该类检测直线并显示的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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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 " << 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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    3. 区别与应用

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

  • 相关阅读:
    VLAN笔记
    《大模型时代-ChatGPT开启通用人工智能浪潮》精华摘抄
    渗透测试-Python安全工具编程进阶
    Unity微信小游戏登录授权获取用户信息
    Java基础知识总结(42)
    php的短信验证的流程,如何实现前端js加后端php
    el-table 表格表头、单元格、滚动条样式修改
    C++ -- IO流
    java计算机毕业设计固定资产管理系统源码+mysql数据库+系统+LW文档+部署
    【TypeScript】语法详解 - 类型操作的补充
  • 原文地址:https://blog.csdn.net/qq_42679415/article/details/136342328