千萬注意:使用opencv自帶的霍夫API
HoughLinesP():此函數輸入的是一個二進制且八位的圖像,例如:你不能用cvtcolor()變換之后直接輸入。
HoughCircles():此函數輸入的是一個灰度且八位的圖像,例如:你不能經過threshold()、findcontours()等之后的圖像進行輸入。
我現在還不知道經過二值化的圖像怎么轉化為灰度圖。。。。會了再補充。
---霍夫直線變換---
源程序沒有分析,只是分析了基本的原理。。。等以后用到之后再進行分析
首先回顧一下坐標系的概念--->>>
1.直角坐標系(直線)<--->極坐標系(點),極坐標系(直線)<--->直角坐標系(點)。相互對應的關系
2.推導的公式很簡單,看一下就懂了。
3.對於第三個公式,我們給定一個(x0,y0),就是圖像的一個像素點(這個圖是經過濾波、灰度、梯度等處理的),那么這個點在極坐標就可以畫出一條直線。因為在極坐標看的不明顯,把這個函數畫在直角坐標系顯示(圖一),就類似三角函數的圖像。現在我們再給定點(x1,y1)、(x2,y2)。。。進行同樣的方法畫圖(圖二),這個點在直角坐標系就是一條直線,那么多重合的點,就說明很多的像素點在這個直線上,我們設定一個閾值L,當點的重合率大於這個閾值就認定是直線。
4.有點饒人,直角和極坐標相互的轉化實現。
圖一
圖二
上面的原理是可以運行的:
1.效率太低了,試想一下圖像邊緣非常的多,如果每一個像素點都進行計算的話,那太費時費事了。
2.線段的端點沒辦法檢測。
3.對於相近的線段沒辦法區分。
HoughLinesP函數就是利用概率霍夫變換來檢測直線的。它的一般步驟為:
1、隨機抽取圖像中的一個特征點,即邊緣點,如果該點已經被標定為是某一條直線上的點,則繼續在剩下的邊緣點中隨機抽取一個邊緣點,直到所有邊緣點都抽取完了為止;
2、對該點進行霍夫變換,並進行累加和計算;
3、選取在霍夫空間內值最大的點,如果該點大於閾值的,則進行步驟4,否則回到步驟1;
4、根據霍夫變換得到的最大值,從該點出發,沿着直線的方向位移,從而找到直線的兩個端點;
5、計算直線的長度,如果大於某個閾值,則被認為是好的直線輸出,回到步驟1。
opencv霍夫直線變換:
houghlines()--->>>
其返回的是(ρ,Θ),ρ代表距離(0,0)點到直線的歐幾里得距離,也就是直線距離。Θ代表的是(0,0)點垂直直線然后與Y軸的夾角。
houghlinesP()--->>>
返回的是直線兩個點:(x0,y0)(x1,y1)
剛開始我看不起houghlines函數,感覺效率低,后來基本上都是用houghlinesP的,但是這次實現文本的轉正就用到了,這兩個用途不一樣吧!
---霍夫圓變換---
圓變換的想法和直線變化是一樣的,就是把直角坐標系中的圓畫在極坐標系中,然后求交點
第一階段:檢測圓心
1.1、對輸入圖像邊緣檢測;
1.2、計算圖形的梯度,並確定圓周線,其中圓周的梯度就是它的法線;
1.3、在二維霍夫空間內,繪出所有圖形的梯度直線,某坐標點上累加和的值越大,說明在該點上直線相交的次數越多,也就是越有可能是圓心;
1.4、在霍夫空間的4鄰域內進行非最大值抑制;
1.5、設定一個閾值,霍夫空間內累加和大於該閾值的點就對應於圓心。
第二階段:檢測圓半徑
2.1、計算某一個圓心到所有圓周線的距離,這些距離中就有該圓心所對應的圓的半徑的值,這些半徑值當然是相等的,並且這些圓半徑的數量要遠遠大於其他距離值相等的數量;
2.2、設定兩個閾值,定義為最大半徑和最小半徑,保留距離在這兩個半徑之間的值,這意味着我們檢測的圓不能太大,也不能太小;
2.3、對保留下來的距離進行排序;
2.4、找到距離相同的那些值,並計算相同值的數量;
2.5、設定一個閾值,只有相同值的數量大於該閾值,才認為該值是該圓心對應的圓半徑;
2.6、對每一個圓心,完成上面的2.1~2.5步驟,得到所有的圓半徑。
opencv實例:
1 #include<iostream> 2 #include <opencv2/opencv.hpp> 3 #include <math.h> 4 using namespace cv; 5 using namespace std; 6 7 int main(int argc,char**argv) 8 { 9 Mat input_image = imread("1.jpg"); 10 if (input_image.data==NULL) { 11 return -1; cout << "can't open image.../"; 12 } 13 imshow("Sourse image", input_image); 14 Mat mid_image,output_image, mid_image1; 15 mid_image.create(input_image.size(),input_image.type()); 16 mid_image1.create(input_image.size(), input_image.type()); 17 cvtColor(input_image,output_image,COLOR_BGR2GRAY); 18 GaussianBlur(output_image,output_image,Size(3,3),2,2); 19 Canny(output_image, output_image,50,200); 20 vector<Vec4i> lines; 21 vector<Vec3f> circles; 22 HoughLinesP(output_image,lines,1,CV_PI/180,80,50,10); 23 HoughCircles(output_image,circles,HOUGH_GRADIENT,1.5,10,200,100,0,0); 24 for (size_t i = 0; i < lines.size(); i++) 25 { 26 Vec4i l; 27 l = lines[i]; 28 line(mid_image,Point(l[0],l[1]),Point(l[2],l[3]),Scalar(100,255,200),1,LINE_AA); 29 } 30 imshow("Destinate1 image", output_image); 31 imshow("Destinate2 image", mid_image); 32 for (size_t j = 0; j < circles.size(); j++) 33 { 34 Vec3f c; 35 c = circles[j]; 36 circle(mid_image1, Point(cvRound(c[0]), cvRound(c[1])), 3, Scalar(0, 255, 50)); 37 circle(mid_image1, Point(cvRound(c[0]), cvRound(c[1])), cvRound(c[2]), Scalar(0, 255, 50),3,8,0); 38 } 39 imshow("Destinate3 image", mid_image1); 40 waitKey(0); 41 return 0; 42 }
opencv自帶的API主要就是參數的設置,設置不好的參數要么檢測的不好,要么根本檢測不到直線和圓!
1.圓的檢測是找不到同心圓的
2.很容易受噪聲干擾
3.必須非常的圓度,橢圓不行
主要參考:http://blog.csdn.net/zhaocj/article/details/50454847