• 【数字图像处理】图像细化处理


    图像细化

    细化技术:把一个平面区域简化成图的结构形状表示法
    骨架:一种细化结构,它是目标的重要拓扑描述,具有非常广泛的应用。在图像识别或数据压缩时,经常用细化结构。
    例如:在识别字符之前,往往要先对字符作细化处理,求出字符的细化结构。
    细化的作用:目的将图像的骨架提取出来的同时,保持图像细小部分的连通性,对被处理的图像进行细化有助于突出形状特点和减少冗余信息量。

    细化算法

    细化算法:采取逐次去除边界的方法进行的,不能破化图像的连通性。
    通常选择一组结构元素对,不断在这些结构对中循环,如果所得结果不再变化,则终止迭代过程,随着迭代的进行,集合也不断细化。
    结构对的选择:仅受结构元素不相交的限制(不同的结构对),事实上,我们可以使用同一个结构对,即在不断重复的迭代细化过程使用同一个结构对。
    细化满足的条件:
    1.在细化的过程中,图像应该有规律地缩小;
    2.在图像逐步缩小的过程中,应当使图像的连通性质保持不变。

    细化算法过程详解

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

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


    细化实例编程

    1.首先对图像进行二值化,白色为255,黑色为0。
    2.设置一个3*3的领域S模板。
    3.S模板中各个位置上的取值取决于模板所对应图像中不同位置的像素,如果S模板某一个位置上所对应的像素值为白,模板上该位置赋为0,否则赋为1。
    4.循环所有的前景像素点,对符合如下条件的像素点标记为删除:

    • 2 ≤ N(p1) ≤ 6——N(p1)表示跟P1相邻的8个像素点中,为前景像素点的个数
    • S(P1) = 1——S(P1)表示将p2-p9-p2之间按序前后分别成对值为0、1的个数
    • P2 * P4 * P6 = 0
    • P4 * P6 * P8 = 0

    5.循环所有的前景像素点,对符合如下条件的像素点标记为删除:

    •  2 ≤ N(p1) ≤ 6——N(p1)表示跟P1相邻的8个像素点中,为前景像素点的个数
    •  S(P1) = 1——S(P1)表示将p2-p9-p2之间按序前后分别成对值为0、1的个数
    •  P2 * P4 * P8 = 0
    • P2 * P6 * P8 = 0

     6.如果没有满足的点,则结束细化过程。

    下面:

    Image_Use为目标图像:高120,长180,处理时不考虑边界(四边)
                       
    //背景为黑色,值为0,要细化的前景物体像素值为1。
    int temp[3][3];
    int count = 0,flinsh_flag = 0;
    while(1){
      flinsh_flag = 0;
      for(int i = 1;i<120-1;i++)
      {
              for(int j = 1;j<180-1;j++)    
              {
                      if(Image_Use[i][j] == 255) continue;
                      //第一步初始化模板
                      memset(temp, 0, sizeof(temp));
                      count = 0;
                      //第二步根据模板所对应的像素点,对模板进行赋值
                      //如果S模板某一个位置上所对应的像素值为白,模板上该位置赋为0,否则赋为1
                      if(Image_Use[i][j-1] == 0) temp[1][0] = 1;
                      if(Image_Use[i][j+1] == 0) temp[1][2] = 1;
                      if(Image_Use[i-1][j-1] == 0) temp[0][0] = 1;
                      if(Image_Use[i-1][j+1] == 0) temp[0][2] = 1;
                      if(Image_Use[i-1][j] == 0) temp[0][1] = 1;
                      if(Image_Use[i+1][j-1] == 0) temp[2][0] = 1;
                      if(Image_Use[i+1][j+1] == 0) temp[2][2] = 1;
                      if(Image_Use[i+1][j] == 0) temp[2][1] = 1;    
                      //
                      for(int x = 0;x<3;x++)
                              for(int y = 0;y<3;y++)
                              {      
                                      if(x == 1 && y == 1) continue;
                                      if(temp[x][y] == 1)
                                      count ++;
                              }
                      
                      if(count>=2&&count<=6)
                      { 
                        int ap = 0;
                        if (temp[0][1] == 0 && temp[0][2] == 1) ++ap;
                        if (temp[0][2] == 0 && temp[1][2] == 1) ++ap;
                        if (temp[1][2] == 0 && temp[2][2] == 1) ++ap;
                        if (temp[2][2] == 0 && temp[2][1] == 1) ++ap;
                        if (temp[2][1] == 0 && temp[2][0] == 1) ++ap;
                        if (temp[2][0] == 0 && temp[1][0] == 1) ++ap;
                        if (temp[1][0] == 0 && temp[0][0] == 1) ++ap;
                        if (temp[0][0] == 0 && temp[0][1] == 1) ++ap;
                        if(ap == 1&&((temp[0][1]*temp[1][2]*temp[2][1])== 0)&&((temp[1][2]*temp[2][1]*temp[1][0])== 0))
                        {
                          Image_Use[i][j] = 255;
                          flinsh_flag ++;
                        }
                      }
                      
              }
    }
      if(flinsh_flag == 0) 
      {
        break;
      }
      
      flinsh_flag = 0;
      for(int i = 1;i<120-1;i++)
      {
              for(int j = 1;j<180-1;j++)    
              {
                      if(Image_Use[i][j] == 255) continue;
                      //第一步初始化模板
                       memset(temp, 0, sizeof(temp));
                      count = 0;
                      //第二步根据模板所对应的像素点,对模板进行赋值
                      //如果S模板某一个位置上所对应的像素值为白,模板上该位置赋为0,否则赋为1
                      if(Image_Use[i][j-1] == 0) temp[1][0] = 1;
                      if(Image_Use[i][j+1] == 0) temp[1][2] = 1;
                      if(Image_Use[i-1][j-1] == 0) temp[0][0] = 1;
                      if(Image_Use[i-1][j+1] == 0) temp[0][2] = 1;
                      if(Image_Use[i-1][j] == 0) temp[0][1] = 1;
                      if(Image_Use[i+1][j-1] == 0) temp[2][0] = 1;
                      if(Image_Use[i+1][j+1] == 0) temp[2][2] = 1;
                      if(Image_Use[i+1][j] == 0) temp[2][1] = 1;    
                      //
                      for(int x = 0;x<3;x++)
                              for(int y = 0;y<3;y++)
                              {       
                                      if(x == 1 && y == 1) continue;
                                      if(temp[x][y] == 1)
                                      count ++;
                              }
                       if(count>=2&&count<=6)
                      {    
                        int ap = 0;
                        if (temp[0][1] == 0 && temp[0][2] == 1) ++ap;
                        if (temp[0][2] == 0 && temp[1][2] == 1) ++ap;
                        if (temp[1][2] == 0 && temp[2][2] == 1) ++ap;
                        if (temp[2][2] == 0 && temp[2][1] == 1) ++ap;
                        if (temp[2][1] == 0 && temp[2][0] == 1) ++ap;
                        if (temp[2][0] == 0 && temp[1][0] == 1) ++ap;
                        if (temp[1][0] == 0 && temp[0][0] == 1) ++ap;
                        if (temp[0][0] == 0 && temp[0][1] == 1) ++ap;
                        if(ap == 1&&((temp[0][1]*temp[1][2]*temp[1][0])== 0)&&((temp[0][1]*temp[2][1]*temp[1][0]) == 0))
                        {
                          Image_Use[i][j] = 255;
                          flinsh_flag++;
                        }
                      }
              }
      }
      if(flinsh_flag == 0)
      { 
        break;
      }
    }

     测试结果:

     

     二值化图像粗化处理

    粗化处理可以对图像的二值化补集进行细化后得到。

    refer:

    图像处理细化算法

    C/C++ 图像处理(19)------细化算法

  • 相关阅读:
    JavaScript实现HTML导航栏下拉菜单[悬浮显示]
    Paper Pal:一个中英文论文及其代码大数据搜索平台
    小程序定位地图模块全系列开发教学(超详细)
    简单的个人介绍网页主页面【附代码】
    前端分页功能(通用)
    打造完美写作系统:Gitbook+Github Pages+Github Actions
    移动端布局
    三剑客var,let,const
    包含多个段的程序01 零基础入门学习汇编语言29
    更灵活的定位内存地址的方法01 零基础入门学习汇编语言32
  • 原文地址:https://www.cnblogs.com/-wenli/p/11743999.html
Copyright © 2020-2023  润新知