连通域算法的原理及程序实现

本文介绍了图像处理中的连通域算法,包括Two-Pass算法和种子填充法,详细阐述了这两种方法的原理,并提供了C++程序实现4/8连通域分析,有助于理解图像轮廓计算和连通区域分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、算法原理

利用连通区域算法计算图像中的各个轮廓,一般可以分4领域和8领域,如图所示。有两种经典的连通区域分析算法:Two-Pass(两次遍历)和Seed Filling(种子填充)。下面以四连通区域为例,分别介绍两种分析方法的原理。
连通域

1. Two-Pass算法

Two-Pass算法,顾名思义需要两次遍历图像,第一次遍历给图像所有的像素设置一个标记,并记录各个标记属于哪个连通域,第二次遍历将每个像素标记为所属的连通域。

具体流程如下:

  1. 图像二值化。
  2. 第一次按行扫描图像时,图像中的每个像素值从上到下,从左到右扫描,给每一个有效的像素值一个标签label,规则如下:
    (1)如果该像素的4邻域中左边像素值和上边像素值都为0且都没有标签,则给该像素一个新的标签label;
    (2)如果该像素的4邻域中左边像素值或上边像素值有一个为1,则该像素的标签是像素值为1的标签;
    (3)如果该像素的4邻域中左边像素值和上边像素值都为1,且标签相同,则该像素的标签就是此标签;
    (4)如果该像素的4邻域中左边像素值和上边像素值都为1,且标签不同,则把其中较小的标签作为该像素的标签。这样标记完后,会出现一个连通域里有好几个不同标签,将该像素的左边像素的标签和该像素的上边像素的标签记为相等关系。
  3. 第二次按行扫描图像时,将其中具有相等关系的标签 选择里面最小的标签作为它们的标签,即访问已经标记的标签并合并具有相等关系的标签。

2. 种子填充法(Seed Filling)

  1. 图像二值化。
  2. 从上到下,从左到右按行扫描图像,如果像素值为1则执行以下操作:
    (1)把它当作一个种子,并赋予一个新的标签,并将此元素压入栈底;
    (2)判断栈是否为空,如果不空,给该元素标记为前面(1)中的标签,将栈里的元素取出,然后依次访问该元素四邻域中的4个元素,这4个元素中像素值为1的,压入栈中;
    (3)重复步骤3,直到栈为空。
    这三个小步骤(1)(2)(3)构成一个连通域。
  3. 继续扫描图像,重复步骤2。

二、Seed Filling 4连通域的C++程序

int Seed_Filling_4(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
   
	// connected component analysis (4-component)
	// use seed filling algorithm
	// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
	// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
	//
	// foreground pixel: _binImg(x,y) = 1
	// background pixel: _binImg(x,y) = 0
	if (_binImg.empty() ||
		_binImg.type() != CV_8UC1)
	{
   
		return -1;
	}

	_binImg.convertTo(_lableImg, CV_32SC1);

	int label = 1;  // start by 2

	int rows = _binImg.rows - 1;
	int cols = _binImg.cols - 1;
	for (int i = 1; i < rows - 1; i++)
	{
   
		int* data = _lableImg.ptr<int>(i);
		for (int j = 1; j < cols - 1; j++)
		{
   
			if (data[j] == 1)
			{
   
				stack<std::pair<int, int>> neighborPixels;
				neighborPixels.push(std::pair<int, int>(i, j));     // pixel position: <i,j>
				++label;  // begin with a new label
				while (!neighborPixels.empty())
				{
   
					// get the top pixel on the stack and label it with the same label
					std::pair<int, int> curPixel = neighborPixels.top();
					int curX = curPixel.first;
					int curY = curPixel.second;
					_lableImg.at<int>(curX, curY) = label;

					// pop the top pixel
					neighborPixels.pop();

					// push the 4-neighbors (foreground pixels)
					if (curY != 0 && _lableImg.at<int>(curX, curY - 1) == 1)
					{
   // left pixel
						neighborPixels.push(std::pair<int, int>(curX, curY - 1));
					}
					if (curY != cols && _lableImg.at<int>(curX, curY + 1) == 1)
					{
   // right pixel
						neighborPixels.push(std::pair<int, int>(curX, curY + 1));
					}
					if (curX != 0 && _lableImg.at<int>(curX - 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值