• OpenCV16-图像连通域分析



    1.图像连通域分析

    连通域是指图像中具有相同像素值并且位置相邻的像素组成的区域。连通域分析是指在图像中寻找彼此互相独立的连通域并将其标记出来。

    4邻域与8邻域的概念:点 P 0 ( x , y ) P_0(x,y) P0(x,y) 的4邻域为其上下左右4个像素点,其8邻域为上下左右再加上对角线方向的4个点。

    根据两个像素相邻定义方式不同,得到的连通区域也不相同,因此,在分析连通域的同时,一定要声明是在哪种邻域条件下分析得到的结果。

    2.connectedComponents

    OpenCV提供了用于提取图像中不同连通域的 connectedComponent() 函数:

    int connectedComponents(
        InputArray image, 
        OutputArray labels, // 标记不同连通域后的输出图像
        int connectivity,   // 标记连通域时使用的邻域种类,4表示4邻域
        int ltype,   // 输出图像数据类型:CV_32S、CV_16U
        int ccltype  // 标记连通域时使用的算法类型
    );
    
    int connectedComponents(
        InputArray image, 
        OutputArray labels,
        int connectivity = 8, 
        int ltype = CV_32S
    );
    
    enum ConnectedComponentsAlgorithmsTypes {
        CCL_DEFAULT   = -1, // 8邻域使用SAUF、4邻域使用SAUF
        CCL_WU        = 0,  // 8邻域使用BBDT、4邻域使用SAUF
        CCL_GRANA     = 1,  // 8邻域使用BBDT、4邻域使用SAUF
        CCL_BOLELLI   = 2, 
        CCL_SAUF      = 3,  
        CCL_BBDT      = 4, 
        CCL_SPAGHETTI = 5, 
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    该函数用于计算二值图像中连通域的个数,并在图像中不同的连通域用不同的数字标签标记,其中标签0表示图像中的背景色。函数返回图像中连通域的数目。

    示例代码:

    3.connectedComponentsWithStatus

    虽然 connectedComponents() 函数可以实现图像中多个连通域的统计,但是只能通过标签将图像中的不同连通域分开,无法得到更多的统计信息。有时,我们希望得到每个连通域中心位置或者在图像中标记出连通域所在的矩形区域, connectedComponents 便无法完成这个任务。

    OpenCV中提供了 connectedComponentsWithStatus()函数用于在标记出图像中不同连通域的同时统计连通域的位置、面积的信息:

    int connectedComponentsWithStats(
        InputArray image, 
        OutputArray labels, // 标记不同连通域后的输出图像
        OutputArray stats,  // 含有不同连通域统计信息的矩阵,CV_32S。矩阵第i行是标签为i的连通域的统计信息。
        OutputArray centroids, // 每个连通域质心坐标,CV_64F
        int connectivity, // 邻域种类
        int ltype,        // 输出图像数据类型
        int ccltype       // 标记连通域使用算法标志,同connectedComponents函数参数
    );
    
    int connectedComponentsWithStats(
        InputArray image, 
        OutputArray labels,
        OutputArray stats, 
        OutputArray centroids,
        int connectivity = 8, 
        int ltype = CV_32S
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    第三个参数为每个连通域统计信息矩阵:

    enum ConnectedComponentsTypes {
        CC_STAT_LEFT   = 0, // 连通域内最左侧像素的x坐标,它是水平方向上的包含连通域边界框的开始
        CC_STAT_TOP    = 1, // 连通域内最上方像素的y坐标,它是垂直方向上的包含连通域边界框的开始
        CC_STAT_WIDTH  = 2, // 宽
        CC_STAT_HEIGHT = 3, // 高
        CC_STAT_AREA   = 4, // 连通域面积
    #ifndef CV_DOXYGEN
        CC_STAT_MAX    = 5  // 统计信息种类数目,无实际含义
    #endif
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用:stats.at(i, CC_STAT_WIDTH)

    第四个参数为每个连通域的质心坐标,使用:centroids.at(i, 0)取得x坐标,centroids.at(i, 1)取得y坐标。

    示例代码:

    #include 
    #include  // debug no log
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
    	cout << "OpenCV Version: " << CV_VERSION << endl;
    	utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);
    
    	//对图像进行距离变换
    	Mat img = imread("rice.png");
    	if (img.empty())
    	{
    		cout << "请确认图像文件名称是否正确" << endl;
    		return -1;
    	}
    	imshow("原图", img);
    	Mat rice, riceBW;
    
    	//将图像转成二值图像,用于统计连通域
    	cvtColor(img, rice, COLOR_BGR2GRAY);
    	threshold(rice, riceBW, 50, 255, THRESH_BINARY);
    
    	//生成随机颜色,用于区分不同连通域
    	RNG rng(10086);
    	Mat out, stats, centroids;
    	//统计图像中连通域的个数
    	int number = connectedComponentsWithStats(riceBW, out, stats, centroids, 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(rice.size(), img.type());
    	int w = result.cols;
    	int h = result.rows;
    	for (int i = 1; i < number; i++)
    	{
    		// 中心位置
    		int center_x = centroids.at<double>(i, 0);
    		int center_y = centroids.at<double>(i, 1);
    		//矩形边框
    		int x = stats.at<int>(i, CC_STAT_LEFT);
    		int y = stats.at<int>(i, CC_STAT_TOP);
    		int w = stats.at<int>(i, CC_STAT_WIDTH);
    		int h = stats.at<int>(i, CC_STAT_HEIGHT);
    		int area = stats.at<int>(i, CC_STAT_AREA);
    
    		// 中心位置绘制
    		circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);
    		// 外接矩形
    		Rect rect(x, y, w, h);
    		rectangle(img, rect, colors[i], 1, 8, 0);
    		putText(img, format("%d", i), Point(center_x, center_y),
    			FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
    		cout << "number: " << i << "\tarea: " << area << endl;
    	}
    	//显示结果
    	imshow("标记后的图像", img);
    
    	waitKey(0);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    在这里插入图片描述

  • 相关阅读:
    unity 运行时创建一个新的场景
    StringUtils 工具类常用方法汇总 2(截取、去除空白、包含、查询索引)
    Java 基础实战—Bank 项目—实验题目
    Microsoft 10/11 命令行打开系统设置页(WUAP,!WIN32)
    RabbitMQ高可用集群部署
    浅析云边端协同与算力调度在AI视频检测场景中的应用意义
    Sqli-Libs 速通
    论文阅读:GPT-too- A language-model-first approach for AMR-to-text generation Manuel
    计算机网络 实验二 交换机的基本配置
    SpringBoot 整合 Redis 全面教程:从配置到使用
  • 原文地址:https://blog.csdn.net/ArthurHai521/article/details/133862942