1. 程式人生 > >【OpenCV】8鄰域種子填充法剔除短連通域的高效演算法

【OpenCV】8鄰域種子填充法剔除短連通域的高效演算法

//本文件參考種子填充演算法描述及C++程式碼實現(https://www.bbsmax.com/A/amd0AVWzge/)講解的原理,實現快速種子填充演算法,執行效果高。
//具體功能如下:依次掃描每個畫素,檢測8領域,尋找連通域,刪掉面積小於閾值的。
#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                500
int position_offset[POSITION_OFFSET_SIZE] = {-INIMG_WIDTH, -INIMG_WIDTH-1,-1, INIMG_WIDTH-1, INIMG_WIDTH, INIMG_WIDTH+1, 1, -INIMG_WIDTH+1};

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);
	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; 
		}
	}
}