zoukankan      html  css  js  c++  java
  • 二值形态学——腐蚀与膨胀 及 C语言代码实现

     参考文献:数字图像处理(第三版) 何东健 西安电子科技大学出版社

     

    二值形态学中的运算对象是集合, 但实际运算中, 当涉及两个集合时并不把它们看作是互相对等的。 一般设A为图像集合, S为结构元素, 数学形态学运算是用S对A进行操作。 结构元素本身也是一个图像集合, 不过通常其尺寸要比目标图像小得多。 对结构元素可指定一个原点, 将其作为结构元素参与形态学运算的参考点。 原点可包含在结构元素中, 也可不包含在结构元素中, 但运算的结果常不相同。 以下用黑点代表值为1的区域, 白点代表值为0的区域, 运算对于值为1的区域进行。

     

    1.腐蚀

      腐蚀是一种最基本的数学形态学运算。 对给定的目标图像X和结构元素S, 将S在图像上移动, 则在每一个当前位置x, S+x只有3种可能的状态, 如下图所示:

               

    第(1)种情形说明S+x与X相关;

    第(2)种情形说明S+x与X不相关;

    第(3)种情形说明S+x与X只是部分相关。

    因而满足(1)式的点x的全体元素,称该点集为S对X的腐蚀(简称腐蚀, 也称X用S腐蚀),记为

    腐蚀也可以用集合的方式定义:

    该式表明, X用S腐蚀的结果是所有使S平移x后仍在X中的x的集合。 换句话说, 用S来腐蚀X得到的集合是S完全包含在X中时S的原点位置的集合。   

      腐蚀在数学形态学运算中的作用是消除物体边界点、 去除小于结构元素的物体、 清除两个物体间的细小连通等。 如果结构元素取3×3的像素块, 腐蚀将使物体的边界沿周边减少1个像素。

     

    “腐蚀”图解:(腐蚀将图像(区域)缩小了)

     

     

    代码实现:

    【注】二值腐蚀基本运算,背景为黑色,目标为白色。

     1 //二值腐蚀
     2 /*函数参数:
     3     a——待腐蚀的图像
     4     b——腐蚀后的结果
     5     mat[5][5]——结构元素,我这里默认设了5*5的大小
     6 */
     7 void Bi_Corrosion(Mat &a, Mat &b, int mat[5][5])
     8 {
     9     int i, j, k, o;
    10     int rows = a.rows;
    11     int cols = a.cols*a.channels();
    12 
    13     bool flag;
    14 
    15     uchar *dst = b.data;
    16     uchar *src = a.data;
    17     //针对图像中每一个像素位置,判断是否结构元素能填入目标内部
    18     for(i = 2; i < rows-2; i++) {
    19         for(j = 2; j < cols-2; j++) {        
    20             //判断结构元素是否可以在当前点填入目标内部,1为可以,0为不可以
    21             flag = 1;
    22             for(k = -2; k <= 2 && flag; k++) {
    23                 for(o = -2; o <= 2; o++) {
    24                     //如果当前结构元素位置为1,判断与对应图像上的像素点是否为非0
    25                     if(mat[k+2][o+2]) {
    26                         //如果图像当前像素为0,则没有击中该点,不是腐蚀的输出
    27                         if(!*(src+(i+k)*cols+j+o)){
    28                             flag = 0;    break;
    29                         }
    30                     }
    31                 }
    32             }
    33             *(dst+i*cols+j) = flag ? 255 : 0;
    34         }
    35     }
    36 }
    View Code

    2.膨胀

      腐蚀可以看作是将图像X中每一个与结构元素S全等的子集S+x收缩为点x。 反之, 也可以将X中的每一个点x扩大为S+x, 即膨胀运算, 记为。用集合语言定义膨胀运算的定义形式为:

    图示:

     

    【注意】来看下特殊情况: 用B膨胀后,结果向左平移了;而用B图像的反射膨胀后位置不变。

            

      

    对于非对称结构S,膨胀后会使得原图错移,但膨胀不会,总的位置和形状不变,因此膨胀公式也可以写做:

     

    对集合X的膨胀也可以看做是对集合X补集的腐蚀的补集具有对偶特性

    腐蚀和膨胀运算与集合运算的关系如下:

     

    代码实现:

    【注】二值膨胀基本运算,背景为黑色,目标为白色。

     1 //二值膨胀
     2 /*函数参数:
     3     a——待腐蚀的图像
     4     b——腐蚀后的结果
     5     mat——结构元素
     6 */
     7 void Bi_Expansion(Mat &a, Mat &b, int mat[5][5]) {
     8     int i, j, k, o;
     9     int rows = a.rows;
    10     int cols = a.cols*a.channels();
    11     Mat tmp = a.clone();
    12     uchar* src = tmp.data;
    13     //膨胀是对图像中目标补集的腐蚀,因此先求输入图像数据的补集
    14     for(i = 0; i < rows; i++)
    15         for(j = 0; j < cols; j++)
    16             *(src+i*cols+j) = 255 - *(src+i*cols+j);
    17     //膨胀是结构元素的对称集对补集的腐蚀,此处求其反射
    18     for(i = 0; i < 5; i++)
    19         for(j = 0; j <= i; j++)
    20             mat[i][j] = mat[j][i];
    21     bool flag;
    22     uchar* dst = b.data;
    23     //针对图像中每一个像素位置,判断是否结构元素能填入目标内部
    24     for(i = 2; i < rows-2; i++) {
    25         for(j = 2; j < cols-2; j++) {        
    26             //判断结构元素是否可以在当前点填入目标内部,1为可以,0为不可以
    27             flag = 1;
    28             for(k = -2; k <= 2 && flag; k++) {
    29                 for(o = -2; o <= 2; o++) {
    30                     //如果当前结构元素位置为1,判断与对应图像上的像素点是否为非0
    31                     if(mat[k+2][o+2]) {
    32                         if(!*(src+(i+k)*cols+j+o)){//没击中
    33                             flag = 0;    break;
    34                         }
    35                     }
    36                 }
    37             }
    38             *(dst+i*cols+j) = flag ? 255 : 0;
    39         }
    40     }
    41     //用结构元素对称集对目标补集腐蚀后,还要对结构再求一次补集,才是膨胀结构输出
    42     //赋值结构元素腐蚀漏掉的区域,使原图像恢复为二值图像
    43     for(i = 0; i < rows; i++) {
    44         for(j = 0; j < cols; j++) {
    45             *(dst+i*cols+j) = 255 - *(dst+i*cols+j);
    46             if(*(dst+i*cols+j) != 255 && *(dst+i*cols+j) != 0)
    47                 *(dst+i*cols+j) = 0;
    48         }
    49     }
    50 }
    View Code
  • 相关阅读:
    cron表达式
    特殊二叉树和平衡二叉树和树的遍历
    进阶之常见算法和算法题
    原码,反码,补码、移码
    PostgreSQL 大小写问题 一键修改表名、字段名为小写
    ImportError: cannot import name 'PackageFinder' from 'pip._internal.index'
    安装pl/sql developer(内附下载地址)
    oracle plsql的结构
    oracle数据库基本操作
    java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/8697904.html
Copyright © 2011-2022 走看看