zoukankan      html  css  js  c++  java
  • 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类。

  • 相关阅读:
    阿里DatatX mysql8往 Elasticsearch 7 插入时间数据 时区引发的问题
    通俗易懂 k8s (3):kubernetes 服务的注册与发现
    ReplicaSet 和 ReplicationController 的区别
    使用Go module导入本地包
    k8s之statefulset控制器
    终于成功部署 Kubernetes HPA 基于 QPS 进行自动伸缩
    Atitit drmmr outline org stat vb u33.docx Atitit drmmr outline org stat v0 taf.docx Atitit drmmr out
    Atitit all diary index va u33 #alldiary.docx Atitit alldiaryindex v1 t717 目录 1. Fix 1 2. Diary deta
    Atitit path query 路径查询语言 数据检索语言 目录 1.1. List map >> spel 1 1.2. Html数据 》》Css选择符 1 1.3. Json 》map》
    Atitit prgrmlan topic--express lan QL query lan表达式语言 目录 1. 通用表达语言(CEL) 1 1.1. 8.2 功能概述 1 1.2. Ongl
  • 原文地址:https://www.cnblogs.com/My-code-z/p/5712524.html
Copyright © 2011-2022 走看看