输入一张二值图,输出图像中的各个连通域
连通域分析函数
int Imglabelnum = cv::connectedComponents(
cv::InputArrayn image, // 输入一张二值图
cv::OutputArray labels, // 输出标签图(和二值图一样大,每个标签值代表连通域的ID)
int connectivity = 8, // 4连通或是8连通方式
int ltype = CV_32S // 标签值类型(CV_32S or CV_16U)
);
int Imglabelnum = int cv::connectedComponentsWithStats (
cv::InputArrayn image, // 输入一张二值图
cv::OutputArray labels, // 输出标签图(和二值图一样大,每个标签值代表连通域的ID)
cv::OutputArray stats, // 状态矩阵
cv::OutputArray centroids, // 各个连通域的中心点:
int connectivity = 8, // 4连通或是8连通方式
int ltype = CV_32S // 标签值类型(CV_32S or CV_16U)
);
其中:
Imglabelnum 表示连通域的个数;
stats包含了一些信息:
stats.at<int>(i, CC_STAT_AREA) //连通域的面积
double left = stats.at<int>(i, CC_STAT_LEFT); //连通域的boundingbox的最左边
double top = stats.at<int>(i, CC_STAT_TOP); //连通域的boundingbox的最上边
double width= stats.at<int>(i, CC_STAT_WIDTH); //连通域的宽
double height stats.at<int>(i, CC_STAT_HEIGHT); //连通域的高
各个连通域的中心点获取方式(i表示连通域的ID):
Point2f center;
center.x = Imgcentriods.at<double>(i, 0);
center.y = Imgcentriods.at<double>(i, 1);
注意:背景点,也就是二值图像中像素值为0的点的标签值为0
使用示例
cv::Mat lable;
cv::Mat labels, stats, centroids;
//连通域计算
int nccomps = cv::connectedComponentsWithStats(
imBin, //二值图像
labels, //和原图一样大的标记图
stats, //nccomps×5的矩阵 表示每个连通区域的外接矩形和面积(pixel)
centroids //nccomps×2的矩阵 表示每个连通区域的质心
);
float maxArea = (imBin.rows - 1)*(imBin.cols - 1);
for (int y = 0; y < imBin.rows; y++)
{
for (int x = 0; x < imBin.cols; x++)
{
int label = labels.at<int>(y, x);
if (label > 0)
{
//去除面积占比小于3%的连通域
if (stats.at<int>(label, cv::CC_STAT_AREA) / maxArea < 0.03)
imBin.at<uchar>(y, x) = 0;
}
}
}
二值图:
连通域分析后,删除较小连通域后的二值图:
做个形态学闭运算处理:
删除突出部分(注意,删除点不能改变其连通性):