• OpenCV细化算法简单解析


    细化算法它的原理也很简单:

          我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点。假设一个像素点,我们定义该点为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就满足。

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

    细化算法代码如下:

    以上部分原理是转载(迈克老狼2012)http://www.cnblogs.com/mikewolf2002/p/3321732.html

    接下来发布的是在我电脑上通过的测试代码:

    编译环境为win7+VS2015+OpenCV3.0

      1 void cvThin(IplImage* src, IplImage* dst, int iterations)
      2 {
      3     //此时的src是一个二值化的图片  
      4     CvSize size = cvGetSize(src);
      5     cvCopy(src, dst);
      6 
      7     int n = 0, i = 0, j = 0;
      8     for (n = 0; n < iterations; n++)//开始进行迭代  
      9     {
     10         IplImage* t_image = cvCloneImage(dst);
     11         for (i = 0; i < size.height; i++)
     12         {
     13             for (j = 0; j < size.width; j++)
     14             {
     15                 if (CV_IMAGE_ELEM(t_image, uchar, i, j) == 1)
     16                 {
     17                     int ap = 0;
     18                     int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j);
     19                     int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j + 1);
     20                     if (p2 == 0 && p3 == 1)
     21                     {
     22                         ap++;
     23                     }
     24 
     25                     int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j + 1);
     26                     if (p3 == 0 && p4 == 1)
     27                     {
     28                         ap++;
     29                     }
     30 
     31                     int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j + 1);
     32                     if (p4 == 0 && p5 == 1)
     33                     {
     34                         ap++;
     35                     }
     36 
     37                     int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j);
     38                     if (p5 == 0 && p6 == 1)
     39                     {
     40                         ap++;
     41                     }
     42 
     43                     int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j - 1);
     44                     if (p6 == 0 && p7 == 1)
     45                     {
     46                         ap++;
     47                     }
     48 
     49                     int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j - 1);
     50                     if (p7 == 0 && p8 == 1)
     51                     {
     52                         ap++;
     53                     }
     54 
     55                     int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j - 1);
     56                     if (p8 == 0 && p9 == 1)
     57                     {
     58                         ap++;
     59                     }
     60                     if (p9 == 0 && p2 == 1)
     61                     {
     62                         ap++;
     63                     }
     64 
     65                     if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7)
     66                     {
     67                         if (ap == 1)
     68                         {
     69                             if (!(p2 && p4 && p6))
     70                             {
     71                                 if (!(p4 && p6 && p8))
     72                                 {
     73                                     CV_IMAGE_ELEM(dst, uchar, i, j) = 0;//设置目标图像中像素值为0的点  
     74                                 }
     75                             }
     76                         }
     77                     }
     78 
     79                 }
     80             }
     81         }
     82 
     83         cvReleaseImage(&t_image);
     84 
     85         t_image = cvCloneImage(dst);
     86         for (i = 0; i < size.height; i++)
     87         {
     88             for (int j = 0; j < size.width; j++)
     89             {
     90                 if (CV_IMAGE_ELEM(t_image, uchar, i, j) == 1)
     91                 {
     92                     int ap = 0;
     93                     int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j);
     94                     int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j + 1);
     95                     if (p2 == 0 && p3 == 1)
     96                     {
     97                         ap++;
     98                     }
     99                     int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j + 1);
    100                     if (p3 == 0 && p4 == 1)
    101                     {
    102                         ap++;
    103                     }
    104                     int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j + 1);
    105                     if (p4 == 0 && p5 == 1)
    106                     {
    107                         ap++;
    108                     }
    109                     int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j);
    110                     if (p5 == 0 && p6 == 1)
    111                     {
    112                         ap++;
    113                     }
    114                     int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j - 1);
    115                     if (p6 == 0 && p7 == 1)
    116                     {
    117                         ap++;
    118                     }
    119                     int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j - 1);
    120                     if (p7 == 0 && p8 == 1)
    121                     {
    122                         ap++;
    123                     }
    124                     int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j - 1);
    125                     if (p8 == 0 && p9 == 1)
    126                     {
    127                         ap++;
    128                     }
    129                     if (p9 == 0 && p2 == 1)
    130                     {
    131                         ap++;
    132                     }
    133                     if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7)
    134                     {
    135                         if (ap == 1)
    136                         {
    137                             if (p2*p4*p8 == 0)
    138                             {
    139                                 if (p2*p6*p8 == 0)
    140                                 {
    141                                     CV_IMAGE_ELEM(dst, uchar, i, j) = 0;
    142                                 }
    143                             }
    144                         }
    145                     }
    146                 }
    147 
    148             }
    149 
    150         }
    151         cvReleaseImage(&t_image);
    152     }
    153 
    154 }

    细化结果因为我的图不方便展示,大家可以参考迈克老狼2012的哦,效果是很像的,他采用的mat类,而我采用的iplimage类。

  • 相关阅读:
    BZOJ2705[SDOi2012]Longge的问题
    Ubuntu 18.04 打不开1.1.0版本网易云音乐的解决方法汇总
    BZOJ3295[CQOI2011]动态逆序对(CDQ分治)
    hdu-4638-Group(树状数组)
    hdu-3333-Turing Tree(树状数组)
    UVA-11983-Weird Advertisement(线段树+扫描线)[求矩形覆盖K次以上的面积]
    ZOJ-3597-Hit the Target!(线段树+扫描线)
    POJ-1177-Picture(线段树+扫描线+离散化)[矩形周长并]
    POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]
    LightOJ 1135(线段树)
  • 原文地址:https://www.cnblogs.com/My-code-z/p/5712524.html
Copyright © 2020-2023  润新知