连通域分析算法

基于opencv的cv::connectedComponentsWithStats()的连通域分析标记算法:

一、函数介绍:

在OpenCV3中有了新的专门的函数 cv::connectedComponents() 和函数 cv::connectedComponentsWithStats(); 来做连通域分析,如果需要获取连通域的具体状态信息,则用第二种。

函数原型:

int  cv::connectedComponents (
    cv::InputArray image,                // input 8-bit single-channel (binary)
    cv::OutputArray labels,               // output label map
    int             connectivity = 8,     // 4- or 8-connected components
    int             ltype        = CV_32S // Output label type (CV_32S or CV_16U)
    );
int  cv::connectedComponentsWithStats (
    cv::InputArray image,                // input 8-bit single-channel (binary)
    cv::OutputArray labels,               // output label map
    cv::OutputArray stats,                // Nx5 matrix (CV_32S) of statistics:
                                                          // [x0, y0, width0, height0, area0;
                                                          //  ... ; x(N-1), y(N-1), width(N-1),
                                                           // height(N-1), area(N-1)]
    cv::OutputArray centroids,            // Nx2 CV_64F matrix of centroids:
                                                           // [ cx0, cy0; ... ; cx(N-1), cy(N-1)]
    int             connectivity = 8,     // 4- or 8-connected components
    int             ltype        = CV_32S // Output label type (CV_32S or CV_16U)
);

参数解析:
(1) image一般需要是一个二值灰度图像(可以用阈值分割来得到)
(2) labels是一张0到total-1的灰度值的图像,比如背景的灰度值为0,第一块的区域的灰度值为1,第total-1块的灰度值为total-1,具体长这样:
在这里插入图片描述

(3) stats是一个存储连通域的状态信息的二维矩阵[total,5],第一行存储的是背景,后面的每一行代表着一个连通域的信息:[x,y,width,height,area],x,y是连通域的位置,width、height是连通域外接矩形的宽和高,area是连通域的具体的像素个数,也就是连通域的面积。具体长这样:
在这里插入图片描述
(4) centroids返回的也是一个二维数组[total,2],存储着连通域的质点的位置[ cx0, cy0; … ; cx(N-1), cy(N-1)];
(5) connectivity默认为8领域,可以选择为4邻域;

二、实战效果:

原图和阈值分割后:
在这里插入图片描述 在这里插入图片描述
连通域分析后:
在这里插入图片描述

三、C++代码:

//输入一张二值灰度图像ostuImage,和连通域最小面积area_min ,当背景为白色时,需要key=1,“黑白颠倒”才能进行连通域分析
void connectedAnalysis(Mat ostuImage,int area_min ,bool key){
	if (key) {
		bitwise_not(ostuImage, ostuImage);//黑白颠倒
	}
	//imshow("ostuImage_not", ostuImage);

	Mat labels, stats, centroids, img_color;

	int nccomps = connectedComponentsWithStats(ostuImage, labels, stats, centroids);
	cout << "连通区域总数: " << nccomps << endl;

	vector<cv::Vec3b> colors(nccomps + 1);

	colors[0] = Vec3b(0, 0, 0); // 背景为黑色

	for (int i = 1; i < nccomps; i++) {

		colors[i] = Vec3b(rand() % 256, rand() % 256, rand() % 256);//连通域颜色随机
		if (stats.at<int>(i, cv::CC_STAT_AREA) < area_min) //如果小于最小面积,也认为不是连通域,归类到背景为黑色
			colors[i] = Vec3b(0, 0, 0); 
	}

	img_color = Mat::zeros(ostuImage.size(), CV_8UC3);

	for (int y = 0; y < img_color.rows; y++)

		for (int x = 0; x < img_color.cols; x++)
		{
			int label = labels.at<int>(y, x);
			CV_Assert(0 <= label && label <= nccomps);
			img_color.at<cv::Vec3b>(y, x) = colors[label];

		}

	imshow("Labeled map", img_color);
}

main()函数:

#include <opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <ctime>

using namespace cv;
using namespace std;

int ostu(Mat src);//阈值分割函数,上一篇博客有介绍
Mat cutImage(Mat src, int x, int y);//分块的阈值分割函数,上一篇博客有介绍,这里不使用
void connectedAnalysis(Mat ostuImage,int area_min,bool key=1);//连通域分析

int main()
{
	Mat src = imread("C:/Users/***/Desktop/blobs.tif");//读取图像
	if (src.empty()) {
		cout << "error!" << endl;
		return 0;
	}
	imshow("src", src);

	if (src.channels() > 1) {
		cvtColor(src, src, COLOR_RGB2GRAY);
	}

	int k;//阈值
	k = ostu(src);

	Mat ostuImage;//分割图像
	threshold(src, ostuImage, k, 255, THRESH_BINARY);
	imshow("ostuImage", ostuImage);  //背景为白色 

	connectedAnalysis(ostuImage, 50 ,1);

	waitKey(0);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值