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

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

一、算法原理

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

1. Two-Pass算法

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

具体流程如下:

图像二值化。

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

第二次按行扫描图像时,将其中具有相等关系的标签 选择里面最小的标签作为它们的标签,即访问已经标记的标签并合并具有相等关系的标签。

2. 种子填充法(Seed Filling)

图像二值化。

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

for (int j = 1; j < cols - 1; j++)

{

if (data[j] == 1)

{

stack> neighborPixels;

neighborPixels.push(std::pair(i, j)); // pixel position:

++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 curPixel = neighborPixels.top();

int curX = curPixel.first;

int curY = curPixel.second;

_lableImg.at(curX, curY) = label;

// pop the top pixel

neighborPixels.pop();

// push the 4-neighbors (foreground pixels)

if (curY != 0 && _lableImg.at(curX, curY - 1) == 1)

{

// left pixel

neighborPixels.push(std::pair(curX, curY - 1));

}

if (curY != cols && _lableImg.at(curX, curY + 1) == 1)

{

// right pixel

neighborPixels.push(std::pair(curX, curY + 1));

}

if (curX != 0 && _lableImg.at(curX - 1, curY) == 1)

{

// up pixel

neighborPixels

相关内容

古风花钿手绘画法
365安卓版

古风花钿手绘画法

⌛ 07-07 👁️ 1412
电话被拦截了怎么解除
365bet官网最新网址

电话被拦截了怎么解除

⌛ 07-05 👁️ 4338
世界杯让球规则?足球让球规则
365安卓版

世界杯让球规则?足球让球规则

⌛ 07-11 👁️ 7507
如何在web上修改邮箱密码
365bet官网最新网址

如何在web上修改邮箱密码

⌛ 07-19 👁️ 8871
路由表学习笔记(一):如何查看路由表和操作路由表
365bet官网最新网址

路由表学习笔记(一):如何查看路由表和操作路由表

⌛ 07-03 👁️ 8837
天猫超市限时抢购在哪里查看?
365安卓版

天猫超市限时抢购在哪里查看?

⌛ 07-02 👁️ 3273