C++ 两遍扫描法 八领域实现对矩阵连通区域的识别

首先,输入的矩阵binImg连通区域都用1表示,剩余的都是0
函数实现:

//两遍扫描法 八领域
void CPointCloud::Two_Pass( cv::Mat binImg, cv::Mat &lableImg)    //两遍扫描法
{
	if (binImg.empty() ||
		binImg.type() != CV_8UC1)
	{
		return;
	}

	// 第一个通路
	lableImg.release();
	lableImg = binImg;

	int label = 1; 
	std::vector<int> labelSet;
	labelSet.push_back(0);  
	labelSet.push_back(1);  

	int rows = binImg.rows - 1;
	int cols = binImg.cols - 1;
	uchar *data = lableImg.ptr<uchar>(0);
	if (data[0]==1)
	{
		labelSet.push_back(++label);
		data[0] = label; 
		labelSet[label] = label;
	}
	for (int i=1;i<lableImg.cols;i++)
	{
		if (data[i] == 1)
		{
			if (data[i-1] != 0)
			{
				data[i] = label;
			}
			else
			{
				labelSet.push_back(++label);
				data[i] = label; 
				labelSet[label] = label;
			}
		}
	}
	for (int i=1;i<lableImg.rows;i++)
	{
		uchar *ndatafront = lableImg.ptr<uchar>(i-1);
		uchar *ndata = lableImg.ptr<uchar>(i);
		if (ndatafront[0]!=0)
		{
			ndata[0]=ndatafront[0];
		}
		else
		{
			labelSet.push_back(++label);
			ndata[0] = label; 
			labelSet[label] = label;
		}

	}

	for (int i = 1; i < rows+1; i++)
	{
		uchar* data_preRow = lableImg.ptr<uchar>(i-1);
		uchar* data_curRow = lableImg.ptr<uchar>(i);
		for (int j = 1; j < cols+1; j++)
		{
			if (data_curRow[j] == 1)
			{
				std::vector<int> neighborLabels;
				neighborLabels.reserve(2);
				int leftPixel = data_curRow[j-1];
				int upPixel = data_preRow[j];
				int upleftpixel = data_preRow[j-1];
				if ( leftPixel >1)
				{
					neighborLabels.push_back(leftPixel);
				}
				if (upPixel >1)
				{
					neighborLabels.push_back(upPixel);
				}
				if (upleftpixel >1)
				{
					neighborLabels.push_back(upleftpixel);
				}
				if (neighborLabels.empty())
				{
					labelSet.push_back(++label);  // 不连通,标签+1
					data_curRow[j] = label;
					labelSet[label] = label;
				}
				else
				{
					std::sort(neighborLabels.begin(), neighborLabels.end());
					int smallestLabel = neighborLabels[0];  
					data_curRow[j] = smallestLabel;

					// 保存最小等价表
					for (size_t k = 1; k < neighborLabels.size(); k++)
					{
						int tempLabel = neighborLabels[k];
						int& oldSmallestLabel = labelSet[tempLabel];
						if (oldSmallestLabel > smallestLabel)
						{							
							labelSet[oldSmallestLabel] = smallestLabel;
							oldSmallestLabel = smallestLabel;
						}						
						else if (oldSmallestLabel < smallestLabel)
						{
							labelSet[smallestLabel] = oldSmallestLabel;
						}
					}
				}				
			}
		}
	}

	// 更新等价对列表
	// 将最小标号给重复区域
	for (size_t i = 2; i < labelSet.size(); i++)
	{
		int curLabel = labelSet[i];
		int preLabel = labelSet[curLabel];
		while (preLabel != curLabel)
		{
			curLabel = preLabel;
			preLabel = labelSet[preLabel];
		}
		labelSet[i] = curLabel;
	}  

	for (int i = 0; i < rows; i++)
	{
		uchar* data = lableImg.ptr<uchar>(i);
		for (int j = 0; j < cols; j++)
		{
			int pixelLabel = data[j];
			data[j] = labelSet[pixelLabel];	
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值