opencv筆記-SimpleBlobDetector


    通用的 Blob 檢測方法包括:Laplacian of Gaussian(LoG), Difference of Gaussian(DoG), Derterminant of Hessian(DoH)。

    opencv 提供了一種簡單的方法實現 Blob 檢測:SimpleBlobDetector。所謂 Blob,其實就是圖像上一些或亮或暗的小連通區域,該連通區域可以使用特定閾值提取出來。

    當分析場景相對簡單,使用 SimpleBlobDetector 可以比較准確且高效的定位 Blob 區域,基本思路如下:

    1 使用連續閾值對圖像進行閾值操作,其閾值參數范圍為 ,步長為 s;

    2 使用 suzuki 算法(findContours)提取每個閾值下形成的區域,findContours 得到的每個邊界圍成的區域被認為是候選 Blob;

       使用 findContours 檢測連通區域要比連通區域分析算法更加高效,同時,一次 findContours 可以區分內外邊界,外邊界對應亮區域,內邊界對應暗區域,但 opencv 2.4.10 源碼中並未對內外邊界區分對待;

    3 對 Blob 區域進行篩查,篩查條件包括:

      

 1  CV_PROP_RW bool filterByColor;
 2  CV_PROP_RW uchar blobColor;
 3 
 4  CV_PROP_RW bool filterByArea;
 5  CV_PROP_RW float minArea, maxArea;
 6 
 7  CV_PROP_RW bool filterByCircularity;
 8  CV_PROP_RW float minCircularity, maxCircularity;
 9 
10  CV_PROP_RW bool filterByInertia;
11  CV_PROP_RW float minInertiaRatio, maxInertiaRatio;
12 
13  CV_PROP_RW bool filterByConvexity;
14  CV_PROP_RW float minConvexity, maxConvexity;

      1)filterByColor 表示提取亮區域或者暗區域。當 blobColor = 255 時,提取亮區域;當 blobColor = 0 時,提取暗區域;

      2)filterByArea 表示是否限制 Blob 面積,其面積范圍為一個半開半閉區間 [minArea, maxArea);

      3)filterByCircularity 表示是否限制 Blob 圓形度,圓形度公式為 

            當 Blob 為圓形時,。當 Blob 為一個無限長的橢圓,。故圓形度范圍取值范圍為 (0, 1];

      4)filterByConvexity 表示  Blob 面積與其凸包面積比,取值范圍為 (0, 1);

      5)filterByInertia 表示 Blob  區域轉動慣量最小值與最大值比值,在 “二值圖像的幾何性質” 博客中,轉動慣量表示為:

           

            

            

            

            由於 轉動慣量 E 為一個二次型函數,使用系數矩陣 的特征值與特征向量可描述轉動慣量特性,其最小值與最大值比為   。

            通過以上分析可知,當 Blob 區域為圓形時,比值接近 1。當 Blob 區域為無限長橢圓時,比值接近 0,故取值范圍為 (0,1);

    4 對於符合篩查條件的 Blob 區域,使用區域邊界到中心點距離中值點作為該 Blob 區域半徑;

    5 將不同閾值下符合條件的候選 Blob 區域組合到一起,使用 minRepeatability 與 minDistBetweenBlobs 篩查出最終有效 Blob 區域;

      以下給出 opencv 對候選 Blob 篩查的部分源碼:

      

 1 for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++)
 2 {
 3     
 4     Center center;
 5     center.confidence = 1;   // 將可信度置1
 6 
 7     // 求輪廓所圍成區域零階矩,一階矩,二階矩,用於篩查條件計算
 8     Moments moms = moments(Mat(contours[contourIdx]));
 9 
10     if (params.filterByArea)
11     {
12          // 零階矩表示區域面積
13          double area = moms.m00;
14          if (area < params.minArea || area >= params.maxArea)
15              continue;
16     }
17 
18      if (params.filterByCircularity)
19      {
20          // 求區域面積與區域周長,並使用圓形度公式計算圓形度
21          double area = moms.m00;
22          double perimeter = arcLength(Mat(contours[contourIdx]), true);
23          double ratio = 4 * CV_PI * area / (perimeter * perimeter);
24          if (ratio < params.minCircularity || ratio >= params.maxCircularity)
25              continue;
26      }
27 
28       if (params.filterByInertia)
29       {
30            // 使用二階矩求區域形狀
31            double denominator = sqrt(pow(2 * moms.mu11, 2) + pow(moms.mu20 - moms.mu02, 2));
32             const double eps = 1e-2;
33             double ratio;
34             if (denominator > eps)
35             {
36                 double cosmin = (moms.mu20 - moms.mu02) / denominator;
37                 double sinmin = 2 * moms.mu11 / denominator;
38                 double cosmax = -cosmin;
39                 double sinmax = -sinmin;
40 
41                 double imin = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmin - moms.mu11 * sinmin;
42                 double imax = 0.5 * (moms.mu20 + moms.mu02) - 0.5 * (moms.mu20 - moms.mu02) * cosmax - moms.mu11 * sinmax;
43                 ratio = imin / imax;
44             }
45             else
46             {
47                 ratio = 1;
48             }
49 
50             if (ratio < params.minInertiaRatio || ratio >= params.maxInertiaRatio)
51                 continue;
52 
53             center.confidence = ratio * ratio;
54         }
55 
56         if (params.filterByConvexity)
57         {
58            // 求區域面積與凸包面積之比
59             vector < Point > hull;
60             convexHull(Mat(contours[contourIdx]), hull);
61             double area = contourArea(Mat(contours[contourIdx]));
62             double hullArea = contourArea(Mat(hull));
63             double ratio = area / hullArea;
64             if (ratio < params.minConvexity || ratio >= params.maxConvexity)
65                 continue;
66         }
67 
68         center.location = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);
69 
70         if (params.filterByColor)
71         {
72            // 提取亮區域或者暗區域
73             if (binaryImage.at<uchar> (cvRound(center.location.y), cvRound(center.location.x)) != params.blobColor)
74                 continue;
75         }
76 
77         // 計算 Blob 半徑
78         {
79             vector<double> dists;
80             for (size_t pointIdx = 0; pointIdx < contours[contourIdx].size(); pointIdx++)
81             {
82                 Point2d pt = contours[contourIdx][pointIdx];
83                 dists.push_back(norm(center.location - pt));
84             }
85             std::sort(dists.begin(), dists.end());
86             center.radius = (dists[(dists.size() - 1) / 2] + dists[dists.size() / 2]) / 2.;
87         }
88 
89         centers.push_back(center);
90 
91    }

 

       

    參考資料 Learning OpenCV 3   Adrian Kaehler & Gary Bradski


免責聲明!

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



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