前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >two Pass方法连通域检测

two Pass方法连通域检测

作者头像
一棹烟波
发布2018-03-19 17:32:11
2.1K0
发布2018-03-19 17:32:11
举报
文章被收录于专栏:一棹烟波

原理:

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

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

代码:

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

代码语言:javascript
复制
  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 }

结果:

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

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

(2)寻找连通域

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原理:
  • 代码:
  • 结果:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档