• two Pass方法连通域检测


    原理:

    Two-Pass方法检测连通域的原理可参见这篇博客:http://blog.csdn.net/lichengyu/article/details/13986521

    参考下面动图,一目了然。

    代码:

    代码中标记图的数据类型要注意,如果first pass中标记数多于255,就不要用uchar类型,我直接设置为int类型。

      1 #include "opencv2/imgproc/imgproc.hpp"
      2 #include "opencv2/highgui/highgui.hpp"
      3 #include <map>
      4 #include <cassert>
      5 #include <iostream>
      6 
      7 using namespace std;
      8 
      9 const int max_size = 1000;
     10 int parent[max_size] = { 0 };
     11 
     12 // 找到label x的根节点
     13 int Find(int x, int parent[])
     14 {
     15     assert(x < max_size);
     16     int i = x;
     17     while (0 != parent[i])
     18         i = parent[i];
     19     return i;
     20 }
     21 
     22 // 将label x 和 label y合并到同一个连通域
     23 void Union(int x, int y, int parent[])
     24 {
     25     assert(x < max_size && y < max_size);
     26     int i = x;
     27     int j = y;
     28     while (0 != parent[i])
     29         i = parent[i];
     30     while (0 != parent[j])
     31         j = parent[j];
     32     if (i != j)
     33         parent[i] = j;
     34 }
     35 
     36 cv::Mat twoPassConnectComponent(cv::Mat &binaryImg)
     37 {
     38     int imgW = binaryImg.cols;
     39     int imgH = binaryImg.rows;
     40     int channel = binaryImg.channels();
     41     int type = binaryImg.type();
     42     // first pass
     43     int label = 0;
     44 
     45     cv::Mat dst = cv::Mat::zeros(cv::Size(imgW, imgH), CV_32SC1);
     46     for (int y = 0; y < imgH; y++)
     47     {
     48         for (int x = 0; x < imgW; x++)
     49         {
     50             if (binaryImg.at<uchar>(y, x) != 0)
     51             {
     52                 int left = (x - 1 < 0) ? 0 : dst.at<int>(y, x - 1);
     53                 int up = (y - 1 < 0) ? 0 : dst.at<int>(y - 1, x);
     54 
     55                 if (left != 0 || up != 0)
     56                 {
     57                     if (left != 0 && up != 0)
     58                     {
     59                         dst.at<int>(y, x) = min(left, up);
     60                         if (left <= up)
     61                             Union(up, left, parent);
     62                         else if (up<left)
     63                             Union(left, up, parent);
     64                     }
     65                     else
     66                         dst.at<int>(y, x) = max(left, up);
     67                 }
     68                 else
     69                 {
     70                     dst.at<int>(y, x) = ++label;
     71                 }
     72             }
     73         }
     74     }
     75 
     76     //second pass 
     77     for (int y = 0; y < imgH; y++)
     78     {
     79         for (int x = 0; x < imgW; x++)
     80         {
     81             if (binaryImg.at<uchar>(y, x) != 0)
     82                 dst.at<int>(y, x) = Find(dst.at<int>(y, x), parent);
     83         }
     84     }
     85 
     86     return dst;
     87 }
     88 
     89 cv::Scalar getRandomColor()
     90 {
     91     uchar r = 255 * (rand() / (1.0 + RAND_MAX));
     92     uchar g = 255 * (rand() / (1.0 + RAND_MAX));
     93     uchar b = 255 * (rand() / (1.0 + RAND_MAX));
     94     return cv::Scalar(b, g, r);
     95 }
     96 
     97 cv::Mat showColorLabel(cv::Mat label)
     98 {
     99     int imgW = label.cols;
    100     int imgH = label.rows;
    101     std::map<int, cv::Scalar> colors;
    102 
    103     cv::Mat colorLabel = cv::Mat::zeros(imgH, imgW, CV_8UC3);
    104     int *pLabel = (int*)label.data;
    105     uchar *pColorLabel = colorLabel.data;
    106     for (int i = 0; i < imgH; i++)
    107     {
    108         for (int j = 0; j < imgW; j++)
    109         {
    110             int idx = (i*imgW + j) * 3;
    111             int pixelValue = pLabel[i*imgW + j];
    112             if (pixelValue > 0)
    113             {
    114                 if (colors.count(pixelValue) <= 0)
    115                 {
    116                     colors[pixelValue] = getRandomColor();
    117                 }
    118                 cv::Scalar color = colors[pixelValue];
    119                 pColorLabel[idx + 0] = color[0];
    120                 pColorLabel[idx + 1] = color[1];
    121                 pColorLabel[idx + 2] = color[2];
    122             }
    123         }
    124     }
    125 
    126     return colorLabel;
    127 }
    128 
    129 int main() 
    130 {
    131     // 加载图像
    132     string imageName = "data/source_images/logo.png";
    133     cv::Mat image = cv::imread(imageName, 1);
    134     if (!image.data) 
    135     {
    136         cout << "No image data" << endl;
    137         getchar();
    138         return -1;
    139     }
    140     //转为灰度图
    141     cv::cvtColor(image, image, CV_RGB2GRAY);
    142     //阈值化,情景为255,背景为0
    143     cv::Mat threshImg;
    144     cv::threshold(image, threshImg, 200, 255, cv::THRESH_BINARY);
    145     cv::bitwise_not(threshImg, threshImg);
    146 
    147     //连通域检测 two Pass方法标记图像
    148     cv::Mat labelImg = twoPassConnectComponent(threshImg);
    149 
    150     //不同连通区域用不同颜色表示
    151     cv::Mat colorLabelImg=showColorLabel(labelImg);
    152 
    153     //显示
    154     cv::imshow("thresh", threshImg);
    155     cv::imshow("label", labelImg*20);
    156     cv::imshow("colorLabel", colorLabelImg);
    157     cv::waitKey(0);
    158 }
    View Code

    结果:

    使用OpenCV的logo为素材图,如下:

    (1)转为灰度图然后阈值化

    (2)寻找连通域

    (3)不同连通区域不同颜色显示

        

       

     封装后的代码见我的码云code:https://gitee.com/rxdj/twoPassMethod.git

     

  • 相关阅读:
    Java 对文件的操作
    快速排序算法
    Java 时间和字符换的处理
    Redis 数据结构之Keys
    [转] Redis系统性介绍
    【转】JAVA 接口
    [转] Python 代码性能优化技巧
    几道关于面试的题目
    随手笔记2
    随手笔记
  • 原文地址:https://www.cnblogs.com/riddick/p/8280883.html
Copyright © 2020-2023  润新知