国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

opencv學習筆記(二十五)霍夫圓變換

2019-11-08 02:59:11
字體:
來源:轉載
供稿:網友

霍夫圓變換與之前所描述的霍夫直線變換是大體上是類似的。說“大體上類似”的原因是——如果想要嘗試完全類似——累加平面會被三維的累加容器所代替:在這三維中,一維是x,一維是y,另一維是圓的半徑r。這就意味著需要大量的內存但速度卻很慢。在OpenCV的應用中可以通過一個比較靈活的霍夫梯度法來解決圓變換的這一問題。 霍夫梯度法的原理如下。首先對圖像應用邊緣檢測(這里用cvCanny ( )。然后,對邊緣圖像中每一個非0點,考慮其局部梯度(通過cvSobel( )函數計算x和Y方向的Sobel一階導數得到梯度)。利用得到的梯度,由斜率指定的直線上的每一個點都在累加器中被累加,這里斜率是從一個指定的最小值到指定的最大值的距離。同時,標記邊緣圖像中每一個非0像素的位置。然后從(二維)累加器中這些點中選擇候選的中心,這些中心都大于給定閾值并且大于其所有近鄰。這些候選的中心按照累加值降序排列,以便于最支持像素的中心首先出現。接下來對每一個中心,考慮所有的非0像素(回想一下這個清單在早期已經建立)。這些像素按照其與中心的距離排序。從到最大半徑的最小距離算起,選擇非0像素最支持的一條半徑。如果一個中心受到邊緣圖像非0像素最充分的支持,并且到前期被選擇的中心有足夠的距離,它將會被保留。

這個實現可以使算法執行起來更快,或許更重要的是,能夠幫助解決三維累加器中其他稀疏分布問題,這個問題會產生許多噪聲并使結果不穩定。另一方面,這個算法有許多需要注意的缺點。 首先,使用Sobel導數計算局部梯度——隨之而來的假設是這個可以看作等同于一條局部切線—并不是一個數值穩定做法。在大多數時間這個命題可能是真的,但你可能認為這樣會在輸出中產生一些噪聲。 其次,在邊緣圖像中的整個非0像素集被認為是每個中心的候選。因此,加器的閾值設置偏低,算法將要消耗比較長的時間。 第三,因為每一個中心只選擇一個圓,如果有同心圓,就只能選擇其中的一個。 最后,因為中心是被認為是按照與其關聯的累加器的值升序排列的,并且如果新的中心過于接近以前接受的中心將不會被保留。這里有一個傾向就是當有許多同心圓或者是近似同心圓時,保留最大的一個圓。(只是個“偏見”,因為從Sobcl導數產生了噪聲;若是在無窮分辨率的平滑圖像,這才是確定的)。 霍夫圓變換函數evHoughCircles()與直線變換有相似的變量。輸入的image也是8位的。cvHoughCircles()與cvHoughLines2()一個明顯的不同是后者需要二值圖像。cvHoughCircles()函數將會在內部(自動)調用。cvSobel()①——注釋:①內部調用的是函數cvSobel()而不是cvCanny ( )。因為cvHoughCircles()需要估計每一個像素梯度的方向,但二值邊緣圖像的處理是比較難的,所以可以提供更加普通的灰度圖。 circle_storage既可以是數組,也可以是內存存儲器(memory storage),這取決于我們希望返回什么結果。如果使用數組,則應該是CV_32FC3類型的單列數組,三個通道分別存儲圓的位置及其半徑。如果使用內存存儲器(memory storage) ,圓將會變成OpenCV的一個序列Cvseq,由cvHoughCircles()返回一個指向這個序列的指針(給定一個指向圓存儲的數組指針值,cvHoughCircles()的返回值將為空)。 在這個方法中,參數必須設置為CV_HOUGH_GRADIENT。

cvHoughCircles()

注意:盡管cvHoughCircles()能很好地捕獲到圓心,但有時也會找不到圓的半徑。因此,在只需找到圓的中心(或者有其他一些技術可以準確找到圓的半徑)的實際應用中,cvHoughCircles()返回的圓半徑可以忽略。

利用 Hough 變換在灰度圖像中找圓 定義: CvSeq* cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 ); 參數: image 輸入 8比特、單通道灰度圖像。 circle_storage 檢測到的圓存儲倉。可以是內存存儲倉 (此種情況下,一個線段序列在存儲倉中被創建,并且由函數返回)或者是包含圓參數的特殊類型的具有單行/單列的CV_32FC3型矩陣(CvMat*)。矩陣頭為函數所修改,使得它的 cols/rows 將包含一組檢測到的圓。如果 circle_storage 是矩陣,而實際圓的數目超過矩陣尺寸,那么最大可能數目的圓被返回。每個圓由三個浮點數表示:圓心坐標(x,y)和半徑r。 method Hough 變換方式,目前只支持CV_HOUGH_GRADIENT。 dp 累加器圖像的分辨率。這個參數允許創建一個比輸入圖像分辨率低的累加器。(這樣做是因為有理由認為圖像中存在的圓會自然降低到與圖像寬高相同數量的范疇)。如果dp設置為1,則分辨率是相同的;如果設置為更大的值(比如2),累加器的分辨率受此影響會變小(此情況下為一半)。dp的值不能比1小。 自己試驗之后發現,當dp=1時,好像檢測不出圓。1.5時正好,一旦大于1.5,就有N個圓出現了。數越大,圓越多。 min_dist 該參數是讓算法能明顯區分的兩個不同圓之間的最小距離。 param1 用于Canny的邊緣閥值上限,下限被置為上限的一半。 param2 累加器的閥值。 min_radius 最小圓半徑,默認值0。 max_radius 最大圓半徑,默認值0。

程序實例:

#include <opencv2/opencv.hpp>int main(int argc, char* argv[]) { iplImage* image0=cvLoadImage("d.jpg",CV_LOAD_IMAGE_GRAYSCALE); IplImage* image= cvLoadImage("d.jpg",CV_LOAD_IMAGE_GRAYSCALE); CvMemStorage* storage=cvCreateMemStorage(0); cvSmooth(image0,image,CV_GAUSSIAN,5,5); CvSeq* results=cvHoughCircles(image,storage,CV_HOUGH_GRADIENT,1.8, 10, 200, 100, 0, 0 ); for(int i=0;i<results->total ;i++) { float* p=(float*) cvGetSeqElem(results,i); CvPoint pt=cvPoint(cvRound(p[0]),cvRound(p[1])); cvCircle(image,pt,cvRound(p[2]),CV_RGB(0,0,0), 3, 8, 0); } cvNamedWindow("source",1); cvShowImage("source",image0); cvNamedWindow("cvHoughCircles",1); cvShowImage("cvHoughCircles",image); cvWaitKey(0); return 0; }

程序使用的圖片: 這里寫圖片描述

程序理解: 這里面有一個 float* p=(float*) cvGetSeqElem(results,i); CvPoint pt=cvPoint(cvRound(p[0]),cvRound(p[1])); cvCircle(image,pt,cvRound(p[2]),CV_RGB(0,0,0), 3, 8, 0); 我們需要注意一下的是: 調用cvGetSeqElem之后得到的是相應圓的圓心(x,y)和半徑信息。 所以才有下的cvCircle中的引用pt(圓心坐標)和cvRound(p[2])——半徑。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 胶南市| 肥城市| 乌兰察布市| 广安市| 东乌珠穆沁旗| 兴业县| 乌拉特后旗| 天水市| 东乌珠穆沁旗| 咸丰县| 奉新县| 西乡县| 娄底市| 壤塘县| 潞城市| 汉沽区| 白城市| 三明市| 宝清县| 斗六市| 汾阳市| 稷山县| 温泉县| 福州市| 鹿泉市| 广南县| 通山县| 武鸣县| 太康县| 安吉县| 靖边县| 合山市| 彭泽县| 乌苏市| 莱阳市| 紫云| 观塘区| 苍溪县| 东明县| 高台县| 松潘县|