连通域分析算法

基于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;
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
连通域分析算法是一种用于图像处理和计算机视觉中的算法,可以将连续的像素点组成的区域视为一个连通域。下面是一个基于python的实现: ```python import numpy as np def connected_component_labeling(image): # 初始化标签矩阵 labels = np.zeros_like(image) label = 1 # 定义邻域元素 neighbors = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 遍历每个像素 for i in range(image.shape[0]): for j in range(image.shape[1]): # 如果是前景点并且没有被标记过 if image[i, j] == 255 and labels[i, j] == 0: # 进行深度优先搜索(DFS) stack = [(i, j)] while len(stack) > 0: x, y = stack.pop() labels[x, y] = label for dx, dy in neighbors: # 计算相邻像素的坐标 nx, ny = x + dx, y + dy # 如果相邻像素是前景点并且没有被标记过 if nx >= 0 and nx < image.shape[0] and ny >= 0 and ny < image.shape[1] and image[nx, ny] == 255 and labels[nx, ny] == 0: stack.append((nx, ny)) # 给下一个连通域赋值新的标签 label += 1 return labels ``` 该函数接收一个二值图像作为输入,并返回与输入图像大小相同的标签矩阵,其中每个连通域都被赋予一个唯一的整数标签。实现上,该算法使用深度优先搜索(DFS)来遍历所有前景像素,并将它们标记为相同的连通域。在遍历的过程中,我们使用一个栈来记录需要继续搜索的像素。最终,我们对每个连通域赋予一个新的标签,并返回标签矩阵。 下面是一个使用示例: ```python import cv2 # 读取二值图像 image = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE) # 进行连通域分析 labels = connected_component_labeling(image) # 显示标签矩阵 cv2.imshow('Labels', labels.astype('uint8') * 50) cv2.waitKey() ``` 在这个示例中,我们使用OpenCV库来读取一个二值图像,并将其传递给connected_component_labeling函数进行连通域分析。最后,我们将标签矩阵显示出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值