二值化后的图像为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);
}
//对二值图进行分析,输出图像深度可通过参数设置
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);
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);
}
}
对二值图像取反,则连通域表示的则是原来的孔洞及背景,然后计算每个连通域面积,小于一定阈值则将其置零,完成之后再取反,优势:速度较快,实现如下:
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;