OpenCV学习笔记(十三):霍夫变换:HoughLines(),HoughLinesP(),HoughCircles( )
OpenCV學習筆記(十三):霍夫變換:HoughLines(),HoughLinesP(),HoughCircles( )
1、霍夫線變換HoughLines()
OpenCV支持三種不同的霍夫線變換,它們分別是:
 1)標準霍夫變換(Standard Hough Transform,SHT)
 2)多尺度霍夫變換(Multi-Scale Hough Transform,MSHT)
 3)累計概率霍夫變換(Progressive Probabilistic Hough Transform ,PPHT)。
 PPHT算法是標準霍夫變換(SHT)算法的一個改進,它在一定的范圍內進行霍夫變換,計算單獨線段的方向以及范圍,從而減少計算量,縮短計算時間。累計概率霍夫變換執行效率很高,所有相比于HoughLines函數,我們更傾向于使用HoughLinesP函數。
 原理:
 這就是霍夫線變換要做的. 它追蹤圖像中每個點對應曲線間的交點. 如果交于一點的曲線的數量超過了閾值, 那么可以認為這個交點所代表的參數表示的直線,在原圖像中為一條直線。
1)示例代碼:
#include <opencv2/opencv.hpp>using namespace cv; using namespace std;//原圖,邊緣圖,灰度圖 Mat g_srcImage,g_midImage, g_srcGrayImage; int g_HoughLinesThreshold=250;//TrackBar位置參數int main() {// 1、載入原圖g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/7.2 Hough 霍夫變換/2.jpg");if( !g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; }//顯示原始圖imshow("【原始圖】", g_srcImage);// 2、進行邊緣檢測和轉化為灰度圖Canny(g_srcImage, g_midImage, 50, 150, 3);//進行一此canny邊緣檢測imshow("【邊緣檢測后的圖】", g_midImage);// 3、創建trackbarnamedWindow( "HoughLines", WINDOW_AUTOSIZE );createTrackbar( "參數值:", "HoughLines", &g_HoughLinesThreshold,300, on_HoughLines);// 4、調用回調函數on_HoughLines(0, 0);//輪詢獲取按鍵信息,若按下Q,程序退出while((char(waitKey(1)) != 'q')) {}waitKey(0);return 0; }2)霍夫線變換回調函數
void on_HoughLines(int, void*) {// 0、生成灰度圖cvtColor(g_midImage,g_srcGrayImage, COLOR_GRAY2BGR);//轉化邊緣檢測后的圖為灰度圖// 1、定義一個矢量結構lines用于存放得到的線段矢量集合// 2、進行霍夫線變換// 3、依次在圖中繪制出每條線段vector<Vec2f> lines;HoughLines(g_midImage, lines, 1, CV_PI/180, g_HoughLinesThreshold, 0, 0 );//double類型的rho,以像素為單位的距離精度:是離坐標原點((0,0)(也就是圖像的左上角)的距離//double類型的theta,以弧度為單位的角度精度:是弧度線條旋轉角度(0~垂直線,π/2~水平線)// 直線公式; r=x*cos(theta)+y*sin(theta)for( size_t i = 0; i < lines.size(); i++ ){float rho = lines[i][0], theta = lines[i][1];Point pt1, pt2; //起點和終點double a = cos(theta), b = sin(theta);// 公垂線焦點double x0 = a*rho, y0 = b*rho;// 直線經過 第一點坐標值pt1.x = cvRound(x0 + 1000*(-b)); // 取整pt1.y = cvRound(y0 + 1000*(a)); // 取整// 直線經過 第二點坐標值pt2.x = cvRound(x0 - 1000*(-b));pt2.y = cvRound(y0 - 1000*(a));// 繪制連接兩個點的線段line(g_srcGrayImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA); // 繪制直線(抗鋸齒線)}//顯示效果圖imshow( "HoughLines", g_srcGrayImage ); }3)結果:
 
 
2、累計概率霍夫線變換HoughLinesP()
此函數在HoughLines的基礎上末尾加了一個代表Probabilistic(概率)的P,表明它可以采用累計概率霍夫變換(PPHT)來找出二值圖像中的直線。
C++: void HoughLinesP( InputArray image, // 源圖像 OutputArray lines, // 存儲了檢測到的線條的輸出矢量,每一條線由具有四個元素的矢量(x_1,y_1, x_2, y_2) // 表示,其中,(x_1, y_1)和(x_2, y_2) 是是每個檢測到的線段的結束點 double rho, // 以像素為單位的距離精度。另一種形容方式是直線搜索時的進步尺寸的單位半徑。 double theta, // 以弧度為單位的角度精度。另一種形容方式是直線搜索時的進步尺寸的單位角度。 int threshold, // 累加平面的閾值參數,即識別某部分為圖中的一條直線時它在累加平面中必須達到的值。// 大于閾值threshold的線段才可以被檢測通過并返回到結果中。 double minLineLength=0, // 表示最低線段的長度,比這個設定參數短的線段就不能被顯現出來 double maxLineGap=0 // 允許將同一行點與點之間連接起來的最大的距離 )1)示例代碼:
#include <opencv2/opencv.hpp>using namespace cv; using namespace std;//原圖,邊緣圖,灰度圖 Mat g_srcImage,g_midImage, g_srcGrayImage; int g_HoughLinesThreshold=250;//TrackBar位置參數int main() {// 1、載入原圖g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/111.jpg");if( !g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; }//顯示原始圖imshow("【原始圖】", g_srcImage);// 2、進行邊緣檢測和轉化為灰度圖Canny(g_srcImage, g_midImage, 50, 200, 3);//進行一此canny邊緣檢測imshow("【邊緣檢測后的圖】", g_midImage);// 3、創建trackbarnamedWindow( "HoughLines", WINDOW_AUTOSIZE );createTrackbar( "累加閾值:", "HoughLines", &g_HoughLinesThreshold,300, on_HoughLines);createTrackbar( "最小直線距離:", "HoughLines", &g_minLineLength,200, on_HoughLines);// 4、調用回調函數on_HoughLines(0, 0);//輪詢獲取按鍵信息,若按下Q,程序退出while((char(waitKey(1)) != 'q')) {}waitKey(0);return 0; }2)霍夫線變換回調函數
void on_HoughLines(int, void*) {// 0、生成灰度圖cvtColor(g_midImage,g_srcGrayImage, COLOR_GRAY2BGR);//轉化邊緣檢測后的圖為灰度圖// 1、定義一個矢量結構lines用于存放得到的線段矢量集合// 2、進行霍夫線變換// 3、依次在圖中繪制出每條線段vector<Vec4i> lines;HoughLinesP(g_midImage, lines, 1, CV_PI/180, g_HoughLinesThreshold, g_minLineLength, 10 );for( size_t i = 0; i < lines.size(); i++ ){Vec4i l = lines[i];line( g_srcGrayImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186,88,255), 1, LINE_AA);}//顯示效果圖imshow( "HoughLines", g_srcGrayImage ); }3)結果:
 
 
3、霍夫圓變換HoughCircles()
霍夫圓變換的基本原理和上面講的霍夫線變化大體上是很類似的,只是點對應的二維極徑極角空間被三維的圓心點x, y還有半徑r空間取代。說“大體上類似”的原因是,如果完全用相同的方法的話,累加平面會被三維的累加容器所代替:在這三維中,一維是x,一維是y,另外一維是圓的半徑r。這就意味著需要大量的內存而且執行效率會很低,速度會很慢。
 我們一般通過一個叫做“霍夫梯度法”的方法來解決圓變換的問題:
霍夫梯度法:
 1)首先對圖像應用邊緣檢測,比如用canny邊緣檢測。
 2)然后,對邊緣圖像中的每一個非零點,考慮其局部梯度,即用Sobel()函數計算x和y方向的Sobel一階導數得到梯度。
 3)利用得到的梯度,由斜率指定的直線上的每一個點都在累加器中被累加,這里的斜率是從一個指定的最小值到指定的最大值的距離。
 4)同時,標記邊緣圖像中每一個非0像素的位置。
 5)然后從二維累加器中這些點中選擇候選的中心,這些中心都大于給定閾值并且大于其所有近鄰。這些候選的中心按照累加值降序排列,以便于最支持像素的中心首先出現。
 6)接下來對每一個中心,考慮所有的非0像素。
 7)這些像素按照其與中心的距離排序。從到最大半徑的最小距離算起,選擇非0像素最支持的一條半徑。8.如果一個中心收到邊緣圖像非0像素最充分的支持,并且到前期被選擇的中心有足夠的距離,那么它就會被保留下來。
霍夫梯度法的缺點:
 1)在霍夫梯度法中,我們使用Sobel導數來計算局部梯度,那么隨之而來的假設是,其可以視作等同于一條局部切線,并這個不是一個數值穩定的做法。在大多數情況下,這樣做會得到正確的結果,但或許會在輸出中產生一些噪聲。
 2)在邊緣圖像中的整個非0像素集被看做每個中心的候選部分。因此,如果把累加器的閾值設置偏低,算法將要消耗比較長的時間。第三,因為每一個中心只選擇一個圓,如果有同心圓,就只能選擇其中的一個。
 3)因為中心是按照其關聯的累加器值的升序排列的,并且如果新的中心過于接近之前已經接受的中心的話,就不會被保留下來。且當有許多同心圓或者是近似的同心圓時,霍夫梯度法的傾向是保留最大的一個圓??梢哉f這是一種比較極端的做法,因為在這里默認Sobel導數會產生噪聲,若是對于無窮分辨率的平滑圖像而言的話,這才是必須的。
結果:
 
 
總結
以上是生活随笔為你收集整理的OpenCV学习笔记(十三):霍夫变换:HoughLines(),HoughLinesP(),HoughCircles( )的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: pytorch自定义数据集和数据加载器
- 下一篇: tf.nn.embedding_look
