20.OpenCV连通性原理及应用详解

OpenCV连通性原理及应用详解

在图像处理和计算机视觉中,连通性分析是一项基础且重要的技术,用于检测图像中相互连接的像素区域,这些区域通常代表着图像中的独立对象或目标。本文将介绍连通性(Connectivity)的基本原理、常见的连通方式(如 4 连通和 8 连通)、OpenCV 中的相关实现方法以及实际应用场景。

1. 连通性基本原理

在二值图像中,连通性描述的是像素之间是否存在“连接”关系。两种常用的连通性定义如下:

  • 4 连通(4-connected):仅考虑水平和垂直方向上相邻的像素。如果一个像素与其上、下、左、右的像素具有相同的值,则认为它们连通。
  • 8 连通(8-connected):不仅考虑水平和垂直方向,还考虑对角线方向上的邻域。如果一个像素与其周围 8 个像素中的任意一个具有相同的值,则认为它们连通。

连通性分析的核心任务是将图像中所有相互连接的像素归为同一组,通常称为“连通分量”。每个连通分量可以被赋予一个唯一的标签,以便后续处理和分析。

在这里插入图片描述

2. OpenCV 中的连通性分析方法

OpenCV 提供了多种函数来实现连通性分析,其中最常用的函数包括:

2.1 connectedComponents

该函数用于对二值图像进行连通分量标记,并输出一个标签图像。函数原型如下:

int connectedComponents(InputArray image, OutputArray labels, int connectivity = 8, int ltype = CV_32S);
  • image:输入二值图像(非零表示前景)。
  • labels:输出标签图像,每个连通分量的像素赋予相同的标签。
  • connectivity:连通性类型,可以选择 4 或 8(默认 8)。
  • ltype:输出标签图像的数据类型,通常为 CV_32S

该函数返回连通分量的数目(包括背景)。

2.1.1 参考代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main() {
    // 读取灰度图像
    Mat gray = imread("E:/image/rice1.jpg", IMREAD_GRAYSCALE);
    if (gray.empty()) {
        cerr << "图像加载失败!" << endl;
        return -1;
    }
	GaussianBlur(gray, gray, Size(5, 5), 0);

    Mat binary;
    double otsu_thresh_val = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    cout << "Otsu 自动选择的阈值为:" << otsu_thresh_val << endl;

    Mat outlabs=Mat::zeros(binary.size(),CV_32S);
    //包括背景
    int number= connectedComponents(binary, outlabs, 8, CV_32S);
	cout << "number of rice: " << number-1 << endl;   

    imshow("原始灰度图像", gray);
    imshow("Triangle 二值化", binary);

	//显示标签图像
	vector<Vec3b> colors(number);
    //bk color
	colors[0] = Vec3b(0, 0, 0);
	for (int i = 1; i < number; i++) {
		colors[i] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255));
	}
	Mat dst = Mat::zeros(binary.size(), CV_8UC3);
	int w = binary.cols;
	int h = binary.rows;
    for (int row = 0; row < h; row++) {
		for (int col = 0; col < w; col++) {
			int label = outlabs.at<int>(row, col);
			dst.at<Vec3b>(row, col) = colors[label];
		}
    }

	imshow("Connected Components", dst);
    waitKey(0);
    return 0;
}

2.2 connectedComponentsWithStats

在 connectedComponents 的基础上,该函数除了返回连通分量标签外,还计算每个连通分量的统计信息,如区域面积、边界框等。函数原型如下:

int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, OutputArray centroids, int connectivity = 8, int ltype = CV_32S);
  • image:输入的二值图像(CV_8U 类型),像素值必须是 0 或 255。
  • labels:输出的标签图,每个连通区域的像素值相同,不同区域的像素值不同(类型由 ltype 指定)。
  • stats:输出的统计信息矩阵(返回值也就是联通个数x5大小),包含每个连通区域的属性(CV_32S 类型)。每行表示一个连通组件,包括以下列:
    • stats[i, 0]:连通组件的左边界 x 坐标。
    • stats[i, 1]:连通组件的上边界 y 坐标。
    • stats[i, 2]:连通组件的宽度。
    • stats[i, 3]:连通组件的高度。
    • stats[i, 4]:连通组件的像素数量(面积)。
  • centroids:输出的质心坐标矩阵(CV_64F 类型),每个连通区域的中心点坐标 (cx, cy)
  • connectivity:连通性类型,可选值:
    • 4:使用 4 连通性。
    • 8:使用 8 连通性(默认)。
  • ltype:标签图的数据类型,默认为 CV_32S
2.2.1 参考代码:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main() {
    // 读取灰度图像
    Mat gray = imread("E:/image/rice1.jpg", IMREAD_GRAYSCALE);
    if (gray.empty()) {
        cerr << "图像加载失败!" << endl;
        return -1;
    }
    GaussianBlur(gray, gray, Size(5, 5), 0);

    Mat binary;
    double otsu_thresh_val = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    cout << "Otsu 自动选择的阈值为:" << otsu_thresh_val << endl;

    Mat outlabs = Mat::zeros(binary.size(), CV_32S);
    //包括背景
    Mat labels, stats, centroids;
    int nComponents = connectedComponentsWithStats(binary, labels, stats, centroids, 8, CV_32S);
    cout << "连通分量数量(包括背景): " << nComponents << endl;

    imshow("原始灰度图像", gray);
    imshow("Triangle 二值化", binary);
    // 将标签图像转换为彩色图像,方便可视化
    Mat labelImage = Mat::zeros(labels.size(), CV_8UC3);
    RNG rng(12345);
    vector<Vec3b> colors(nComponents);
    colors[0] = Vec3b(0, 0, 0); // 背景为黑色
    for (int i = 1; i < nComponents; i++) {
        colors[i] = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
    }
    for (int r = 0; r < labels.rows; r++) {
        for (int c = 0; c < labels.cols; c++) {
            int label = labels.at<int>(r, c);
            labelImage.at<Vec3b>(r, c) = colors[label];
        }
    }

    // 显示每个连通分量的统计信息(忽略背景)
    for (int i = 1; i < nComponents; i++) {
        int x = stats.at<int>(i, CC_STAT_LEFT);
        int y = stats.at<int>(i, CC_STAT_TOP);
        int width = stats.at<int>(i, CC_STAT_WIDTH);
        int height = stats.at<int>(i, CC_STAT_HEIGHT);
        int area = stats.at<int>(i, CC_STAT_AREA);
		int cx = centroids.at<double>(i, 0);
		int cy = centroids.at<double>(i, 1);

        cout << "组件 " << i << ": 区域大小 = " << area
            << ", 边界框 = [" << x << ", " << y << ", " << width << ", " << height << "]" <<
            ",中心位置:"<<cx<<","<<cy << endl;
		//绘制中心位置
		circle(labelImage, Point(cx, cy), 5, Scalar(255, 0, 0), -1);
		// 绘制边界框
		rectangle(labelImage, Point(x, y), Point(x + width, y + height), Scalar(0, 255, 0), 1);
    }

	imshow("Connected Components", labelImage);
    waitKey(0);
    return 0;
}

在这里插入图片描述

代码先进行滤波然后二值化,在通过联通性检测确定目标的信息。

3. 连通性分析的主要应用

  • 对象计数:通过连通性分析,可以统计图像中独立对象的数量,如细胞计数、车牌检测等。
  • 目标分割:在物体检测和形态学处理中,连通性分析可以用于分割独立的目标区域。例如,在医学图像处理(如细胞检测)、目标跟踪等领域均有应用。
  • 区域分析:通过提取连通分量的统计信息,可以进一步分析目标的形状、大小、位置和质心等特征。
  • 轮廓分析:连通性分析可以结合 findContours 进行轮廓提取,以便进行目标识别、计数等任务。
  • **图像降噪:**在图像预处理中,使用连通性分析可以过滤掉过小的连通区域(如噪声点),提高图像的质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值