二值图贴标签算法

/*
    二值图处理 --- 贴标签法
    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);
}





原文地址:https://www.cnblogs.com/xiaomaLV2/p/2269991.html