OpenCV—連通域分析connectedComponentsWithStats()

下文主要內容來自《Learning OpenCV 3》page417-419和官方文檔 

在OpenCV 3中提供了兩個很好的函數,在OpenCV 2中沒有。 

(1)cv::connectedComponents()

(2)cv::connectedComponentsWithStats()

對應的官方文檔爲:https://docs.opencv.org/3.3.1/d3/dc0/group__imgproc__shape.html#ga107a78bf7cd25dec05fb4dfc5c9e765f

int cv::connectedComponents (
    cv::InputArrayn image, // input 8-bit single-channel (binary)
    cv::OutputArray labels, // output label map
    int connectivity = 8, // 4- or 8-connected components
    int ltype = CV_32S // Output label type (CV_32S or CV_16U)
);
int cv::connectedComponentsWithStats (
    cv::InputArrayn image, // input 8-bit single-channel (binary)
    cv::OutputArray labels, // output label map
    cv::OutputArray stats, // Nx5 matrix (CV_32S) of statistics:
    // [x0, y0, width0, height0, area0;
    // ... ; x(N-1), y(N-1), width(N-1),
    // height(N-1), area(N-1)]
    cv::OutputArray centroids, // Nx2 CV_64F matrix of centroids:
    // [ cx0, cy0; ... ; cx(N-1), cy(N-1)]
    int connectivity = 8, // 4- or 8-connected components
    int ltype = CV_32S // Output label type (CV_32S or CV_16U)
);
其中connectedComponents()僅僅創建了一個標記圖(圖中不同連通域使用不同的標記,和原圖寬高一致),connectedComponentsWithStats()也可以完成上面任務,除此之外,還可以返回每個連通區域的重要信息--bounding box, area, and center of mass(centroid).如果不需要連通域的質心,將參數centroids設置爲cv::noArray(),這句話在我的版本中運行會出錯。

函數返回值爲連通區域的總數N,範圍爲[0,N-1],其中0代表背景。


下面是一個簡單的示例,畫出了帶標記的連通區域,同時去除很小的連通域(相當於無損降噪)。


#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
      cv::Mat src_img, img_bool, labels, stats, centroids, img_color, img_gray;
      
      if( (src_img = cv::imread("2.bmp",0)).empty())
      {
            cout<<"load image error!";
            return -1;
      }
      cv::threshold(src_img, img_bool, 0, 255, cv::THRESH_OTSU);
      //連通域計算
      int nccomps = cv::connectedComponentsWithStats (
            img_bool, //二值圖像
            labels,     //和原圖一樣大的標記圖
            stats, //nccomps×5的矩陣 表示每個連通區域的外接矩形和麪積(pixel)
            centroids //nccomps×2的矩陣 表示每個連通區域的質心
            );
      //顯示原圖統計結果
      char title[1024];
      sprintf(title,"原圖中連通區域數:%d\n",nccomps);
      cv::String num_connect(title);
      cv::imshow(num_connect, img_bool);
      
      //去除過小區域,初始化顏色表
      vector<cv::Vec3b> colors(nccomps);
      colors[0] = cv::Vec3b(0,0,0); // background pixels remain black.
      for(int i = 1; i < nccomps; i++ ) {
            colors[i] = cv::Vec3b(rand()%256, rand()%256, rand()%256);
            //去除面積小於100的連通域
            if( stats.at<int>(i, cv::CC_STAT_AREA) < 100 )
                  colors[i] = cv::Vec3b(0,0,0); // small regions are painted with black too.
      }
      //按照label值,對不同的連通域進行着色
      img_color = cv::Mat::zeros(src_img.size(), CV_8UC3);
      for( int y = 0; y < img_color.rows; y++ )
            for( int x = 0; x < img_color.cols; x++ )
            {
                  int label = labels.at<int>(y, x);
                  CV_Assert(0 <= label && label <= nccomps);
                  img_color.at<cv::Vec3b>(y, x) = colors[label];
            }
      
      //統計降噪後的連通區域
      cv::cvtColor(img_color,img_gray,cv::COLOR_BGR2GRAY);
      cv::threshold(img_gray, img_gray, 1, 255, cv::THRESH_BINARY);
      nccomps = cv::connectedComponentsWithStats (img_gray, labels,stats,centroids);
      sprintf(title,"過濾小目標後的連通區域數量:%d\n",nccomps);
      num_connect = title;
      cv::imshow(num_connect, img_color);
      cv::waitKey();
      return 0;
}



發佈了89 篇原創文章 · 獲贊 212 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章