细化算法

程序编码参考经典的细化或者骨架算法文章:

T. Y. Zhang and C. Y. Suen, “A fast parallel algorithm for thinning digital patterns,” Comm. ACM, vol. 27, no. 3, pp. 236-239, 1984.

它的原理也很简单:

      我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。假设一个像素点,我们定义该点为p1,则它的八邻域点p2->p9位置如下图所示,该算法考虑p1点邻域的实际情况,以便决定是否删除p1点。假设我们处理的为二值图像,背景为黑色,值为0,要细化的前景物体像素值为1。

image

算法的描述如下。

首先复制源图像到目地图像,然后建立一个临时图像,接着执行下面操作:

1. 把目地图像复制给临时图像,对临时图像进行一次扫描,对于不为0的点,如果满足以下四个条件,则在目地图像中删除该点(就是设置该像素为0),这里p2,…,p9是对应位置的像素灰度值(其为1或者0)。

   a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

    大于等于2会保证p1点不是端点或孤立点,因为删除端点和孤立点是不合理的,小于等于6保证p1点是一个边界点,而不是一个内部点。等于0时候,周围没有等于1的像素,所以p1为孤立点,等于1的时候,周围只有1个灰度等于1的像素,所以是端点(注:端点是周围有且只能有1个值为1的像素)。

image

 

   b. p2->p9的排列顺序中,01模式的数量为1,比如下面的图中,有p2p3 => 01, p6p7=>01,所以该像素01模式的数量为2。

image

     之所以要01模式数量为1,是要保证删除当前像素点后的连通性。比如下面的图中,01模式数量大于1,如果删除当前点p1,则连通性不能保证。

image

    c. P2*p4*p6 = 0

    d. p4*p6*p8 = 0

image

      在第一次子迭代中,只是移去东南的边界点,而不考虑西北的边界点,注意p4,p6出现了2次,就是说它们有一个为0,则c,d就满足。

2. 接下来,把目地图像再次复制到临时图像,接着对临时图像进行一次扫描,如果不为0的点它的八邻域满足以下4个条件,则在目地图像中删除该点(就是设置该像素为0)

    a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

    b. p2->p9的排列顺序中,01模式的数量(这里假设二值图非零值为1)为1。

    c. p2*p4*p8 = 0

    d. p2*p6*p8 = 0

image

第二次迭代则相反,会移去西北的边界点,注意p2,p8出现了2次,就是说它们有一个为0,则c,d就满足。

执行完上面两个步骤后,就完成了一次细化算法,我们可以多次迭代执行上述过程,得到最终的骨架图。

细化算法代码如下:

void gThin::cvThin(cv::Mat& src, cv::Mat& dst, int intera)
    {
    if(src.type()!=CV_8UC1)
        {
        printf("只能处理二值或灰度图像\n");
        return;
        }
    //非原地操作时候,copy src到dst
    if(dst.data!=src.data)
        {
        src.copyTo(dst);
        }

    int i, j, n;
    int width, height;
    width = src.cols -1;
    //之所以减1,是方便处理8邻域,防止越界
    height = src.rows -1;
    int step = src.step;
    int  p2,p3,p4,p5,p6,p7,p8,p9;
    uchar* img;
    bool ifEnd;
    int A1;
    cv::Mat tmpimg;
    //n表示迭代次数
    for(n = 0; n<intera; n++)
        {
        dst.copyTo(tmpimg);
        ifEnd = false;
        img = tmpimg.data;
        for(i = 1; i < height; i++)
            {
            img += step;
            for(j =1; j<width; j++)
                {
                uchar* p = img + j;
                A1 = 0;
                if( p[0] > 0)
                    {
                    if(p[-step]==0&&p[-step+1]>0) //p2,p3 01模式
                        {
                        A1++;
                        }
                    if(p[-step+1]==0&&p[1]>0) //p3,p4 01模式
                        {
                        A1++;
                        }
                    if(p[1]==0&&p[step+1]>0) //p4,p5 01模式
                        {
                        A1++;
                        }
                    if(p[step+1]==0&&p[step]>0) //p5,p6 01模式
                        {
                        A1++;
                        }
                    if(p[step]==0&&p[step-1]>0) //p6,p7 01模式
                        {
                        A1++;
                        }
                    if(p[step-1]==0&&p[-1]>0) //p7,p8 01模式
                        {
                        A1++;
                        }
                    if(p[-1]==0&&p[-step-1]>0) //p8,p9 01模式
                        {
                        A1++;
                        }
                    if(p[-step-1]==0&&p[-step]>0) //p9,p2 01模式
                        {
                        A1++;
                        }
                    p2 = p[-step]>0?1:0;
                    p3 = p[-step+1]>0?1:0;
                    p4 = p[1]>0?1:0;
                    p5 = p[step+1]>0?1:0;
                    p6 = p[step]>0?1:0;
                    p7 = p[step-1]>0?1:0;
                    p8 = p[-1]>0?1:0;
                    p9 = p[-step-1]>0?1:0;
                    if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7  &&  A1==1)
                        {
                        if((p2==0||p4==0||p6==0)&&(p4==0||p6==0||p8==0)) //p2*p4*p6=0 && p4*p6*p8==0
                            {
                            dst.at<uchar>(i,j) = 0; //满足删除条件,设置当前像素为0
                            ifEnd = true;
                            }
                        }
                    }
                }
            }
        
        dst.copyTo(tmpimg);
        img = tmpimg.data;
        for(i = 1; i < height; i++)
            {
            img += step;
            for(j =1; j<width; j++)
                {
                A1 = 0;
                uchar* p = img + j;
                if( p[0] > 0)
                    {
                    if(p[-step]==0&&p[-step+1]>0) //p2,p3 01模式
                        {
                        A1++;
                        }
                    if(p[-step+1]==0&&p[1]>0) //p3,p4 01模式
                        {
                        A1++;
                        }
                    if(p[1]==0&&p[step+1]>0) //p4,p5 01模式
                        {
                        A1++;
                        }
                    if(p[step+1]==0&&p[step]>0) //p5,p6 01模式
                        {
                        A1++;
                        }
                    if(p[step]==0&&p[step-1]>0) //p6,p7 01模式
                        {
                        A1++;
                        }
                    if(p[step-1]==0&&p[-1]>0) //p7,p8 01模式
                        {
                        A1++;
                        }
                    if(p[-1]==0&&p[-step-1]>0) //p8,p9 01模式
                        {
                        A1++;
                        }
                    if(p[-step-1]==0&&p[-step]>0) //p9,p2 01模式
                        {
                        A1++;
                        }
                    p2 = p[-step]>0?1:0;
                    p3 = p[-step+1]>0?1:0;
                    p4 = p[1]>0?1:0;
                    p5 = p[step+1]>0?1:0;
                    p6 = p[step]>0?1:0;
                    p7 = p[step-1]>0?1:0;
                    p8 = p[-1]>0?1:0;
                    p9 = p[-step-1]>0?1:0;
                    if((p2+p3+p4+p5+p6+p7+p8+p9)>1 && (p2+p3+p4+p5+p6+p7+p8+p9)<7  &&  A1==1)
                        {
                        if((p2==0||p4==0||p8==0)&&(p2==0||p6==0||p8==0)) //p2*p4*p8=0 && p2*p6*p8==0
                            {
                            dst.at<uchar>(i,j) = 0; //满足删除条件,设置当前像素为0
                            ifEnd = true;
                            }
                        }
                    }
                }
            }

        //如果两个子迭代已经没有可以细化的像素了,则退出迭代
        if(!ifEnd) break;
        }

    }

下面是三次细化的结果,可以看出在垂直方向H变短了,感觉这是不完美的地方。

image

下面我们对两个汉字进行5次迭代细化,结果如下:

imageimage


原文地址:https://www.cnblogs.com/mikewolf2002/p/3321732.html

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值