• OpenCV学习(10) 图像的腐蚀与膨胀(1)


    建议大家看看网络视频教程:http://www.opencvchina.com/thread-886-1-1.html 

     

    腐蚀与膨胀都是针对灰度图的形态学操作,比如下面的一副16*16的灰度图。

    clip_image002

    它每个像素对应的值为(每个像素值范围都在0-255之间)为:

    clip_image004

          我们定义一个5*5的结构元素,该结构元素用5*5的矩阵表示,其中为1的单元,表示该单元在结构元素中有效,另外还定义一个锚点,坐标为(2,2),在单元格中用蓝色表示。

    clip_image006

    腐蚀/膨胀的操作就是用结构元素的锚点位置对齐图像的像素,然后从左上角的第一个像素滑动到右下角的最后一个像素。

    在滑动到每个像素时,结构元素中为1的各个坐标格子会与相应的像素对齐。比如滑动到第一个像素时,如下图所示:

    clip_image008

    此时,原图像中对齐的格子,如下图所示。

    clip_image010

           腐蚀操作就是取其中的最小值,代替原素像素值,即image(0,0)的像素值为min(0,1,2,16,32)=0,而膨胀操作则相反,是取最大值代替原像素,即image(0,0)=max(0,1,2,16,32)=32。

    下面我们再看一个例子,当结构元素滑动到image(4,4 ) 位置时候,图像的腐蚀膨胀操作:

    clip_image012

          此时,结构元素对齐的像素如下图所示,对于腐蚀操作,此时image(4,4)应该等于min(36,52,66,67,68,69,70,84,100)=36,而膨胀操作,则是image(4,4)等于max(36,52,66,67,68,69,70,84,100)=100。

    clip_image014

    需要注意下面的一种情况:

    结构元素如下图所示,仍是5*5的十字形状,但锚点位置在(3,3),此时当结构元素在图像中滑动时候,会有一些特殊情况需要注意。

    clip_image016

    比如滑动到图像的(0,0)位置时,结构元素中为1的单元格和图像没有交叉的格子,此时按我的理解,应该保持像素的值不变,但opencv中却不是这样,当腐蚀时,此时(0,0)位置像素值为255,当膨胀时,(0,0)位置像素值为0。

    clip_image018

    下面是我写的简单的腐蚀膨胀函数代码:

    cv::Mat gMophEx::Erode(cv::Mat& img,  cv::Mat  kernel, cv::Point anchor)
    {
    cv::Mat tmpImg;
    img.copyTo(tmpImg);
    int i, j, m, n;
    uchar* p;
    for(i=0; i<img.rows; i++)
    {
    p = tmpImg.ptr<uchar>(i);
    for(j=0; j<img.cols; j++)
    {
    int min = 100000;
    for(m = 0; m < kernel.rows; m++)
    {
    for(n=0; n <kernel.cols; n++)
    {
    if(kernel.data[m*kernel.cols+n]==1)
    {
    //printf("i=%d, j=%d, m=%d,n=%d,tt1=%d, tt2=%d, tt3=%d ",i,j,m,n,j+n-anchor.y,i + m - anchor.x,(i + m - anchor.x)*img.cols + j+n-anchor.y);
    if(j+n-anchor.x < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
    continue;
    //printf("%d ",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
    if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]<min)
    min = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
    }
    }
    }

    if (min < 256)
    {
    p[j] = min;
    }
    else if(min==100000)
    {
    p[j] = 255; //opencv结果是这样,当腐蚀时候,当前像素找不到相应的点,赋予最大值
    }

    }
    }
    return tmpImg;
    }

    cv::Mat gMophEx::Dilate(cv::Mat& img, cv::Mat kernel, cv::Point anchor)
    {
    cv::Mat tmpImg;
    img.copyTo(tmpImg);
    int i, j, m, n;
    uchar* p;
    for(i=0; i<img.rows; i++)
    {
    p = tmpImg.ptr<uchar>(i);
    for(j=0; j<img.cols; j++)
    {
    int max=-1;
    for(m = 0; m < kernel.rows; m++)
    {
    for(n=0; n <kernel.cols; n++)
    {
    if(kernel.data[m*kernel.cols+n]==1)
    {
    //printf("i=%d, j=%d, m=%d,n=%d, tt=%d ",i,j,m,n,(i + m - anchor.x)*img.cols + j+n-anchor.y);
    if(j+n-anchor.y < 0 || j+n-anchor.y >=img.cols || i + m - anchor.x < 0 || i + m - anchor.x >= img.rows)
    continue;
    //printf("%d ",img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]);
    if(img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y]>max)
    max = img.data[(i + m - anchor.x)*img.cols + j+n-anchor.y];
    }
    }
    }

    if (max >= 0)
    {
    p[j] = max;
    }
    else if(max == -1)
    {
    p[j] = 0;
    }
    //PrintMat(tmpImg);
    }
    }
    return tmpImg;
    }

    最后我们对图像进行腐蚀操作,得到新的图像像素值为:

    clip_image020

    膨胀操作后的像素值为:

    image

    程序代码: 工程FirstOpenCV4

  • 相关阅读:
    用户需求与抱怨的理解:重视用户所关注的核心利益
    有效的沟通,从聆听开始
    Forms 身份验证下“诡异”的Cookie 丢失问题
    Q 语言初学者系列:(2)基本数据类型
    Q 语言初学者系列:(1)开门篇
    熟悉的感觉
    将.NET Entity Framework 的 Cache模块移植到JAVA平台
    [JAVA]你见过这样的switch吗?
    网站上图片"另存为" 为什么是 bmp 格式
    KDB+性能分析:内存篇
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3321228.html
Copyright © 2020-2023  润新知