zoukankan      html  css  js  c++  java
  • OpenCV学习(13) 细化算法(1)

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

    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("只能处理二值或灰度图像 ");
    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

    程序代码:工程FirstOpenCV11

  • 相关阅读:
    hdu 3790 最短路径问题
    hdu 2112 HDU Today
    最短路问题 以hdu1874为例
    hdu 1690 Bus System Floyd
    hdu 2066 一个人的旅行
    hdu 2680 Choose the best route
    hdu 1596 find the safest road
    hdu 1869 六度分离
    hdu 3339 In Action
    序列化和反序列化
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3321732.html
Copyright © 2011-2022 走看看