OpenCV图像处理中“找圆技术”的使用
一、為什么“找圓” 圓是基本圖形的一種,更為重要的是,自然情況下采集的圖像,很少大量存在“圓”;但凡存在的,大都是人工的,那么就必然代表特定的意義,從而方便定位、分割和識別。 OpenCV現有代碼中能夠直接“找圓”,主要有2個,一個是“HoughCircle ”,另一個是“BlobDetector ”,此外基本的輪廓分析也能夠用于圓的尋找。但是這些基礎的方法,涉及到的參數比較多,一方面我們需要深入理解、一方面需要融合運用,才能夠有效提高識別準確率。因此結合實踐,整理相關內容如下:1. “找圓”在圖像處理中的價值和應用案例;2. 深入理解“HoughCircle ”的參數設置和優缺點;3. 深入理解 “BlobDetector”的參數設置和應用實踐;4. 進一步理解”閾值-輪廓-分割“的分割方法和在“找圓”上的運用;5. 融合目前技術,提出”找圓算法鏈“,提高識別準確率。6. 對圓度、凸性、慣性比等基礎知識的進一步認識。希望能夠為圖像處理工程師、愛好者提供一些啟發。二、有效“找圓”的方法OpenCV現有代碼中,設計“找圓”算法的,主要有2個,一個是“HoughCircle ”,另一個是“BlobDetector”,此外基本的輪廓分析也能夠用于圓的尋找。2.1HoughCircle 霍夫圓變換
代碼:
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
#include<math.h>
usingnamespacecv;
usingnamespacestd;
intmain(intargc,char**argv)
{
Mat img, gray;
if( argc!=2||!(img=imread(argv[1],1)).data)
return-1;
cvtColor(img, gray, COLOR_BGR2GRAY);
// smooth it, otherwise a lot of false circles may be detected
GaussianBlur( gray, gray, Size(9,9),2,2);
vector<Vec3f>circles;
HoughCircles(gray, circles, HOUGH_GRADIENT,2, gray.rows/4,200,100);
for( size_t i=0; i<circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
intradius=cvRound(circles[i][2]);
// draw the circle center
circle( img, center,3, Scalar(0,255,0),-1,8,0);
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255),3,8,0);
}
namedWindow("circles",1);
imshow("circles", img );
waitKey(0);
return0;
}
特別需要注意的是,目前版本出現新參數“HOUGH_GRADIENT_ALT”,在默認參數下比以前有很大程度的精度提升:
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
#include<math.h>
usingnamespacecv;
usingnamespacestd;
intmain(intargc,char**argv)
{
Mat img, gray;
if( argc!=2||!(img=imread(argv[1],1)).data)
return-1;
cvtColor(img, gray, COLOR_BGR2GRAY);
// smooth it, otherwise a lot of false circles may be detected
GaussianBlur( gray, gray, Size(9,9),2,2);
vector<Vec3f>circles;
HoughCircles(gray, circles, HOUGH_GRADIENT,2, gray.rows/4,200,100);
for( size_t i=0; i<circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
intradius=cvRound(circles[i][2]);
// draw the circle center
circle( img, center,3, Scalar(0,255,0),-1,8,0);
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255),3,8,0);
}
namedWindow("circles",1);
imshow("circles", img );
waitKey(0);
return0;
}
但是HoughCircle的缺點也是顯而易見的,簡單來說,在默認參數下,它非常容易丟目標。
2.2BlobDetector
所謂Blob就是圖像中一組具有某些共同屬性(例如,灰度值)的連接像素。OpenCV提供了一種方便的方法來檢測斑點并根據不同的特征對其進行過濾。
// Setup SimpleBlobDetector parameters.
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold=10;
params.maxThreshold=200;
// Filter by Area.
params.filterByArea=true;
params.minArea=1500;
// Filter by Circularity
params.filterByCircularity=true;
params.minCircularity=0.1;
// Filter by Convexity
params.filterByConvexity=true;
params.minConvexity=0.87;
// Filter by Inertia
params.filterByInertia=true;
params.minInertiaRatio=0.01;
#ifCV_MAJOR_VERSION<3// If you are using OpenCV 2
// Set up detector with params
SimpleBlobDetector detector(params);
// You can use the detector this way
// detector.detect( im, keypoints);
#else
//Setupdetectorwithparamscv::Ptr<cv::SimpleBlobDetector>detector=cv::SimpleBlobDetector::create(params);vector<KeyPoint>keypoints;detector->detect(screw1,keypoints);
#endif
在OpenCV中實現的叫做SimpleBlobDetector,它基于以下描述的相當簡單的算法,并且進一步由參數控制,具有以下步驟。
SimpleBlobDetector::Params::Params()
{
thresholdStep=10; //二值化的閾值步長,即公式1的t
minThreshold=50; //二值化的起始閾值,即公式1的T1
maxThreshold=220; //二值化的終止閾值,即公式1的T2
//重復的最小次數,只有屬于灰度圖像斑點的那些二值圖像斑點數量大于該值時,該灰度圖像斑點才被認為是特征點
minRepeatability=2;
//最小的斑點距離,不同二值圖像的斑點間距離小于該值時,被認為是同一個位置的斑點,否則是不同位置上的斑點
minDistBetweenBlobs=10;
filterByColor=true; //斑點顏色的限制變量
blobColor=0; //表示只提取黑色斑點;如果該變量為255,表示只提取白色斑點
filterByArea=true; //斑點面積的限制變量
minArea=25; //斑點的最小面積
maxArea=5000; //斑點的最大面積
filterByCircularity=false; //斑點圓度的限制變量,默認是不限制
minCircularity=0.8f; //斑點的最小圓度
//斑點的最大圓度,所能表示的float類型的最大值
maxCircularity=std::numeric_limits<float>::max();
filterByInertia=true; //斑點慣性率的限制變量
minInertiaRatio=0.1f; //斑點的最小慣性率
maxInertiaRatio=std::numeric_limits<float>::max(); //斑點的最大慣性率
filterByConvexity=true; //斑點凸度的限制變量
minConvexity=0.95f; //斑點的最小凸度
maxConvexity=std::numeric_limits<float>::max(); //斑點的最大凸度
}
閾值:通過使用以minThreshold開始的閾值對源圖像進行閾值處理,將源圖像轉換為多個二進制圖像。這些閾值以thresholdStep遞增,直到maxThreshold。因此,第一個閾值為minThreshold,第二個閾值為minThreshold + thresholdStep,第三個閾值為minThreshold + 2 x thresholdStep,依此類推;分組:在每個二進制圖像中,連接的白色像素被分組在一起。我們稱這些二進制blob;合并:計算二進制圖像中二進制斑點的中心,并合并比minDistBetweenBlob更近的斑點;中心和半徑計算:計算并返回新合并的Blob的中心和半徑。
并且可以進一步設置SimpleBlobDetector的參數來過濾所需的Blob類型。
按顏色:首先需要設置filterByColor =True。設置blobColor = 0可選擇較暗的blob,blobColor = 255可以選擇較淺的blob。按大小:可以通過設置參數filterByArea = 1以及minArea和maxArea的適當值來基于大小過濾blob。例如。設置minArea = 100將濾除所有少于100個像素的斑點。按圓度:這只是測量斑點距圓的距離。例如。正六邊形的圓度比正方形高。要按圓度過濾,請設置filterByCircularity =1。然后為minCircularity和maxCircularity設置適當的值。圓度定義為()。圓的為圓度為1,正方形的圓度為PI/4,依此類推。按凸性:凸度定義為(斑點的面積/凸包的面積)。現在,形狀的“凸包”是最緊密的凸形,它完全包圍了該形狀,用不嚴謹的話來講,給定二維平面上的點集,凸包就是將最外層的點連接起來構成的凸多邊形,它能包含點集中所有的點。直觀感受上,凸性越高則里面“奇怪的部分”越少。要按凸度過濾,需設置filterByConvexity = true,minConvexity、maxConvexity應該屬于[0,1],而且maxConvexity>minConvexity。按慣性比:這個詞匯比較抽象。我們需要知道Ratio可以衡量形狀的伸長程度。簡單來說。對于圓,此值是1,對于橢圓,它在0到1之間,對于直線,它是0。按慣性比過濾,設置filterByInertia = true,并設置minInertiaRatio、maxInertiaRatio同樣屬于[0,1]并且maxConvexity>minConvexity。
按凸性(左低右高)
按慣性比(左低右高)
// Setup SimpleBlobDetector parameters.
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold=10;
params.maxThreshold=200;
// Filter by Area.
params.filterByArea=true;
params.minArea=1500;
// Filter by Circularity
params.filterByCircularity=true;
params.minCircularity=0.1;
// Filter by Convexity
params.filterByConvexity=true;
params.minConvexity=0.87;
// Filter by Inertia
params.filterByInertia=true;
params.minInertiaRatio=0.01;
#ifCV_MAJOR_VERSION<3// If you are using OpenCV 2
// Set up detector with params
SimpleBlobDetector detector(params);
// You can use the detector this way
// detector.detect( im, keypoints);
#else
//Setupdetectorwithparamscv::Ptr<cv::SimpleBlobDetector>detector=cv::SimpleBlobDetector::create(params);vector<KeyPoint>keypoints;detector->detect(screw1,keypoints);
#endifSimpleBlobDetector::Params::Params()
{
thresholdStep=10; //二值化的閾值步長,即公式1的t
minThreshold=50; //二值化的起始閾值,即公式1的T1
maxThreshold=220; //二值化的終止閾值,即公式1的T2
//重復的最小次數,只有屬于灰度圖像斑點的那些二值圖像斑點數量大于該值時,該灰度圖像斑點才被認為是特征點
minRepeatability=2;
//最小的斑點距離,不同二值圖像的斑點間距離小于該值時,被認為是同一個位置的斑點,否則是不同位置上的斑點
minDistBetweenBlobs=10;
filterByColor=true; //斑點顏色的限制變量
blobColor=0; //表示只提取黑色斑點;如果該變量為255,表示只提取白色斑點
filterByArea=true; //斑點面積的限制變量
minArea=25; //斑點的最小面積
maxArea=5000; //斑點的最大面積
filterByCircularity=false; //斑點圓度的限制變量,默認是不限制
minCircularity=0.8f; //斑點的最小圓度
//斑點的最大圓度,所能表示的float類型的最大值
maxCircularity=std::numeric_limits<float>::max();
filterByInertia=true; //斑點慣性率的限制變量
minInertiaRatio=0.1f; //斑點的最小慣性率
maxInertiaRatio=std::numeric_limits<float>::max(); //斑點的最大慣性率
filterByConvexity=true; //斑點凸度的限制變量
minConvexity=0.95f; //斑點的最小凸度
maxConvexity=std::numeric_limits<float>::max(); //斑點的最大凸度
}這里的基礎知識可能比較復雜,關鍵是默認參數下,識別的效果應該說出奇的好。cv::Ptr<cv::SimpleBlobDetector>detector=cv::SimpleBlobDetector::create();
但是存在的主要問題是由于blob分析的配置參數太多,優化起來存在困難。同時對于某些情況,明顯識別錯誤。
2.3 基本輪廓分析更普通的情況下,我們還是需要從輪廓分析開始,通過上面提出的“圓度”來尋找圓,主要是用來“查漏補缺”,或者是用于特殊情況的查找。
三、算法融合、協作增效在前面已經詳細分析3種主要算法的基礎上,本文的重點創造一個“算法鏈”找到的目標有效地融合起來,并且進一步橫向分析研究算法間的關系,希望多少能夠給關注這個方向、有類似需求的創作者一些思考。算法流程首先對于自然圖片,通過blod detection獲得準確的半徑;而后基于準確的半徑,分別調用HoughCircle以查漏補缺;最后,以上獲得的結果,需要進行融合篩選。這個方法,我在“鋼管識別”項目上得到了突出的成功應用,最終能夠實現非常高的準確識別。主要是基于以下幾點:1、blobdetector能夠找到準確的圓的半徑,但是會找錯、找漏;2、HoughCircle在有“準確的圓的半徑”的加持下,能夠很大程度上提高準確識別效率;3、目標物體是有“固有特征”的,比如這里需要尋找的鋼管,他們的“半徑”基本上是一致的。
如果對于這個項目感興趣,可以在51cto課程上搜索,感謝閱讀至此,希望有所幫助。
來自為知筆記(Wiz)
總結
以上是生活随笔為你收集整理的OpenCV图像处理中“找圆技术”的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首批就把骁龙8+干到3499!一图看懂真
- 下一篇: 温湿度监测系统设计:基于 STM32 的