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>
using namespace cv;
using namespace std;
int main(int argc, 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(99), 22 );
    vector<Vec3f> circles;
    HoughCircles(gray, circles, HOUGH_GRADIENT,2, gray.rows/4200100 );
    for( size_t i = 0; i < circles.size(); i++ )
    {
         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
         int radius = cvRound(circles[i][2]);
         // draw the circle center
         circle( img, center, 3, Scalar(0,255,0), -180 );
         // draw the circle outline
         circle( img, center, radius, Scalar(0,0,255), 380 );
    }
    namedWindow( "circles"1 );
    imshow( "circles", img );
    waitKey(0);
    return 0;
}

特別需要注意的是,目前版本出現新參數“HOUGH_GRADIENT_ALT”,在 默認參數下比以前有很大程度的精度提升:

file

但是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;
# if CV_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
 
        // Set up detector with params
        cv::Ptr<cv::SimpleBlobDetectordetector = cv::SimpleBlobDetector::create(params);
        vector<KeyPointkeypoints;
        detector->detect(screw1keypoints);  
# 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。
    按凸性(左低右高) 按慣性比(左低右高)
    Concave versus Convex Shape  Inertia Ratio

這里的基礎知識可能比較復雜,關鍵是默認參數下,識別的效果應該說出奇的好。
cv : :Ptr <cv : :SimpleBlobDetector > detector  = cv : :SimpleBlobDetector : :create();

但是存在的主要問題是由於blob分析的配置參數太多,優化起來存在困難。同時對於某些情況,明顯識別錯誤。

2.3 基本輪廓分析
更普通的情況下,我們還是需要從輪廓分析開始,通過上面提出的“圓度”來尋找圓,主要是用來“查漏補缺”,或者是用於特殊情況的查找。

三、算法融合、協作增效
在前面已經詳細分析3種主要算法的基礎上,本文的重點創造一個“算法鏈”找到的目標有效地融合起來,並且進一步橫向分析研究算法間的關系,希望多少能夠給關注這個方向、有類似需求的創作者一些思考。
算法流程
首先對於自然圖片,通過blod detection獲得准確的半徑; 而后基於准確的半徑,分別調用HoughCircle以查漏補缺; 最后,以上獲得的結果,需要進行融合篩選。這個方法,我在“鋼管識別”項目上得到了突出的成功應用,最終能夠實現非常高的准確識別。主要是基於以下幾點:
1、blobdetector能夠找到准確的圓的半徑,但是會找錯、找漏;
2、HoughCircle在有“准確的圓的半徑”的加持下,能夠很大程度上提高准確識別效率;
3、目標物體是有“固有特征”的,比如這里需要尋找的鋼管,他們的“半徑”基本上是一致的。

如果對於這個項目感興趣,可以在51cto課程上搜索,感謝閱讀至此,希望有所幫助。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM