http://www.cnblogs.com/xiaomaLV2/archive/2011/12/01/2269991.html
/*
二值圖處理 --- 貼標簽法
f(i,j) 檢測圖像 g(i,j) 標簽圖像初始值為設lab = 0
1. 從左到右從上到下掃描f(i,j)
2. 如果f圖像點(i,j)不為指定的值而回到
看該點(i,j) 的在g圖像的鄰域內的lab值情況
如果值都為0 則lab +=1 , g(i,j) = lab;
如果不為0的值都相同則g(i,j) = lab;
如果不為0的值不同即lab2>lab1 (不會出現三個不同值),g(i,j) = lab1 , 所有lab2的值也都改為lab1 ;lab = lab -1 ;
3.掃描全部g圖終止
*/
#include "stdafx.h"
void cvMark(unsigned char *arry,unsigned char *mask,int nwidth , int nheight , int threshold );
int _tmain(int argc, _TCHAR* argv[])
{
unsigned char arry[36] = {
0 , 1 , 0 , 0 , 0 , 0,
0 , 1 , 0 , 1 , 1 , 0,
0 , 0 , 1 , 0 , 0 , 0,
0 , 0 , 0 , 0 , 0 , 0,
0 , 1 , 1 , 0 , 1 , 1,
0 , 1 , 0 , 1 , 0 , 0
};
puts("原圖");
for (int i = 0; i <6 ; ++i)
{
for (int j = 0; j <6; ++j)
{
printf("%4d",*(arry + i * 6 + j));
}
puts("");
}
puts("貼標簽");
unsigned char data[36];
cvMark(arry,data,6,6,1);
for (int i = 0; i <6 ; ++i)
{
for (int j = 0; j <6; ++j)
{
printf("%4d",*(data + i * 6 + j));
}
puts("");
}
getchar();
return 0;
}
// 8 鄰域標記
void cvMark(unsigned char *arry,int *mask,int nwidth , int nheight , int threshold,int *count )
{
//memset(mask,0,nwidth * nheight);
int label = 0;
int lab1,lab2 = 0 ;
int data[4];
//遍歷順序從左到右,從上到下
for (int i = 0; i< nheight ; ++i)
{
for (int j = 0; j < nwidth ; ++j)
{
//f圖不為threshold跳過
if ( *(arry + i * nwidth + j)!=threshold)
continue;
//掃描該點在g圖鄰域lab值,簡化運算只計算
// i-1,i,j-1 , i+1,j-1
// i-1 , 即可
if ( i-1 < 0 || j -1 < 0)
data[0] = 0;
else
data[0] = *(mask + (i -1) * nwidth + j -1);
if (i-1 < 0)
data[1] =0;
else
data[1] = *(mask + (i-1)*nwidth + j);
if (i-1 < 0 || j+1>nwidth)
data[2] = 0;
else
data[2] = *(mask + (i-1)*nwidth + j+1);
if (j -1 < 0)
data[3] = 0;
else
data[3] = *(mask + i *nwidth + j-1);
lab1 = 0;
lab2 = 0;
for (int k = 0 ;k<4;++k)
{
if (data[k]!=0)
{
if (lab1 ==0)
{
lab1 = data[k];
}
else if(data[k] != lab1)
{
lab2 = data[k];
}
}
}
if (lab1 ==0 && lab2 ==0)
{
// 8 鄰域全為0
label = label +1;
*(mask + i * nwidth + j) = label;
}
else if (lab2 ==0)
{
//8鄰域lab 值相同
*(mask + i * nwidth + j) =lab1;
}
else
{
//8 鄰域lab值不同
//取較小的lab值,大lab值全部復制為小lab值
if (lab1 > lab2)
{
lab1 = lab1 ^ lab2;
lab2 = lab1 ^ lab2;
lab1 = lab1 ^ lab2;
}
*(mask + i * nwidth + j) =lab1;
for (int l = 0 ; l< i*nwidth + j ; ++l)
{
if ( * (mask + l) == lab2)
{
*(mask + l) = lab1;
}
}
label = label - 1 ;
}
}
}
*count = label;
}
/*
函數:area_select
參數:mark -- 貼標簽法得到的標記圖 cvmark得到
img -- 二值圖像
area -- 面積選擇 小於area的將被刪除
nwidth -- 圖像寬度
nheight --- 圖像高度
count --- 連通域個數 由cvmark得到
*/
void area_select( int * mark,unsigned char * img,int area,int nwidth,int nheight,int count)
{
int *acc = (int *)malloc((count+1) * sizeof(int));
memset(acc,0,(count+1) * sizeof(int));
//統計各連通域白點個數
for (int i = 0; i <nheight ;++i)
{
for (int j = 0 ; j<nwidth ;++j)
{
int base =*(mark + i * nwidth + j ) ;
if (base !=0)
{
acc[base]++;
}
}
}
//刪除小於area的連通域
for (int i=0;i<nheight ;++i)
{
for (int j = 0 ; j < nwidth ; ++j)
{
int base = *(mark + i * nwidth + j );
if (base >0 && acc[base] <area)
{
*(img + i * nwidth + j) = 0;
}
}
}
free(acc);
}