目标分割算法之连通域分析

1.连通域提取

二值化后的图像为8位图CV_8UC1,首先对连通域进行标记,然后针对32位CV_32S图像进行连通域提取
具体如下:

//标记连通域  img_bw == 二值图像
Mat mask;
connectedComponents(img_bw, mask, 8);//mask位32位图,连通域标签为其索引值
map<int, vector<Point>> map_connect;
for (int i = 0; i < mask.rows; i++)
{
	for (int j = 0; j < mask.cols; j++)
	{
		int Pix = mask.at<int>(i, j);
		if ((Pix != -1)&&(Pix>0)&&(Pix<nums))
			map_connect[Pix].push_back(Point(j, i));
	}
}

//方法二:
vector<vector<Point>>contours;
vector<Vec4i>hierachy;
findContours(bwMask, contours, hierarchy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
int nums=contours.size();
Mat mask_8=Mat(img)bw.size(),CV_8UC1);
int i=0;
for(;i<nums;++i)
{
    drawContours(mask_8,contours,i,Scalar(i+1),-1);
}

2.连通域统计分析

//对二值图进行分析,输出图像深度可通过参数设置
Mat label, stats, cens;
connectedComponentsWithStats(img_img, label, stats, cens, 8);

label为32位标记图像,如下
在这里插入图片描述
stats也是32位图像,尺寸为5x连通域个数,统计信息为连通域外接矩形左上顶点坐标及矩形长、宽和连通域面积,分别通过以下指令读取

int x=stats.at<int>(i,CC_STAT_LEFT);
int y=stats.at<int>(i,CC_STAT_TOP);
int w=stats.at<int>(i,CC_STAT_WIDTH);
int h=stats.at<int>(i,CC_STAT_HEIGHT): 
int area=stats.at<int>(i,CC_STAT_AREA);

数据如下:
在这里插入图片描述
cens为64位矩阵,尺寸为2x连通域个数,存储每个连通域质心坐标,读取如下:

int x=cens.at<double>(i,0);
int y=cens.at<double>(i,1);

数据如下:
在这里插入图片描述

3.分水岭分割结果标记图上色

watershed(result, mask);//mask为32为标记图连通域标记值=灰度值
//opencv上色
vector<Vec3b> colorTab;
for (i = 0; i < compCount; i++)
{
	int b = theRNG().uniform(0, 255);
	int g = theRNG().uniform(0, 255);
	int r = theRNG().uniform(0, 255);
	colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
Mat wshed=Mat(mask.size(),CV_8UC3,Scalar::all(0));
for (i = 0; i < markers.rows; i++)
	for (j = 0; j < markers.cols; j++)
	{
		int index = markers.at<int>(i, j);
		if (index == -1)
		{
			wshed.at<Vec3b>(i, j) = Vec3b(255, 255, 255);		
		}
		else if (index <= 0 || index > compCount)
		{
			wshed.at<Vec3b>(i, j) = Vec3b(0, 0, 0);	
		}
		else {
			wshed.at<Vec3b>(i, j) = colorTab[index - 1];
		}
}
//矩阵并行:
minMaxLoc(markers_, &min_p, &max_p);
Mat wshed_=Mat(mask.size(),CV_8UC3,Scalar::all(0));
for (int i = min_p; i <= max_p; ++i)
{
	if (i == -1)
	{
		wshed_.setTo(Vec3b(255, 255, 255), markers_ == i);
	}
	else if (i <= 0 || i > compCount)
	{
		wshed_.setTo(Vec3b(0, 0, 0), markers_ == i);
	}
	else {
		wshed_.setTo(colorTab[i - 1], markers_ == i);
	}
}

4.一个填充空洞的思路:

对二值图像取反,则连通域表示的则是原来的孔洞及背景,然后计算每个连通域面积,小于一定阈值则将其置零,完成之后再取反,优势:速度较快,实现如下:

Mat img_IN = ~img_bw;
vector<vector<Point>>contours;
vector<Vec4i>hierachy;
findContours(img_IN, contours, hierachy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
int nums = contours.size();
vector<int>areas(nums);
int i = 0;
for (; i < nums; ++i)
{
	areas[i] = round(contourArea(contours[i]));
}
vector<int>areas_(areas);
sort(areas_.begin(), areas_.end());
int area_th = areas_[nums / 2] * 188;
//int area_th = src.cols*src.rows / 1600;
i = 0;
Mat mask(src.size(), CV_8UC1, Scalar::all(0));
for (; i < nums; ++i)
{
	if (areas[i] > area_th)
	{
		drawContours(mask, contours, i, Scalar(255), -1);
	}
}
dst = ~mask;
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值