一、连通域分析
连通域分割原理:
邻域分为4邻域和8邻域。如上图所示。当使用连通域分割方法时,需要首先将图像进行二值化处理,在进行连通域的处理。右图为连通域分割两遍法的一个示意图,具体原理可以自行查询,这里只分享实操部分。
连通域分割函数:
connectedComponents(InputArray image, OutputArray labels, int 8, int ltype = cv_325)
image:待标记不同连通域的图像单通道,数据类型必须为CV_8U。
labels:标记不同连通域后的输出图像,与输入图像具有相同的尺寸。
connectivity:标记连通域时使用的邻域种类,4表示4-邻域,8表示8-邻域,默认参数为8。
ltype:输出图像的数据类型,目前支持CV_32S和CV_16U两种数据类型,默认参数为CV_32S。
分割并统计连通域信息的函数:
connectedComponentswithStats(InputArray image, OutputArray labels, outputArray stats,utputArray centroids, connectivity =, int 8, int ltype = cv_32s
image:待标记不同连通域的图像单通道,数据类型必须为CV_8U。
labels:标记不同连通域后的输出图像,与输入图像具有相同的尺寸。
stats:不同连通域的统计信息矩阵,矩阵的数据类型为Cv_32S。矩阵中第i行是标签为i的连通域的统计特性。
centroids:每个连通域的质心坐标,数据类型为CV_64F。
connectivity:标记连通域时使用的邻域种类,4表示4-邻域,8表示8-邻域,默认参数值为8。
ltype:输出图像的数据类型,目前只支持CV_32s和lCV_16U这两种数据类型,默认参数值为CV_328。
分割检测应用案例:
int main() {//读取图片Mat src = imread("图片1.png", IMREAD_ANYCOLOR);if (src.empty()){printf("不能打开空图片");return -1;}//暂存图像二值化的Mat对象Mat src1, src_BW;//将图像进行二值化操作cvtColor(src, src1, COLOR_BGR2GRAY);threshold(src1, src_BW, 50, 255, THRESH_BINARY);//生成随机颜色,用于区分不用连通域RNG rng(10000);Mat out;//统计图像中连通域的个数int number = connectedComponents(src_BW, out, 8, CV_16U);//对图像进行分割vector<Vec3b> colors;for (int i = 0; i < number; i++){//使用均匀分布的随机数确定颜色Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));colors.push_back(vec3);}//使用不同的颜色连通域标注//新建一个空白矩阵Mat result = Mat::zeros(src1.size(), src.type());int w = result.cols;int h = result.rows;//开始标注,逐像素点标注for (int row = 0; row < h; row++){for (int col = 0; col < w; col++){int label = out.at<uint16_t>(row, col);//如果为背景,则不改变if (label ==0){continue;}result.at<Vec3b>(row, col) = colors[label];}}imshow("123", result);//统计连通域信息Mat stats, centorids;number = connectedComponentsWithStats(src_BW, out, stats, centorids, 8, CV_16U);//对图像进行分割vector<Vec3b> colors_new;for (int i = 0; i < number; i++){//使用均匀分布的随机数确定颜色Vec3b vec3 = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));colors_new.push_back(vec3);}//使用不同的颜色连通域标注//开始标注,逐像素点标注for (int i = 1; i < number; i++){//中心位置int center_x = centorids.at<double>(i, 0);int center_y = centorids.at<double>(i, 1);//矩形边框int x = stats.at<int>(i, CC_STAT_LEFT);int y = stats.at<int>(i, CC_STAT_TOP);int h = stats.at<int>(i, CC_STAT_WIDTH);int w = stats.at<int>(i, CC_STAT_HEIGHT);int area = stats.at<int>(i, CC_STAT_AREA);//绘制中心位置circle(src, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);//绘制外接矩形Rect rect(x, y, h, w);rectangle(src, rect, colors_new[i], 1, 8, 0);putText(src, format("%d", i), Point(center_x, center_y), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);cout << "number:" << i << "area:" << area << endl;}imshow("biaoji", src);waitKey(0);return 0;
}