【OpenCV】8邻域种子填充法剔除短连通域的高效算法

//本文档参考种子填充算法描述及C++代码实现(https://www.bbsmax.com/A/amd0AVWzge/)讲解的原理,实现快速种子填充算法,运行效果高。
//具体功能如下:依次扫描每个像素,检测8领域,寻找连通域,删掉面积小于阈值的。
#include <opencv2/opencv.hpp>
#include <cv.h>

using namespace cv;
using namespace std;

#define IMG_MARGIN_GAP_SIZE			3
#define IMG_MINIMUM_ALGO_AREA		30   //保留连通域的面积下限
#define POSITION_OFFSET_SIZE	    8    //8邻域
#define MAX_STK_BIRD_SIZE           4000
#define INIMG_WIDTH                 300
#define INIMG_HEIGHT                720
int position_offset[POSITION_OFFSET_SIZE] = {-INIMG_WIDTH, -INIMG_WIDTH-1,-1, INIMG_WIDTH-1, INIMG_WIDTH, INIMG_WIDTH+1, 1, -INIMG_WIDTH+1};

int init_stk[MAX_STK_BIRD_SIZE];

void SeedFillAlgorithm(Mat &inImg, Mat &outImg) {
	int i, j, k, p, pp;
	uchar *bdata, *bdata_tmp, *cdata; 
	int *stk, stkN; 

	bdata = inImg.data; 
	bdata_tmp = inImg.data + INIMG_WIDTH * (INIMG_HEIGHT-IMG_MARGIN_GAP_SIZE); 
	for (i = 0; i < IMG_MARGIN_GAP_SIZE; i++) 
	{
		for (j = 0; j < INIMG_WIDTH; j++) 
		{
			*bdata++ = *bdata_tmp++ = 0;   //把图像上下边界3像素宽度范围内像素置为0
		}
	}
	bdata_tmp = inImg.data + (INIMG_WIDTH -1)*IMG_MARGIN_GAP_SIZE; 
	for (i = INIMG_HEIGHT-2*IMG_MARGIN_GAP_SIZE; i > 0; i--) 
	{
		for (j = 0; j < (IMG_MARGIN_GAP_SIZE*2); j++) 
		{
			bdata_tmp[j] = 0;              //把图像左右边界3像素宽度范围内的像素置为0
		}
		bdata_tmp += INIMG_WIDTH; 
	}

	cdata = outImg.data; 
	memset(cdata, 0, sizeof(uchar)*INIMG_HEIGHT*INIMG_WIDTH);

	//需要为stk分配空间!
	stk = init_stk;   //memset(stk, 0, sizeof(int)*MAX_STK_BIRD_SIZE);
	

	bdata = inImg.data; 
	for (i = INIMG_WIDTH*IMG_MARGIN_GAP_SIZE; i < INIMG_WIDTH*(INIMG_HEIGHT-IMG_MARGIN_GAP_SIZE); i++)  
	{
		if (bdata[i] == 0) continue; 
		bdata[i] = 0; 
		stk[0] = i; 
		k = 0; 
		stkN = 1; 
		while (1) 
		{
			p = stk[k++]; 
			for (j = POSITION_OFFSET_SIZE-1; j >= 0; j--) 
			{
				pp = p + position_offset[j]; 
				if (bdata[pp] == 0) continue; 
				bdata[pp] = 0; 
				stk[stkN++] = pp; 
			}
			if (k >= stkN) break; 
			if (stkN >= (MAX_STK_BIRD_SIZE-POSITION_OFFSET_SIZE)) break; 
		}
		if (stkN <= IMG_MINIMUM_ALGO_AREA) continue;   //如果8邻域联通总数小于设置的最小面积阈值,不保留。
		for (k = stkN - 1; k >= 0; k--) 
		{
			p = stk[k]; cdata[p] = 1; 
		}
	}
}

//把只有0/1取值的二值图转为0/255取值的二值图
static void binary2To255(Mat &img)
{
	for (int i=0;i<img.rows;i++)	
	{
		for (int j=0;j<img.cols;j++)	
		{
			if (img.data[i*img.cols + j] > 0)	
				img.data[i*img.cols + j] = 255;
		}
	}	
}

int main()
{
	Mat srcImg = imread("G:\\binaryImg\\image1.bmp", 0);
	imshow("in", srcImg);

	Mat dstImg(srcImg.rows, srcImg.cols, CV_8UC1, Scalar(0));;
	SeedFillAlgorithm(srcImg, dstImg);
	binary2To255(dstImg);

	imshow("out", dstImg);
	waitKey(0);

	return 0;
}

处理结果如下: 

 

 

<think>嗯,用户想了解如何使用OpenCV种子填充算法(Seed Fill)来合并图像中的连通域。首先,我需要回忆一下种子填充算法的基本原理。种子填充通常用于区域填充,从给定的种子点开始,向四周扩散,直到满足停止条件。这在计算机图形学中常用于填充封闭区域。 然后,我需要考虑OpenCV中是否有现成的函数来实现这个功能。比如,我知道OpenCV有floodFill函数,它应该能实现类似种子填充的效果。这个函数可以修改图像,填充连通区域,同时可以设置掩膜和填充颜色。可能需要结合循环,遍历图像中的每个像素,当遇到未访问过的前景点时,作为种子进行填充,并标记已访问的区域。 不过,用户提到的是合并连通域,可能需要将不同的连通区域合并成一个。这时候可能需要先找到所有的连通区域,然后通过某种方式将它们合并。或者,可能用户是指将相邻的连通域合并,比如通过膨胀操作后再进行填充,使得原本分离的区域连接起来。需要确认具体的需求。 接下来,示例代码的结构应该包括读取图像,二值化处理,然后应用种子填充。需要注意处理多个连通域的情况,可能需要为每个区域分配不同的标签或颜色。同时,要处理边界问题,避免越界访问。 另外,可能要考虑性能问题,种子填充算法在大的图像上可能会比较慢,特别是递归实现的话。OpenCV的floodFill可能已经优化过,所以应该优先使用内置函数。同时,掩膜的使用可以帮助限制填充区域,提高效率。 用户可能还需要了解如何在实际应用中使用这种方法,比如在图像分割或对象检测中合并相邻的区域。可能需要结合形态学操作,如膨胀或腐蚀,来预处理图像,使得连通域更容易合并。 最后,要确保代码正确,语法无误,并且注释清晰,方便用户理解每一步的作用。同时,需要验证示例代码是否真的能达到合并连通域的效果,可能需要测试不同的图像情况,比如多个分离的区域经过处理后是否被正确合并。</think>要使用OpenCV种子填充算法合并连通域,可以通过以下步骤实现: ### 实现步骤 1. **二值化预处理**:将图像转换为二值图像以分离前景和背景 2. **标记已访问区域**:创建与原图同尺寸的掩膜矩阵记录填充状态 3. **遍历像素点**:逐像素扫描,发现未标记的前景点时触发种子填充 4. **泛洪填充**:使用`floodFill()`向四邻域/八邻域扩散,标记相同连通域 5. **区域合并**:通过形态学操作预处理可合并相邻区域 ```python import cv2 import numpy as np def merge_connected_areas(img_path): # 读取并二值化图像 img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) _, bin_img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 创建掩膜并初始化 h, w = bin_img.shape mask = np.zeros((h+2, w+2), np.uint8) # 需要+2边界 # 合并处理后的图像 result = bin_img.copy() # 遍历所有像素 for y in range(h): for x in range(w): if mask[y+1, x+1] == 0 and bin_img[y, x] == 255: # 执行泛洪填充,修改填充颜色可区分不同区域 cv2.floodFill(result, mask, (x,y), 255, loDiff=(5,)*3, upDiff=(5,)*3, flags=4|(255 << 8)|cv2.FLOODFILL_MASK_ONLY) return result # 使用示例 merged = merge_connected_areas("input.png") cv2.imwrite("merged_result.png", merged) ``` ### 关键参数说明 1. `loDiff/upDiff`:控制颜色/亮度差异的容忍度 2. `flags=4`:4邻域填充(8邻域使用8) 3. `FLOODFILL_MASK_ONLY`:仅修改掩膜不修改原图[^1]
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值