经典图像处理算法—区域生长法(功能实现)

记录一下区域生长法的学习过程,区域生长法是基于区域的分割方法,通过算法自动选取或者交互式选取种子点(即单个像素点),并规定所应用的谓词逻辑,将8邻接或4邻接并满足谓词逻辑的点进行合并,不断迭代,直至不满足谓词逻辑时,完成分割。

最开始在实现这个功能的时候,在网上看了一些别人的代码,发现和自己理解的区域生长法有些出入,再此写下自己所理解的算法代码,仅代表个人意见。

代码如下:

/*
* function:	区域生长法; 递归版本
* input:	grayImage 源图灰度图像	
* output:	SegmentImage 分割完成图像(必须传入全黑单通道图像)
* D_value:	谓词逻辑;灰度差值
*/
void SeedPoint_trace(cv::Mat& SegmentImage, cv::Mat grayImage, int r, int c, int D_value, int rows, int cols)
{
	//如果该坐标点未被标记
	if (SegmentImage.at<uchar>(r, c) == 0)
	{
		SegmentImage.at<uchar>(r, c) = 255;
		int Seedvalue = grayImage.at<uchar>(r, c);					//种子点像素值
		for (int i = -1; i <= 1; ++i)
		{
			for (int j = -1; j <= 1; ++j)
			{
				//检测该点是否在图像内
				if (checkInRang(r + i, c + j, rows, cols))
				{
					int NeighborValue = grayImage.at<uchar>(r + i, c + j);	//邻域点像素值
					if (abs(Seedvalue - NeighborValue) <= D_value)
						SeedPoint_trace(SegmentImage, grayImage, r + i, c + j, D_value, rows, cols);
				}
			}
		}
	}
}


/*
* function:	区域生长法; 非递归版本
* input:	grayImage 源图灰度图像
* output:	SegmentImage 分割完成图像(必须传入全黑单通道图像)
* D_value:	谓词逻辑;灰度差值
* pt		初始种子点
*/
void SeedPoint_trace2(cv::Mat& SegmentImage, cv::Mat grayImage, cv::Point pt, int D_value, int rows, int cols)
{
	//标记初始生长点
	SegmentImage.at<uchar>(pt) = 255;
	//定义种子点动态集合
	vector<cv::Point> growPtVec;
	growPtVec.push_back(pt);

	while (!growPtVec.empty())
	{
		cv::Point SeedPt = growPtVec.back();			//返回当前容器最后一个元素
		growPtVec.pop_back();							//弹出最后一个元素

		int SeedValue = grayImage.at<uchar>(SeedPt);	//种子点像素值
		cv::Point CurrPt;								//当前点
		//遍历8邻接
		for (int i = -1; i <= 1; ++i)
		{
			for (int j = -1; j <= 1; ++j)
			{
				CurrPt.x = SeedPt.x + j;
				CurrPt.y = SeedPt.y + i;
				//检测该点是否在图像内并且未被标记
				if (checkInRang(CurrPt.y, CurrPt.x, rows, cols) && SegmentImage.at<uchar>(CurrPt) == 0)
				{
					int NeighborValue = grayImage.at<uchar>(CurrPt);
					if (abs(SeedValue - NeighborValue) <= D_value)
					{
						SegmentImage.at<uchar>(CurrPt) = 255;
						growPtVec.push_back(CurrPt);
					}
				}
			}
		}
	}
}

定义了两种版本:递归版本和非递归版本。递归版本看似很简洁,但其性能和非递归版本比起来相差甚远,而且为了防止递归堆栈溢出,还需要在IDE中自定义堆栈区的大小,个人感觉;递归很巧妙,但并不总是很适用。

总结: 当基于阈值分割得不到理想的结果时可以考虑区域生长法,但是此方法的局限性很大,既要考虑谓词逻辑的选取(灰度、颜色、梯度角度等)和设定(终止条件),也要考虑种子点的选取,自动化程度不是很高。而且当区域与区域之间间隔不明显或者渐变过渡时,也容易导致错误分割。

试验结果:
在这里插入图片描述在这里插入图片描述
代码中未定义函数参考链接:自适应阈值canny边缘检测

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值