OpenCV中的快速直線檢測

2021-01-16 OpenCV團隊

cv::ximgproc::FastLineDetectors是opencv-contrib中用於檢測直線的模塊,該方法能在較短時間內獲得精度較高的直線檢測結果,且不需要調節參數。該函數是LineSegmentDetector因版權問題從OpenCV中移除後最易用的直線檢測小能手,沒有之一。本文介紹該功能的使用方法其輸出結果剖析。


本文範例運行環境


FastLineDetectors運行必要條件

FastLineDetectors屬於opencv-contrib中的模塊,需要安裝opencv-contrib-python。在python的opencv相關的安裝包中,opencv-python 包含主要模塊,opencv-contrib-python 包含主要模塊以及一些擴展模塊。但這兩個模塊並不兼容,如果已經安裝過opencv-python,需要先卸載,再安裝opencv-contrib-python。

1 pip uninstall opencv-python2 pip install opencv-contrib-python

在OpenCV 4.1.0之前的版本中,有一個LineSegmentDetector模塊,功能強大,檢測直線非常便捷,但該函數因為版權問題已在4.1.X版本上已移除,故此處不討論此方案。LineSegmentDetector相關的問題可以參考:

any-implementation-of-linesegmentdetector-for-python

https://answers.opencv.org/question/215800/any-implementation-of-linesegmentdetector-for-python/

LineSegmentDetector needs to be removed for license

https://github.com/WPIRoboticsProjects/GRIP/issues/961


FastLineDetectors應用示例
 1 import cv2  2 import numpy as np  3 img = cv2.imread('sudo.png')  4 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  5 #Create default Fast Line Detector (FSD)  6 fld = cv2.ximgproc.createFastLineDetector()  7 #Detect lines in the image  8 lines = fld.detect(gray)  9 #Draw detected lines in the image 10 drawn_img = fld.drawSegments(gray,lines) 11 cv2.imshow("FLD", drawn_img) 12 cv2.waitKey(0)


如以上代碼所示:

第1~2行導入python包。

第3行讀入測試圖片,本文中測試圖片與代碼文件在同一路徑,故只有圖片名稱。更改測試圖像時,更改該行代碼中的圖像名稱即可。

第4行將測試圖片轉換為灰度圖。

第6行創建FastLineDetectors檢測實例,這裡使用的是默認參數,其參數順序及意義如下:

retval = cv.ximgproc.createFastLineDetector( [, _length_threshold[, _distance_threshold[, _canny_th1[, _canny_th2[, _canny_aperture_size[, _do_merge]]]]]] ) Parameters _length_threshold 10 - Segment shorter than this will be discarded _distance_threshold 1.41421356 - A point placed from a hypothesis line segment farther than this will be regarded as an outlier _canny_th1 50 - First threshold for hysteresis procedure in Canny() _canny_th2 50 - Second threshold for hysteresis procedure in Canny() _canny_aperture_size 3 - Aperturesize for the sobel operator in Canny() _do_merge false - If true, incremental merging of segments will be perfomred


第8行使用FastLineDetectors檢測測試圖像中的直線。

第10行根據檢測結果繪製直線。

第11~12行用於顯示檢測結果。


如下動圖所示,我選取了兩張圖,均使用默認參數來檢測,圖中的直線基本被檢出,說明該函數的通用性還是比較強的。

以其中停車場的圖片為例,圖中有許多小短線,此時可以更改createFastLineDetector的默認參數,設置直線的長度來對檢測直線進行過濾。


FastLineDetectors檢測結果詳解

通常我們檢測直線並不只是為了將其繪製出來而已,我們可能需要知道該直線與其他直線的關係。這時我們就需要能取用檢測得到直線兩個端點的坐標。


接下來開始解析FastLineDetectors的檢測結果,學習如何取用檢測直線的端點坐標。


在"FastLineDetectors應用示例"小節中,在完成直線檢測代碼之後,添加如下代碼,先觀察一下FastLineDetectors檢測結果的各種屬性:

print("數據類型",type(lines)) #列印數組數據類型print("數組元素數據類型:",lines.dtype) #列印數組元素數據類型 print("數組元素總數:",lines.size) #列印數組尺寸,即數組元素總數 print("數組形狀:",lines.shape) #列印數組形狀 print("數組的維度數目",lines.ndim) #列印數組的維度數目


運行後,可以看到FastLineDetectors的檢測結果的各種輸入為:

數據類型 <class 'numpy.ndarray'> 數組元素數據類型: float32 數組元素總數: 724 數組形狀: (181, 1, 4) 數組的維度數目 3


然後我們到github查看一下drawSegments的實現函數,如下所示:

 1 void FastLineDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines, bool draw_arrow) 2 { 3   CV_INSTRUMENT_REGION(); 4 5   CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3)); 6  7    Mat gray; 8    if (_image.channels() == 1) 9    {10        gray = _image.getMatRef();11   }12    else if (_image.channels() == 3)13    {14       cvtColor(_image, gray, COLOR_BGR2GRAY);15    }16 17   // Create a 3 channel image in order to draw colored lines18    std::vector<Mat> planes;19    planes.push_back(gray);20    planes.push_back(gray);21    planes.push_back(gray);22 23    merge(planes, _image);24 25    double gap = 10.0;26    double arrow_angle = 30.0;27 28    Mat _lines;29    _lines = lines.getMat();30    int N = _lines.checkVector(4);31    // Draw segments32    for(int i = 0; i < N; ++i)33    {34        const Vec4f& v = _lines.at<Vec4f>(i);35        Point2f b(v[0], v[1]);36        Point2f e(v[2], v[3]);37        line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1);38        if(draw_arrow)39        {40            SEGMENT seg;41            seg.x1 = b.x;42            seg.y1 = b.y;43            seg.x2 = e.x;44            seg.y2 = e.y;45            getAngle(seg);46            double ang = (double)seg.angle;47            Point2i p1;48            p1.x = cvRound(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang));49            p1.y = cvRound(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang));50            pointInboardTest(_image.getMatRef(), p1);51            line(_image.getMatRef(), Point(cvRound(seg.x2), cvRound(seg.y2)), p1, Scalar(0,0,255), 1);52        }53    }54}

上述代碼中:

第28~37行用於繪製檢測到的直線,其中lines[i][0]~lines[i][3]中存儲的四個元素分別為第i條直線端點1的X,Y坐標和端點2的X,Y坐標。

第38行中的變量[draw_arrow],是函數drawSegments的參數之一,默認值為false,用於設定是否在檢測直線的其中一個端點處繪製箭頭。


根據以上信息,我們推測在python的FastLineDetectors檢測結果中,lines[i][0][0]~lines[i][0][3]分別對應第 i 條直線端點1的X,Y坐標和端點2的X,Y坐標。


為了證明上述推測,我們選取下圖作為測試圖片,修改一下相關代碼,實現如下功能:找出檢測結果中最長的一根直線,繪製該直線及其兩個端點,並且在該直線一個端點處繪製箭頭。


 1 import cv2 2 import numpy as np 3 from scipy.spatial import distance as dist 4  5 img = cv2.imread('sDQLM.png') 6 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 7  8 #Create default Fast Line Detector (FSD) 9 fld = cv2.ximgproc.createFastLineDetector()10 11 #Detect lines in the image12 lines = fld.detect(gray)13 14 dMax = 015 bx_Max = 016 by_Max = 017 ex_Max = 018 ey_Max = 019 20 for L in lines:21 22    bx,by,ex,ey = L[0]23   24    # compute the Euclidean distance between the two points,25    D = dist.euclidean((bx, by), (ex, ey))26    27    if D > dMax:28        dMax = D29        bx_Max = bx30        by_Max = by31        ex_Max = ex32        ey_Max = ey33        34 lineMax = np.array([[[bx_Max, by_Max, ex_Max,ey_Max]]])35 #Draw detected lines in the image36 drawn_img = fld.drawSegments(gray,lineMax,True)37 cv2.circle(drawn_img, (bx_Max, by_Max), 1, (255,0,0), 2)#line begin38 cv2.circle(drawn_img, (ex_Max, ey_Max), 1, (0,255,0), 2)#line end39 40 cv2.imshow("FLD", drawn_img)41 cv2.waitKey(0)

上述代碼中:

第25行用於計算直線的長度,便於我們找出檢測結果中最長的直線。

第34行用最長的直線的兩個端點重新構建一個np.array。

第36行繪製最長的直線,並且第三個參數設置為TRUE,即在直線其中一端繪製箭頭。

第37~38行,在圖中繪製兩個端點。

運行結果如下:


FastLineDetectors可以方便的檢測圖中的直線,並且可以簡單的取用直線兩個端點的坐標,接下來就可以用它實現更多有趣的功能。


本文到此結束,感謝閱讀。

原文連結:https://livezingy.com/fastlinedetectors-opencv-contrib/




Webinar 1: OpenCV Overview

Webinar 2: OpenCV DNN在ARM上的加速

Webinar 3: OpenCV深度學習應用與原理分析

Webinar 4: 谷歌編程夏令營2020 OpenCV文本識別項目開發



OpenCV中國團隊官方推薦和認證OpenCV在線課程



加入我們OpenCV志願者

(請註明「OpenCV志願者」)



OpenCV中國團隊於2019年9月由深圳市人工智慧與機器人研究院支持成立,非營利目的,致力於OpenCV的開發、維護和推廣工作。

長按下方QR碼關注我們獲取最新動態

相關焦點

  • OpenCV 之 霍夫變換
    它常用來檢測 直線和曲線 (圓形),識別圖像中的幾何形狀,甚至可用來分割重疊或有部分遮擋的物體。 1  平面坐標和極坐標1)  平面坐標的點 <=> 極坐標(平面化)的曲線    所謂極坐標平面化是指, 將 ρ-θ 的關係像 x-y 那樣在平面內展開。
  • OpenCV(四)邊緣檢測
    然後Gx=sobel*A,Gy=sobely*A,最終得到的結果就是:Sobel相比於其他算子的優勢在於比較簡單和快速,只需要三次簡單運算就可以得到(Sobel需要灰度圖,所以更準確的說想要使用Sobel還需要灰度圖轉換的步驟)。同時Sobel也可以只檢測垂直方向或者只檢測水平方向。
  • 如何快速簡單的安裝opencv-python
    這樣就會從清華鏡像安裝opencv-contrib-python庫。目前opencv最新版本為4.1.1 ----2019-8-28在opencv-contrib-python 版本中含有額外模塊( Extra modules ),而 opencv-python 版本中只含有基礎模塊。
  • 基於TensorFlow 、OpenCV 和 Docker 的實時視頻目標檢測
    翻譯 | 於志鵬  徐普     校對 | 陶玉龍     整理 | 孔令雙在本文中,我將介紹如何在 Docker 容器中使用 Tensorflow Object-detection API 來執行實時(網絡攝像頭)和視頻的目標檢測。
  • OpenCV特徵點檢測——ORB特徵
    ORB的描述在下面文章中:Ethan Rublee and Vincent Rabaud and Kurt Konolige and Gary Bradski, ORB: an efcient alternative to SIFT or SURF, ICCV 2011沒有加上連結是因為作者確實還沒有放出論文,不過OpenCV2.3RC中已經有了實現,WillowGarage
  • 使用OpenCV和Python構建自己的車輛檢測模型
    utm_source=blog&utm_medium=vehicle-detection-opencv-python)目錄視頻中運動目標檢測的思想視頻中目標檢測的真實世界用例視頻目標檢測的基本概念 幀差分 圖像閾值 檢測輪廓 圖像膨脹利用OpenCV構建車輛檢測系統視頻中運動目標檢測的思想目標檢測是計算機視覺中一個引人入勝的領域。
  • 基於opencv 的圖像處理入門教程
    邊緣檢測邊緣檢測主要是通過 Canny() 方法,它實現了 Canny 邊緣檢測器,這也是目前最優的邊緣檢測器。本例中將採用 HoughCircles() 方法來應用蒙版,這個方法可以檢測圖片中的圓,然後對這些圓應用蒙版。
  • 世界上最好的語言PHP:OpenCV與計算機視覺已在我掌控之下
    在過去的半年中,作者利用空閒時間探索 PHP 與 OpenCV 的結合,並藉此調用與訓練優秀的機器學習模型。本文從實踐的角度介紹了如何使用 PHP 與 OpenCV 構建人臉檢測、人臉識別、超解析度與目標檢測等系統,因此 PHP 的各位擁躉們,可以盡情使用 OpenCV 探索計算機視覺了。本文首發於公眾號機器之心(ID:almosthuman2014),部分代碼格式有誤可參閱原文章。
  • 基於OpenCv 和 Python 的手指識別及追蹤
    翻譯 | 餘杭 Lamaric 校對 | 吳曉曼 審核 | 餘杭詳細代碼參考:https://github.com/amarlearning/opencv手指追蹤是許多計算機視覺應用的重要特徵。在該應用中,使用基於直方圖的方法將手與背景幀分離。
  • 基於OpenCV來實現對圖像中目標對象檢測識別 以土地為例
    https://docs.opencv.org/master/d9/df8/tutorial_root.html   https://docs.opencv.org/   https://www.zhihu.com/question/26881367我們今天的內容主要是想基於OpenCV來實現對圖像中我們關注的一些目標對象進行檢測識別或者說是對其存在的區域位置進行挖掘,在開始這篇文章之前,我曾經看到了有人基於
  • Python中的簡單人臉檢測(建議收藏)
    如何使用OpenCV庫檢測圖像中的人臉在本文中,將展示如何使用Python構建簡單的面部檢測器。建立一個可以檢測人臉的程序是一個很好的項目,可以開始使用計算機視覺。從名稱可以理解,我們將編寫一個程序來檢測圖像中的面部。當我說「程序」時,您可以將其理解為教機器做什麼。我喜歡使用教學而不是編程,因為這實際上是我們正在做的事情。
  • 霍夫變換——形狀特徵提取算法:車道線檢測
    霍夫變換是用來辨別找出物件中的特徵,例如:線條。他的算法流程大致如下,給定一個物件、要辨別的形狀的種類,算法會在參數空間中執行投票來決定物體的形狀,而這是由累加空間(accumulator space)裡的局部最大值來決定。理論上,霍夫變換就是對於原圖上的每一個直線都在參數空間畫一條線,最終找出參數空間變換線比較密集的地方在對應回到xy 空間坐標系。
  • 基於霍夫變換的直線檢測
    用於檢測給定的形狀,例如直線、圓形、橢圓形。(a)笛卡爾坐標系 (b)霍夫空間笛卡爾坐標系中的一點對應霍夫空間的一條直線,笛卡爾坐標系中的一條直線對應霍夫空間的一點。平面中直線接近垂直時通常會根據直線的特性進一步判斷,從而將直線變為線段。4 霍夫變換的推廣目前為止我們討論的是霍夫變換用於直線檢測上,但霍夫變換可推廣到圓[Kimme75]和其它簡單形狀的檢測,感興趣的讀者可進一步閱讀相關文獻。
  • 談談OpenCV中的四邊形
    另一類就是使用機器學習類算法檢測定位四個角點。這篇文章我們主要來看看使用經典圖像處理算法來解決這個問題。1.最小包絡正矩形Rect boundingRect(InputArray points)函數會給我們傳入的邊界點計算得到一個最小的包絡正矩形,並輸出這個正矩形的頂點。
  • 物體檢測中的Objectness是什麼?
    本文轉自AI公園作者:Nathan Zhao編譯:ronghuaiyang在本文中,我們將討論目標檢測模型和Objectness的基礎知識。什麼是物體檢測模型?物體檢測模型本質上,正如其名稱所示,檢測物體。這意味著給定一個圖像,它可以告訴你物體在哪裡,以及這個物體是什麼。例如,在上面的圖像中,我們有許多物體,並且使用物體檢測模型,我們已經檢測出不同的物體在圖像中的位置。
  • 「python opencv視覺零基礎實戰」七邏輯運算應用
    一、學習目標了解opencv中圖像的邏輯運算了解opencv中邏輯運算的應用如有錯誤歡迎指出~目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python
  • 「python opencv視覺零到實戰」八、圖片選區操作
    一、學習目標了解什麼是ROI了解floodFill的使用方法如有錯誤歡迎指出~目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python opencv視覺入門到實戰
  • Python中如何利用Opencv打開視頻或圖像並用PyQt控制項顯示
    一、python中opencv打開圖像方法:import cv2filename='dog.jpg'img=cv2.imread(filename)cv2.imshow('Main Window',img)cv2.waitKey() #任意鍵退出cv2.destroyAllWindows()二、python中用opencv打開視頻頭的方法:
  • 「python opencv視覺零基礎」十四、直方圖反向投影
    前文提醒:博主正在參加博客之星評比,成功入選Top200,現在暫居第九歡迎各位點擊了解更多幫我投票,非常感謝~目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python
  • opencv-python獲取圖像:面向對象與面向過程
    這裡需要注意以下,opencv讀取圖片默認通道為BGR的格式,當在其他UI用戶界面顯示圖像時注意轉換一下通道順序,例如BGR轉換成RGB:Image1=cv2.cvtColor(image, cv2.COLOR_BGR2RGB)下面讀取一張圖片並顯示