日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

直线检测算法汇总

發布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 直线检测算法汇总 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

    • 1、場景需求
    • 2、Hough_line直線檢測算法
        • 2.1 Hough_line實現步驟
        • 2.2 Hough_line代碼實戰
        • 2.3 效果展示與分析
        • 2.4 HoughP_line代碼實戰
        • 2.5 效果展示與分析
    • 3、LSD直線檢測算法
        • 3.1 LSD算法簡介
        • 3.2 LSD代碼實戰
        • 3.3 效果展示與分析
    • 4、FLD直線檢測算法
        • 4.1 FLD算法簡介
        • 4.2 FLD算法代碼實戰
        • 4.3 效果展示與分析
    • 5、EDlines直線檢測算法
        • 5.1 EDlines算法簡介
        • 5.2 EDlines算法實現步驟
        • 5.3 EDlines算法代碼實戰
        • 5.4 效果展示與分析
    • 6、LSWMS直線檢測算法
        • 6.1 LSWMS算法簡介
        • 6.2 LSWMS算法代碼實現
        • 6.3 效果展示與分析
    • 7、CannyLines直線檢測算法
        • 7.1 CannyLines算法簡介
        • 7.2 CannyLines算法代碼實戰
        • 7.3 效果展示與分析
    • 8、MCMLSD直線檢測算法
        • 8.1 MCMLSD算法簡介
        • 8.2 MCMLSD算法代碼實戰
        • 8.3 效果展示與分析
    • 9、LSM直線檢測算法
        • 9.1 LSM算法簡介
        • 9.2 LSM算法代碼實戰
        • 9.3 效果展示與分析
    • 10、總結
    • 參考資料
    • 注意事項

1、場景需求

??在計算機視覺領域,我們經常需要做一些特殊的任務,而這些任務中經常會用到直線檢測算法,比如車道線檢測、長度測量等。盡管直線檢測的任務看起來比較簡單,但是在具體的應用過程中,你會發現這里面還是有很大的優化空間,本文對常用的一些比較經典的直線檢測算法進行匯總。

2、Hough_line直線檢測算法

??Hough變換是一個比較有名的計算機視覺處理算法,該算法可以用來做很多的任務,常用的任務包括直線檢測、圓檢測、橢圓檢測等,下面我們將對該算法進行簡單的分析并進行代碼實戰。

2.1 Hough_line實現步驟

步驟1-首先,它創建一個二維數組或累加器(用于保存兩個參數的值),并將其初始設置為零;
步驟2-用r來表示行,用θ來表示列;
步驟3-數組的大小取決于你所需要的精度。假設您希望角度的精度為1度,則需要180列(直線的最大度數為180);
步驟4-對于r,可能的最大距離是圖像的對角線長度。因此,取一個像素精度,行數可以是圖像的對角線長度。

2.2 Hough_line代碼實戰

# coding=utf-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算法的改進版,具有更快的速度和更好的效果。

# coding=utf-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-項目主頁-論文鏈接-代碼鏈接
??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代碼實戰

# coding=utf-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算法代碼實戰

# coding=utf-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直線檢測算法

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算法代碼實戰

下面僅僅展示了主函數的代碼,具體的代碼請在網盤鏈接中下載。

#include "EDLib.h" #include <iostream>using namespace cv; using namespace std;int main() { //***************************** ED Edge Segment Detection *****************************//Detection of edge segments from an input image string img_name = "test3.jpg";Mat testImg = imread(img_name, 0);// imshow("Source Image", testImg);//Call ED constructorED testED = ED(testImg, SOBEL_OPERATOR, 36, 8, 1, 10, 1.0, true); // apply ED algorithm//Show resulting edge imageMat edgeImg = testED.getEdgeImage();//imshow("Edge Image - PRESS ANY KEY TO CONTINUE", edgeImg);//waitKey();//Output number of segmentsint noSegments = testED.getSegmentNo();std::cout << "Number of edge segments: " << noSegments << std::endl;//Get edges in segment form (getSortedSegments() gives segments sorted w.r.t. legnths) std::vector< std::vector<Point> > segments = testED.getSegments();//***************************** EDLINES Line Segment Detection *****************************//Detection of line segments from the same imageEDLines testEDLines = EDLines(testImg);Mat lineImg = testEDLines.getLineImage(); //draws on an empty imageimwrite("test3_r.jpg", lineImg);// imshow("Line Image 1 - PRESS ANY KEY TO CONTINUE", lineImg);//Detection of lines segments from edge segments instead of input image//Therefore, redundant detection of edge segmens can be avoidedtestEDLines = EDLines(testED);lineImg = testEDLines.drawOnImage(); //draws on the input imageimwrite("test3_a.jpg", lineImg);imshow("Line Image 2 - PRESS ANY KEY TO CONTINUE", lineImg);//Acquiring line information, i.e. start & end pointsvector<LS> lines = testEDLines.getLines();int noLines = testEDLines.getLinesNo();std::cout << "Number of line segments: " << noLines << std::endl;waitKey();

5.4 效果展示與分析


??上圖展示了EDlines直線檢測算法的檢測效果。通過上面的觀察,我們可以發現:1)該算法能獲得和LSD類似的檢測結果;2)該算法抑制了一部分小的誤檢的直線;3)該算法具有更快的運行速度,是LSD的10倍左右。

6、LSWMS直線檢測算法

LSWMS-論文鏈接-代碼鏈接

6.1 LSWMS算法簡介

??LSWMS是一個直線檢測算法。本文介紹了一種精確且實時的直線檢測方法。以前的直線檢測方法都沒有使用到圖像場景的先驗知識,因而不需要對輸入的參數進行微調。該算法在檢測精度和檢測速度之間進行了折中,文中使用了一個高效的采樣方法來進行加速處理,然后,文中使用一種快速的直線增長算法基于bresenham算法用改進的mean-shift算法提供精確的線段,同時保持穩健對抗噪音。測試了該策略的性能對于各種各樣的圖像,將其結果與流行的最新線段檢測方法。結果表明,我們的建議優于這些工作同時考慮了結果和處理速度。

6.2 LSWMS算法代碼實現

/** Project: lineSegments (LSWMS Line Segment using Weighted Mean-Shift)** File: main.cpp** Contents: Creation, initialisation and usage of LSWMS object* for the detection of line segments in images or videos** Author: Marcos Nieto <marcos.nieto.doncel@gmail.com>** Homepage: www.marcosnieto.net*/#ifdef WIN32#include <windows.h>#include <time.h> #endif#ifdef linux#include <stdio.h>#include <sys/time.h>#include <time.h> #endif#include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/videoio.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgproc/types_c.h>#include "LSWMS.h"using namespace std; using namespace cv;// Timing #ifdef WIN32double t1, t2; #elseint t1, t2; struct timeval ts; #endif double t;void help() {cout << "/*\n"<< " **************************************************************************************************\n"<< " * Line segment detection using WMS \n"<< " * ----------------------------------------------------\n" << " * \n"<< " * Author:Marcos Nieto\n"<< " * www.marcosnieto.net\n"<< " * marcos.nieto.doncel@gmail.com\n"<< " * \n"<< " * Date:01/04/2012\n"<< " **************************************************************************************************\n"<< " * \n"<< " * Usage: \n" << " * -video # Specifies video file as input (if not specified, camera is used) \n"<< " * -image # Specifies image file as input (if not specified, camera is used) \n"<< " * -verbose # Actives verbose: ON, OFF (default)\n"<< " * -play # ON: the video runs until the end; OFF: frame by frame (key press event)\n"<< " * -resizedWidth # Specifies the desired width of the image (the height is computed to keep aspect ratio)\n"<< " * -numMaxLSegs # Specifies the maximum number of line segments to detected.\n" << " *\n"<< " * -hough # ON: Applies OpenCV HoughLinesP for comparison (PPHT)\n"<< " *\n"<< " * Example:\n"<< " * lineSegment -video myVideo.avi -verbose ON -play OFF\n"<< " * lineSegment -image myImage.jpg -resizedWidth 300 -numMaxLSegs 100\n"<< " * lineSegment -image myImage.jpg -hough ON\n"<< " * \n"<< " * Keys:\n"<< " * Esc: Quit\n"<< " */\n" << endl; } void processPPHT(cv::Mat &img, std::vector<LSEG> &lSegs) {cv::Mat imgGRAY;cv::cvtColor(img, imgGRAY, CV_RGB2GRAY);cv::Mat dst;cv::Canny(imgGRAY, dst, 20, 80, 3);std::vector<cv::Vec4i> lines;cv::HoughLinesP(dst, lines, 1, CV_PI/180, 80, 30, 10);LSEG lSeg;cv::Point p1, p2;lSegs.clear();for(size_t i=0; i<lines.size(); i++){lSeg.clear();p1.x = lines[i][0];p1.y = lines[i][1];p2.x = lines[i][2];p2.y = lines[i][3];lSeg.push_back(p1);lSeg.push_back(p2);lSegs.push_back(lSeg); } } void drawPPHT(cv::Mat &dst, std::vector<LSEG> &lSegs, cv::Scalar color) {for(size_t i=0; i<lSegs.size(); i++){ cv::line(dst, lSegs[i][0], lSegs[i][1], color, 2); } } /** Main function*/ int main(int argc, char** argv) { // Imagescv::Mat inputImg, imgGRAY; cv::Mat outputImg, outputImgPPHT;int procWidth=0, procHeight=0;cv::Size procSize;// Other variableschar *videoFileName = 0;char *imageFileName = 0;cv::VideoCapture video;bool useCamera = true;bool playMode = true;bool stillImage = false;bool verbose = false;int numMaxLSegs = 0; bool usePPHT = false;// Line segments (LSWMS and PPHT)std::vector<LSEG> lSegs, lSegsPPHT;std::vector<double> errors;// Start showing helphelp();// Parse argumentsif(argc < 2)return -1; for(int i=1; i<argc; i++){const char* s = argv[i];if(strcmp(s, "-video" ) == 0){// Input video is a video filevideoFileName = argv[++i];useCamera = false;}else if(strcmp(s,"-hough") == 0){const char* ss = argv[++i];if(strcmp(ss, "ON") == 0 || strcmp(ss, "on") == 0|| strcmp(ss, "TRUE") == 0 || strcmp(ss, "true") == 0 || strcmp(ss, "YES") == 0 || strcmp(ss, "yes") == 0 )usePPHT = true; }else if(strcmp(s,"-image") == 0){// Input is a image fileimageFileName = argv[++i];stillImage = true;useCamera = false;} else if(strcmp(s, "-numMaxLSegs") == 0){numMaxLSegs = atoi(argv[++i]); } else if(strcmp(s, "-resizedWidth") == 0){procWidth = atoi(argv[++i]);}else if(strcmp(s, "-verbose" ) == 0){const char* ss = argv[++i];if(strcmp(ss, "ON") == 0 || strcmp(ss, "on") == 0 || strcmp(ss, "TRUE") == 0 || strcmp(ss, "true") == 0 || strcmp(ss, "YES") == 0 || strcmp(ss, "yes") == 0 )verbose = true; }else if(strcmp(s, "-play" ) == 0){const char* ss = argv[++i];if(strcmp(ss, "OFF") == 0 || strcmp(ss, "off") == 0 || strcmp(ss, "FALSE") == 0 || strcmp(ss, "false") == 0 || strcmp(ss, "NO") == 0 || strcmp(ss, "no") == 0 || strcmp(ss, "STEP") == 0 || strcmp(ss, "step") == 0)playMode = false; } }// Open video inputif( useCamera )video.open(0);else{if(!stillImage)video.open(videoFileName);}// Check video inputint width = 0, height = 0, fps = 0, fourcc = 0;if(!stillImage){if( !video.isOpened() ){printf("ERROR: can not open camera or video file\n");return -1;}else{// Show video informationwidth = (int) video.get(CAP_PROP_FRAME_WIDTH);height = (int) video.get(CAP_PROP_FRAME_HEIGHT);fps = (int) video.get(CAP_PROP_FPS);fourcc = (int) video.get(CAP_PROP_FOURCC);if(!useCamera)printf("Input video: (%d x %d) at %d fps, fourcc = %d\n", width, height, fps, fourcc);elseprintf("Input camera: (%d x %d) at %d fps\n", width, height, fps);}}else{inputImg = cv::imread(imageFileName);if(inputImg.empty())return -1;width = inputImg.cols;height = inputImg.rows;printf("Input image: %s, Size (%d x %d)\n", imageFileName, width, height);playMode = false;}// Resize if(procWidth != 0){ procHeight = (int)(height*((double)procWidth/width));procSize = cv::Size(procWidth, procHeight);printf("Resize to: (%d x %d)\n", procWidth, procHeight); }elseprocSize = cv::Size(width, height);if(numMaxLSegs != 0) printf("NumMaxLSegs=%d\n", numMaxLSegs);// ---------------------------// Create and init LSWMSint R = 3;LSWMS lswms(procSize, R, numMaxLSegs, verbose);if(numMaxLSegs==0)printf("LSWMS object created: R=%d\n\n", R);elseprintf("LSWMS object created: R=%d, numMaxLSegs=%d\n\n", R, numMaxLSegs);// ---------------------------// MAIN LOOPint frameNum=0;for( ;; ){if(!stillImage){//if(verbose) printf("\n-------------------------\nFRAME #%6d\n", frameNum);frameNum++;// Get current image video >> inputImg;} else{printf("-------------------------\n");} if( inputImg.empty() )break;// Resize to processing sizecv::resize(inputImg, inputImg, procSize); // Color Conversionif(inputImg.channels() == 3){cv::cvtColor(inputImg, imgGRAY, CV_BGR2GRAY); inputImg.copyTo(outputImg);if(usePPHT)inputImg.copyTo(outputImgPPHT); }else{inputImg.copyTo(imgGRAY);cv::cvtColor(inputImg, outputImg, CV_GRAY2BGR);if(usePPHT)cv::cvtColor(inputImg, outputImgPPHT, CV_GRAY2BGR); }// ++++++++++++++++++++++++++++++++++++++++// Process LSWMS#ifdef WIN32t1 = ::GetTickCount();#elsegettimeofday(&ts,0);t1 = (ts.tv_sec * 1000 + (ts.tv_usec / 1000));#endiflswms.run(inputImg, lSegs, errors); #ifdef WIN32t2 = ::GetTickCount();#elsegettimeofday(&ts,0);t2 = (ts.tv_sec * 1000 + (ts.tv_usec / 1000));#endif // process time = t2 - t1 t = (double)t2-(double)t1;cv::Scalar mean, stddev;cv::meanStdDev(errors, mean, stddev);if(!stillImage)printf("Fr.#%d - LSWMS: %d lines / %.0f ms , Ang.Error: (Mean, Std)=(%.2f, %.2f)(deg)\n", frameNum, lSegs.size(), t, mean.val[0]*180/CV_PI, stddev.val[0]*180/CV_PI);elseprintf("LSWMS: %d segments\nAngular Error: Mean = %.2f (deg), Std = %.2f (deg)\nProcess Time = %.0f (ms)\n", lSegs.size(), mean.val[0]*180/CV_PI, stddev.val[0]*180/CV_PI, t);//lswms.drawLSegs(outputImg, lSegs,CV_RGB(255,0,0), 2); // drawing all line segments the samelswms.drawLSegs(outputImg, lSegs, errors); // drawing according to errors// ++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++ if(usePPHT){// Process PPHT#ifdef WIN32t1 = ::GetTickCount();#elsegettimeofday(&ts,0);t1 = (ts.tv_sec * 1000 + (ts.tv_usec / 1000));#endifprocessPPHT(inputImg, lSegsPPHT); #ifdef WIN32t2 = ::GetTickCount();#elsegettimeofday(&ts,0);t2 = (ts.tv_sec * 1000 + (ts.tv_usec / 1000));#endif// process time = t2 - t1 t = (double)t2-(double)t1;drawPPHT(outputImgPPHT, lSegsPPHT, CV_RGB(0,0,255));if(!stillImage)printf("Fr.#%d - PPHT: %d lines / %.0f ms\n", frameNum, lSegsPPHT.size(), t);elseprintf("\nPPHT: %d segments\nProcess Time = %.0f (ms)\n", lSegsPPHT.size(), t);// ++++++++++++++++++++++++++++++++++++++++ }// Viewimshow("LSWMS", outputImg); if(usePPHT)imshow("PPHT", outputImgPPHT);if(stillImage){cv::imwrite("lswms.bmp", outputImg);if(usePPHT)cv::imwrite("ppht.bmp", outputImgPPHT);}if(playMode)cv::waitKey(1);elsecv::waitKey(0);char q = (char)waitKey(1);if( q == 27 ){printf("\nStopped by user request\n");break;} if(stillImage)break;} // main whileif(!stillImage)video.release();return 0;}

6.3 效果展示與分析


??上圖展示的是LSWMS論文中的結果。由于作者提供的代碼需要在Ubuntu下編譯,我沒有去做這個工作,如果你感興趣你可以去運行在本文的3張測試圖片上面的效果。

7、CannyLines直線檢測算法

CannyLines-項目主頁-論文鏈接 -代碼鏈接

7.1 CannyLines算法簡介

??CannyLines算法在該論文中被提出。本文提出了一種魯棒的線段檢測算法,有效地檢測出輸入圖像中的線段。首先,提出了一種無參數canny算子cannypf,通過自適應地設置傳統canny算子的低閾值和高閾值,從輸入圖像中穩健地提取邊緣映射。其次,提出了直接從邊緣地圖中提取共線點簇的有效像素連接和分割技術,并基于最小二乘法對初始線段進行擬合。第三,通過有效的擴展和合并,生成更長、更完整的線段。最后,根據helmholtz原理對檢測到的所有線段進行了驗證,該原理同時考慮了梯度方向和幅度信息。在一組有代表性的圖像上的實驗結果表明,與常用的兩種線段檢測器lsd和edline相比,我們提出的cannyline線段檢測器能夠提取出更有意義的線段,特別是在人造場景中。

7.2 CannyLines算法代碼實戰

這里僅僅展示了主函數,完整的代碼請從網盤鏈接進行下載。

#include <stdio.h> #include <fstream> #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/types_c.h>#include "CannyLine.h"using namespace cv; using namespace std;void main() { string fileCur = "test3.jpg";cv::Mat img = imread( fileCur, 0 );cv::Mat img1 = imread(fileCur, 1);CannyLine detector;std::vector<std::vector<float> > lines;detector.cannyLine( img, lines );// showcv::Mat imgShow( img.rows, img.cols, CV_8UC3, cv::Scalar( 255, 255, 255 ) );for ( int m=0; m<lines.size(); ++m ){cv::line( img1, cv::Point( lines[m][0], lines[m][1] ), cv::Point( lines[m][2], lines[m][3] ), cv::Scalar(0,255,0), 1, LINE_AA );}imshow("",img1);imwrite("test3_r.jpg", img1);cv::waitKey(0); }

7.3 效果展示與分析


??上圖展示了CannyLines直線檢測算法的檢測效果。通過觀察上圖我們可以發現該算法能夠獲得更加準確的檢測結果,具有更少的誤檢。該算法主要是提高了邊緣檢測的效果,具體的效果如下所示:

8、MCMLSD直線檢測算法

MCMLSD-論文鏈接-代碼鏈接

8.1 MCMLSD算法簡介

??MCMLSD算法出自于該論文。論文中提出了一個融合兩者優點的概率算法。在第一階段,使用全局概率hough方法。在第二階段,在圖像域中分析每個檢測到的行,以定位在霍夫圖中生成峰值的線段。通過將搜索限制在一條直線上,線段的分布線上的點序列可以被建模為馬爾可夫鏈和概率最優標簽使用標準動態規劃算法精確計算,在線性時間內。馬爾可夫假設同時也產生了一種直觀的排名方法,它使用估計期望值的邊際后驗概率線段上正確標記的點的數目。評估由此產生的馬爾可夫鏈邊緣線段檢測器(mcmlsd)我們開發并應用了一種新的定量方法控制分段不足和分段過量的評估方法。在YorkUrbanDB數據集的評價結果表明,所提出的MCMLSD方法優于以相當大的優勢達到最先進水平。

8.2 MCMLSD算法代碼實戰

這里僅僅展示了主函數,完整的代碼請從網盤鏈接進行下載。

clear clc close alladdpath(genpath('code/')); addpath('Img2/'); img = imread(['Img2', filesep, 'test3.jpg']); % img = imresize(img, [300, 400]); % img = imresize(img, [round(size(img,1)/4), round(size(img,2)/4)]);%compute the kernel for the image size %you only need to compute the kernal once for one an image size [kernels, kernels_flip, kernel_params] =kernelInitialization(img); ticId = tic; %the lines variable contains the detected line segmentations it arranged as %[x1 y1 x2 y2 probability] %The fullLines are the detected lines. It is arranged as [rho theta probability] [lines, fullLines] =lineSegmentation_HighRes(img,kernels, kernels_flip, kernel_params); display('Total time'); toc(ticId) fig = figure; imshow(img); hold all%Order lines by probabilitylines = sortrows(lines, -5);ttlLines = size(lines,1);for i = 1:ttlLines%plot the top 90 linesline([lines(i,1) lines(i,3)], [lines(i,2) lines(i,4)],'Color', rand(1,3), 'LineWidth', 3);end

8.3 效果展示與分析


??上圖展示了MCMLSD算法的檢測效果。通過上面的觀察,我們可以發現該算法取得了很好的檢測效果,但是美中不足的是該算法的運行速度比較慢,可能也和matlab代碼有關吧。

9、LSM直線檢測算法

LSM-項目主頁-論文鏈接-代碼鏈接

9.1 LSM算法簡介

??LSM算法不僅僅是一個直線檢測算法,同時也是一個直線合并算法。論文中提出了一種合并這些斷開的線段的算法,以恢復原始的感知準確的線段。該算法根據角度和空間接近度對線段進行分組。然后將每組中滿足新的自適應合并準則的線段對依次合并成一條線段。重復此過程,直到不再合并行段。我們還提出了一種定量比較線段檢測算法的方法。在york-urban數據集上的結果表明,與最新的線段檢測算法相比,我們的合并線段更接近人類標記的地面真線段。

9.2 LSM算法代碼實戰

這里僅僅展示了主函數,完整的代碼請從網盤鏈接進行下載。

% 清除空間變量 clear; close all; clc; addpath(genpath(pwd));%****THRESHOLD AND PARAMETER SETTING***% % 設置一些參數和閾值 xi_s=.05; % spatial proximity threshold tau_theta=pi/24; % angular proximity threshold% 設置保存結果的名字 img_name = 'img1\test3.jpg'; name = split(img_name, '\'); save_name1 = ['result1\ori_', char(name(2))]; save_name2 = ['result1\opt_', char(name(2))]; save_name3 = ['result1\merge_', char(name(2))]; % 讀取輸入圖片 I=imread(img_name); % I=rgb2gray(I); I=double(I); D=lsd(I/max(I(:))*255); [L]=mergeLines(D,tau_theta,xi_s); display(strcat(int2str(size(L,1)),' merged line segments')); imgD=double(display_image( D,I)); imgL=double(display_image( L,I));imwrite([imgD],save_name1); imwrite([imgL],save_name2); imwrite([imgL],save_name3);imshow([imgD imgL]);

9.3 效果展示與分析


??上圖展示了直線檢測算法LSM的檢測效果。左邊一列表示的是LSD的檢測結果,右邊一列表示的是LSM算法的優化效果,圖中不同的顏色表示不同的直線。通過上面的觀察,我們可以發現LSM可以將一些間斷的直線合并成一條更長的直線,這在現實場景中具有很大的用處,但是我們也會發現LSM算法會錯誤的將一些直線進行合并,會造成一些誤差。

10、總結

??本文對比較經典的直線檢測算法進行了總結和分析。對于直線檢測這個任務而言,它在現實場景中具有很多的應用,對于一個具體的場景,你可以根據自己的需要從本文中選擇出一個合適的直線檢測算法進行應用,如果你的場景比較簡單,HoughP_line算法可能就可以滿足你的要求;如果你同時對速度和精度有要求,可以選擇使用EDlines等;如果你需要獲得盡可能長的直線,那么建議你使用LSM直線檢測算法。總而言之,最適合你的場景的算法才是最好的算法。

參考資料

[1] LSD
[2] EDLines
[3] LSWMS
[4] CannyLines
[5] MCMLSD
[6] LSM

注意事項

[1] 該博客是本人原創博客,如果您對該博客感興趣,想要轉載該博客,請與我聯系(qq郵箱:1575262785@qq.com),我會在第一時間回復大家,謝謝大家的關注.
[2] 由于個人能力有限,該博客可能存在很多的問題,希望大家能夠提出改進意見。
[3] 如果您在閱讀本博客時遇到不理解的地方,希望您可以聯系我,我會及時的回復您,和您交流想法和意見,謝謝。
[4] 本文測試的圖片可以通過該鏈接進行下載。網盤鏈接- 提取碼:xh2i。
[5] 本人業余時間承接各種本科畢設設計和各種小項目,包括圖像處理(數據挖掘、機器學習、深度學習等)、matlab仿真、python算法及仿真等,有需要的請加QQ:1575262785詳聊,備注“項目”!!!

總結

以上是生活随笔為你收集整理的直线检测算法汇总的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。