如何判斷輪廓是否爲圓(算法更新)

    咱們已經獲得了感興趣的輪廓,下一步就是要對輪廓進行選擇,有一些輪廓是須要——有一些是不須要的,是噪音。經過判斷一個輪廓是否爲圓,在不少狀況下能夠幫助咱們來作這相當重要的一步。
    簡單的狀況,好比下圖的啤酒瓶缺口檢測:
     因爲瓶口是有缺陷的,形成最大外輪廓不閉合——這顯然和「圓」差距很遠,那反過來講,那些差距比較小的輪廓可能就是沒有缺陷的。
    再來看比較複雜的狀況,咱們來「數鋼管」。下圖是connection效果,咱們發現了不少輪廓,可是隻有一部分更接近圓——這些可能就是咱們須要尋找的目標。
    相當重要的一步就是創建數學模型。2017年左右爲解決實際問題,我創建了模型一
    基於圓的定義:  「平面上到定點的距離等於定長的全部點組成的圖形叫作圓.定點稱爲圓心,定長稱爲半徑.」。那麼經過判斷當前輪廓到一個定點的距離是否爲定長,就能夠獲得當前輪廓是否更像圓。這個定點就能夠採用外接圓圓心。這裏的度量方式能夠是方差。
   //根據輪廓點和圓心計算方差 參考代碼
float ComputeVariance(std : : vector < cv : : Point > theContour,Point2f theCenter)
{
    int a[ 65535 ],n;
    float aver,s;
    float sum = 0 ,e = 0 ;
    n = theContour.size();
    for ( int i = 0 ;i < n;i ++ )
    {
        a[i] = GetDistance(theContour[i],theCenter);
        sum += a[i];
    }
    aver = sum / n;
    for ( int i = 0 ;i < n;i ++ )
        e += (a[i] - aver) * (a[i] - aver);
    e /= n - 1 ;
    s = sqrt(e);
    return e;
}
    模型一使用了3年左右,也解決了不少問題,特別對於簡單問題來講,效果是很好的。可是它有一個明顯的缺點,就是關於這個結果方差的度量,每次都須要不斷試驗纔可以得出一個較好的值。2020年我遇到了前面的「數鋼管」問題,出現了新的困難,好比下圖:
當輪廓爲長條形的時候(上圖紅圈),會錯誤地識別爲圓。這種長條型輪廓能夠抽象爲下圖紅圈:
    這種狀況的方差可能不是很大,雖然直觀理解其它,它很不是一個圓。
    通過一段時間思索和尋找,創建模型二:
    基於「圓度」的定義:設平面上一個封閉圖形(內部無空洞)的面積爲S,它的周長爲C,則定義該圖形的圓度爲:
    
                4 * PI * S
         Afa = ------------
                  C * C

       正圓的afa爲1,輪廓的afa值越接近1,輪廓越解決圓
        //afa參考代碼
         double s  = cv : :contourArea(contours_test[i]); //輪廓面積
         double c  = cv : :arcLength(contours_test[i],  true);  //輪廓周長
         float afa  =  4  * PI */ (c *c);  //afa計算
        afa  = abs(afa  -  1);


比較不一樣afa閾值狀況下,對此輪廓篩選結果

afa(越小越好) 結果
0.5  
0.3
0.4
  
    從結果上能夠明顯看出,afa方法很好地過濾掉了噪音。
    感謝閱讀至此,但願有所幫助。!


參考資料:
https://bbs.csdn.net/topics/50480119





相關文章
相關標籤/搜索