opencv连通域分析

博客主要介绍了使用OpenCV进行连通域分析,通过代码展示了分析过程,鼓励读者对代码提出疑问和交流。
摘要由CSDN通过智能技术生成

                                                                    OpenCV连通域分析

连通域分析的原理都大同小异,我就不写了,直接上代码,哪有错的或者不懂得地方,欢迎交流。

#include <opencv2/opencv.hpp>  
#include <iostream>     
using namespace std;
using namespace cv;

typedef struct connectedComponentAnalysis_struct {
	int area;	            //面积
	int perimeter;	        //周长
	float pa_ratio;	        //周长面积比
	Rect boundingRect;      //包围连通域的矩形区域
}CCA_struct;

enum connectedComponentMode_enum {
	CC_FOUR, CC_EIGHT
};

void connectedComponentAnalysis(Mat &input, int cc_mode, connectedComponentAnalysis_struct *&cca, int &cc_num);
/**
@param input    输入,二值图
@param cc_mode  连通域模式  0为4领域,1为8领域
@param cca	    存储连通域信息
@param cc_num	连通域个数
*/

int main()
{
	Mat src = imread("sa2.jpg");
	imshow("src", src);
	Mat src_clone, src_gray, src_bin;
	src_clone = src.clone();
	cvtColor(src_clone, src_gray, CV_RGB2GRAY);
	threshold(src_gray, src_bin, 20, 255, 0);
	imshow("src_bin", src_bin);
	cout << src_bin << endl << endl;//为了便于理解输出该矩阵
	connectedComponentAnalysis_struct *cca;
	int cc_num;
	connectedComponentAnalysis(src_bin, CC_EIGHT, cca, cc_num);
	for (int i = 0; i < cc_num; i++)
	{
		cout << "第" << (i + 1) << "个连通域" << ":  "
			<< "面积:" << cca[i].area
			<< "  周长:" << cca[i].perimeter
			<< "  包围连通域的矩形区域:" << cca[i].boundingRect
			<< "  周长面积比:" << cca[i].pa_ratio << endl;
	}
	waitKey(0);
}

void connectedComponentAnalysis(Mat &input, int cc_mode, connectedComponentAnalysis_struct *&cca, int &cc_num)
{
	cc_num = 0;
	Mat PointLabel = Mat::zeros(input.size(), CV_8UC1);
	compare(input, PointLabel, PointLabel, CMP_EQ);
	//记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表已完成检查 
	PointLabel = (PointLabel / 255) * 2;
	cout << PointLabel << endl << endl;//为了便于理解输出该矩阵
	copyMakeBorder(PointLabel, PointLabel, 1, 1, 1, 1, BORDER_CONSTANT,2);//扩展边界,防止越界
	//定义邻域位置
	std::vector<int> NeighborPointOffset;
	int step = PointLabel.step;                          //int NeighborX = extendSeedGroup.at(k).x + 1 + NeighborPointOffset[n];
	NeighborPointOffset.push_back(-step);						 //                        seed.x-step    
	NeighborPointOffset.push_back(-1);					//四领域 //        seed.x-1        seed.x         seed.x+1
	NeighborPointOffset.push_back(1);							 //                        seed.x+step    
	NeighborPointOffset.push_back(step);
	if (cc_mode == 1)
	{
		NeighborPointOffset.push_back(-step - 1);                //        seed.x-setp-1   seed.x-step    seed.x-step+1                        
		NeighborPointOffset.push_back(-step + 1);	   //八领域  //        seed.x-1        seed.x         seed.x+1                        
		NeighborPointOffset.push_back(step - 1);                 //        seed.x+step-1   seed.x+step    seed.x+step+1                               
		NeighborPointOffset.push_back(step + 1);
	}
	vector<Point2i> NeighborCoordinate;	                    //extendSeedGroup.push_back(extendSeedGroup[k] + NeighborCoordinate[n]);
	NeighborCoordinate.push_back(cv::Point2i(0, -1)); 		         //                             seed.x+0,seed.y-1   
	NeighborCoordinate.push_back(cv::Point2i(-1, 0));		//四领域 //        seed.x-1,seed.y+0    seed.x,seed.y       seed.x+1,seed.y+0
	NeighborCoordinate.push_back(cv::Point2i(1, 0));  		         //                             seed.x+0,seed.y+1   
	NeighborCoordinate.push_back(cv::Point2i(0, 1));
	if (cc_mode == 1)
	{
		NeighborCoordinate.push_back(cv::Point2i(-1, -1));
		NeighborCoordinate.push_back(cv::Point2i(1, -1));      		 //        seed.x-1,seed.y-1    seed.x+0,seed.y-1   seed.x+1,seed.y-1
		NeighborCoordinate.push_back(cv::Point2i(-1, 1));	//八领域 //        seed.x-1,seed.y+0    seed.x,seed.y       seed.x+1,seed.y+0
		NeighborCoordinate.push_back(cv::Point2i(1, 1));	   		 //        seed.x-1,seed.y+1    seed.x+0,seed.y+1   seed.x+1,seed.y+1
	}
	int Neighbor_Mode = 4 + 4 * cc_mode;
	vector<connectedComponentAnalysis_struct>temp_cca;
	//开始检测  
	for (int i = 1; i < PointLabel.rows - 1; ++i)
	{
		uchar* checkLabel = PointLabel.ptr<uchar>(i);
		for (int j = 1; j < PointLabel.cols - 1; ++j)
		{
			if (checkLabel[j] == 0)//值为0的点就是待检查的点,2是已经检查的点
			{
				//********开始该点处的检查**********  
				connectedComponentAnalysis_struct temp_allValue;//用来存储寻找到的连通域的信息
				vector<Point> extendSeedGroup;//堆栈,用于存储生长点  
				extendSeedGroup.push_back(cv::Point2i(j - 1, i - 1));//因为之前图片上下左右边界扩展了1个像素,为了对应原图,横纵坐标都要减1个像素
				checkLabel[j] = 1;
				int perimeter = 0;
				for (int k = 0; k < extendSeedGroup.size(); k++)
				{
					uchar* checkedLabel = PointLabel.ptr<uchar>(extendSeedGroup[k].y + 1);
					for (int n = 0; n < Neighbor_Mode; n++)
					{
						int NeighborX = extendSeedGroup.at(k).x + 1 + NeighborPointOffset[n];

						if (checkedLabel[NeighborX] == 0)//判断领域周围的点是否也为0
						{
							extendSeedGroup.push_back(extendSeedGroup[k] + NeighborCoordinate[n]);//如果值和种子点同样为0,则存入extendSeedGroup
							checkedLabel[NeighborX] = 1;
						}
						else if (checkedLabel[NeighborX] == 2 && n < 4)
							perimeter += 1;
					}
				}
				for (int m = 0; m < extendSeedGroup.size(); m++)
				{
					PointLabel.at<uchar>(extendSeedGroup[m].y + 1, extendSeedGroup[m].x + 1) += 1;//更新PointLabel的记录
				}
				//********结束该点处的检查**********  
				temp_allValue.area = extendSeedGroup.size();
				temp_allValue.perimeter = perimeter;
				temp_allValue.pa_ratio = 1.0*perimeter*perimeter / temp_allValue.area;
				temp_allValue.boundingRect = boundingRect(extendSeedGroup);
				temp_cca.push_back(temp_allValue);
				cc_num++;
			}
		}
	}
	cca = new connectedComponentAnalysis_struct[cc_num];
	for (int i = 0; i < cc_num; i++)
	{
		cca[i] = temp_cca[i];
	}
}

程序结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值