two Pass方法连通域检测

时间:2023-03-09 22:51:51
two Pass方法连通域检测

原理:

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

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

two Pass方法连通域检测

代码:

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

 #include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <map>
#include <cassert>
#include <iostream> using namespace std; const int max_size = ;
int parent[max_size] = { }; // 找到label x的根节点
int Find(int x, int parent[])
{
assert(x < max_size);
int i = x;
while ( != parent[i])
i = parent[i];
return i;
} // 将label x 和 label y合并到同一个连通域
void Union(int x, int y, int parent[])
{
assert(x < max_size && y < max_size);
int i = x;
int j = y;
while ( != parent[i])
i = parent[i];
while ( != parent[j])
j = parent[j];
if (i != j)
parent[i] = j;
} cv::Mat twoPassConnectComponent(cv::Mat &binaryImg)
{
int imgW = binaryImg.cols;
int imgH = binaryImg.rows;
int channel = binaryImg.channels();
int type = binaryImg.type();
// first pass
int label = ; cv::Mat dst = cv::Mat::zeros(cv::Size(imgW, imgH), CV_32SC1);
for (int y = ; y < imgH; y++)
{
for (int x = ; x < imgW; x++)
{
if (binaryImg.at<uchar>(y, x) != )
{
int left = (x - < ) ? : dst.at<int>(y, x - );
int up = (y - < ) ? : dst.at<int>(y - , x); if (left != || up != )
{
if (left != && up != )
{
dst.at<int>(y, x) = min(left, up);
if (left <= up)
Union(up, left, parent);
else if (up<left)
Union(left, up, parent);
}
else
dst.at<int>(y, x) = max(left, up);
}
else
{
dst.at<int>(y, x) = ++label;
}
}
}
} //second pass
for (int y = ; y < imgH; y++)
{
for (int x = ; x < imgW; x++)
{
if (binaryImg.at<uchar>(y, x) != )
dst.at<int>(y, x) = Find(dst.at<int>(y, x), parent);
}
} return dst;
} cv::Scalar getRandomColor()
{
uchar r = * (rand() / (1.0 + RAND_MAX));
uchar g = * (rand() / (1.0 + RAND_MAX));
uchar b = * (rand() / (1.0 + RAND_MAX));
return cv::Scalar(b, g, r);
} cv::Mat showColorLabel(cv::Mat label)
{
int imgW = label.cols;
int imgH = label.rows;
std::map<int, cv::Scalar> colors; cv::Mat colorLabel = cv::Mat::zeros(imgH, imgW, CV_8UC3);
int *pLabel = (int*)label.data;
uchar *pColorLabel = colorLabel.data;
for (int i = ; i < imgH; i++)
{
for (int j = ; j < imgW; j++)
{
int idx = (i*imgW + j) * ;
int pixelValue = pLabel[i*imgW + j];
if (pixelValue > )
{
if (colors.count(pixelValue) <= )
{
colors[pixelValue] = getRandomColor();
}
cv::Scalar color = colors[pixelValue];
pColorLabel[idx + ] = color[];
pColorLabel[idx + ] = color[];
pColorLabel[idx + ] = color[];
}
}
} return colorLabel;
} int main()
{
// 加载图像
string imageName = "data/source_images/logo.png";
cv::Mat image = cv::imread(imageName, );
if (!image.data)
{
cout << "No image data" << endl;
getchar();
return -;
}
//转为灰度图
cv::cvtColor(image, image, CV_RGB2GRAY);
//阈值化,情景为255,背景为0
cv::Mat threshImg;
cv::threshold(image, threshImg, , , cv::THRESH_BINARY);
cv::bitwise_not(threshImg, threshImg); //连通域检测 two Pass方法标记图像
cv::Mat labelImg = twoPassConnectComponent(threshImg); //不同连通区域用不同颜色表示
cv::Mat colorLabelImg=showColorLabel(labelImg); //显示
cv::imshow("thresh", threshImg);
cv::imshow("label", labelImg*);
cv::imshow("colorLabel", colorLabelImg);
cv::waitKey();
}

结果:

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

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

(2)寻找连通域

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

two Pass方法连通域检测    two Pass方法连通域检测

two Pass方法连通域检测   two Pass方法连通域检测

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