1. 膨胀与腐蚀的原理

膨胀与腐蚀是数学形态学在图像处理中最基础的操作。在笔者之前的文章《图像的卷积(滤波)运算(一)——图像梯度》《图像的卷积(滤波)运算(二)——高斯滤波》具体介绍了图像卷积\滤波的具体的概念与操作,图像的膨胀与腐蚀其实也是一种类似的卷积操作。其卷积操作非常简单,对于图像的每个像素,取其一定的邻域,计算最大值/最小值作为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。

2. 膨胀的具体实现

1) OpenCV实现

在OpenCV中实现了图像膨胀的函数dilate(),可以直接调用:

  1. Mat img = imread(imagename, IMREAD_GRAYSCALE);
  2. if (img.empty())
  3. {
  4. fprintf(stderr, "Can not load image %s\n", imagename);
  5. return -1;
  6. }
  7. //OpenCV方法
  8. Mat dilated_cv;
  9. dilate(img, dilated_cv, Mat());

dilate()函数第一个参数表示输入影像,第二个参数表示输出影像,第三个表示一个默认的核,在3X3的范围内寻找最大值。

2) C/C++实现

在一般的图像处理时,图像读写是由专门的组件进行读取的。这这里仍然使用OpenCV进行读取,以免增加复杂性。而在CV::Mat类中,提供了at()函数访问某一行某一列的像素值,可以通过at()函数去访问每一个像素的领域。

与之前OpenCV实现的一样,对于每一个像素,遍历以其像素位置为中心的3X3邻域,取最大值作为新图像对应位置的像素值。

其具体实现如下:

  1. //从文件中读取成灰度图像
  2. const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
  3. Mat img = imread(imagename, IMREAD_GRAYSCALE);
  4. if (img.empty())
  5. {
  6. fprintf(stderr, "Can not load image %s\n", imagename);
  7. return -1;
  8. }
  9. //自定义方法
  10. Mat dilated_my;
  11. dilated_my.create(img.rows, img.cols, CV_8UC1);
  12. for (int i = 0; i < img.rows; ++i)
  13. {
  14. for (int j = 0; j < img.cols; ++j)
  15. {
  16. //uchar minV = 255;
  17. uchar maxV = 0;
  18. //遍历周围最大像素值
  19. for (int yi = i-1; yi <= i+1; yi++)
  20. {
  21. for (int xi = j-1; xi <= j+1; xi++)
  22. {
  23. if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
  24. {
  25. continue;
  26. }
  27. //minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
  28. maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
  29. }
  30. }
  31. dilated_my.at<uchar>(i, j) = maxV;
  32. }
  33. }

3) 验证与结果

为了验证自己的算法是否正确,可以通过把两者膨胀的结果通过compare()函数进行比较。compare()函数会逐个比较两者的像素值,如果相同就会返回255(白色),如果不相同就会返回0(黑色)。整个过程的具体实现如下:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <opencv2\opencv.hpp>
  4. using namespace cv;
  5. using namespace std;
  6. int main()
  7. {
  8. //从文件中读取成灰度图像
  9. const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
  10. Mat img = imread(imagename, IMREAD_GRAYSCALE);
  11. if (img.empty())
  12. {
  13. fprintf(stderr, "Can not load image %s\n", imagename);
  14. return -1;
  15. }
  16. //OpenCV方法
  17. Mat dilated_cv;
  18. dilate(img, dilated_cv, Mat());
  19. //自定义方法
  20. Mat dilated_my;
  21. dilated_my.create(img.rows, img.cols, CV_8UC1);
  22. for (int i = 0; i < img.rows; ++i)
  23. {
  24. for (int j = 0; j < img.cols; ++j)
  25. {
  26. //uchar minV = 255;
  27. uchar maxV = 0;
  28. //遍历周围最大像素值
  29. for (int yi = i-1; yi <= i+1; yi++)
  30. {
  31. for (int xi = j-1; xi <= j+1; xi++)
  32. {
  33. if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
  34. {
  35. continue;
  36. }
  37. //minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
  38. maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
  39. }
  40. }
  41. dilated_my.at<uchar>(i, j) = maxV;
  42. }
  43. }
  44. //比较两者的结果
  45. Mat c;
  46. compare(dilated_cv, dilated_my, c, CMP_EQ);
  47. //显示
  48. imshow("原始", img);
  49. imshow("膨胀_cv", dilated_cv);
  50. imshow("膨胀_my", dilated_my);
  51. imshow("比较结果", c);
  52. waitKey();
  53. return 0;
  54. }

其运行结果如下所示。可以发现最后的比较结果是一张白色的图像,说明自己实现的算法是正确的。

3. 腐蚀的具体实现

同样的办法可以实现图像腐蚀的过程,只要将求局部最大值改成局部最小值就可以了。具体实现过程如下:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <opencv2\opencv.hpp>
  4. using namespace cv;
  5. using namespace std;
  6. int main()
  7. {
  8. //从文件中读取成灰度图像
  9. const char* imagename = "D:\\Data\\imgDemo\\lena.jpg";
  10. Mat img = imread(imagename, IMREAD_GRAYSCALE);
  11. if (img.empty())
  12. {
  13. fprintf(stderr, "Can not load image %s\n", imagename);
  14. return -1;
  15. }
  16. //OpenCV方法
  17. Mat eroded_cv;
  18. erode(img, eroded_cv, Mat());
  19. //自定义方法
  20. Mat eroded_my;
  21. eroded_my.create(img.cols, img.rows, CV_8UC1);
  22. for (int i = 0; i < img.rows; ++i)
  23. {
  24. for (int j = 0; j < img.cols; ++j)
  25. {
  26. uchar minV = 255;
  27. //uchar maxV = 0;
  28. //遍历周围最大像素值
  29. for (int yi = i-1; yi <= i+1; yi++)
  30. {
  31. for (int xi = j-1; xi <= j+1; xi++)
  32. {
  33. if (xi<0||xi>= img.cols|| yi<0 || yi >= img.rows)
  34. {
  35. continue;
  36. }
  37. minV = (std::min<uchar>)(minV, img.at<uchar>(yi, xi));
  38. //maxV = (std::max<uchar>)(maxV, img.at<uchar>(yi, xi));
  39. }
  40. }
  41. eroded_my.at<uchar>(i, j) = minV;
  42. }
  43. }
  44. //比较两者的结果
  45. Mat c;
  46. compare(eroded_cv, eroded_my, c, CMP_EQ);
  47. //显示
  48. imshow("原始", img);
  49. imshow("膨胀_cv", eroded_cv);
  50. imshow("膨胀_my", eroded_my);
  51. imshow("比较结果", c);
  52. waitKey();
  53. return 0;
  54. }

其运行结果如下:

图像的膨胀与腐蚀——OpenCV与C++的具体实现的更多相关文章

  1. Atitit 图像处理—图像形态学(膨胀与腐蚀)

    Atitit 图像处理-图像形态学(膨胀与腐蚀) 1.1. 膨胀与腐蚀1 1.2. 图像处理之二值膨胀及应用2 1.3. 测试原理,可以给一个5*5pic,测试膨胀算法5 1.4. Photoshop ...

  2. 膨胀和腐蚀 - cvErode() 和 cvDilate() 函数实现

    前言 膨胀就是对图中的每个像素取其核范围内最大的那个值,腐蚀就相反.这两个操作常用来突出显示图的某个高亮部分或者昏暗部分以及去噪.本文展示两个分别对图像进行膨胀和腐蚀的例子. 膨胀和腐蚀函数 cvEr ...

  3. OpenCV膨胀与腐蚀

    膨胀与腐蚀 本篇博客主要介绍使用OpenCV中的函数接口实现对一个图片的腐蚀或者膨胀,听起来有点像是对图像进行放大和缩小的意思,如果你也是这样认为,那我只能说你跟我一样肤浅!!在OpenCV中几乎所有 ...

  4. opencv之膨胀与腐蚀

    腐蚀和膨胀 Erosion/Dilation erosion/dilation,用白话说,就是让图像亮的区域收缩和扩张. 原理 我们定义一个卷积核矩阵.这个矩阵可以是任何形状的,但通常而言,是矩形或者 ...

  5. OpenCV——图像处理入门:膨胀与腐蚀、图像模糊、边缘检测

    全部外部依赖项: opencv_aruco341d.lib opencv_bgsegm341d.lib opencv_calib3d341d.lib opencv_bioinspired341d.li ...

  6. OpenCV膨胀和腐蚀示例代码

    #include<cv.h> #include<highgui.h> int main(int argc, char** argv) { IplImage* img = cvL ...

  7. 学习 opencv---(9)形态学图像处理(一):膨胀和腐蚀

    本篇文章中,我们一起探究了图像处理中,最基本的形态学运算--膨胀与腐蚀.浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试.......... 一.理论 ...

  8. paper 76:膨胀、腐蚀、开、闭运算——数字图像处理中的形态学

    膨胀.腐蚀.开.闭运算是数学形态学最基本的变换.本文主要针对二值图像的形态学膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔):腐蚀:把二值图像各1像素连接成分的边界点去掉从而 ...

  9. 膨胀、腐蚀、开、闭(matlab实现)

    膨胀.腐蚀.开.闭运算是数学形态学最基本的变换. 本文主要针对二值图像的形态学 膨胀:把二值图像各1像素连接成分的边界扩大一层(填充边缘或0像素内部的孔): B=[0 1 0      1 1 1   ...

随机推荐

  1. 支持向量机(Support Vector Machine,SVM)—— 线性SVM

      支持向量机(Support Vector Machine,简称 SVM)于 1995 年正式发表,由于其在文本分类任务中的卓越性能,很快就成为机器学习的主流技术.尽管现在 Deep Learnin ...

  2. PdfReader按页将PDF切割成多个PDF

    private MemoryStream GetNewPdfByPageNum(PdfReader pdfReader, int pageNum) { MemoryStream memoryStrea ...

  3. 如何通过get,set方法访问到父类的私有属性

    刚学习继承的时候,总是会有这样的疑问. 子类继承父类时,会继承所有的非私有的属性和方法.那么在用set方法修改父类的私有属性时,怎么没有报空指针异常呢? 后来仔细想过这个问题,既然没有报空指针,那么在 ...

  4. 了解git的命令行使用

    git现在已经是非常大众的版本管理工具了,如果在windows下用vs这种ide,已经可以很简单的点点鼠标就完成大部分工作了. 但是在某些特殊情况用命令行时,还是需要了解很多命令的. 安装 linux ...

  5. 使用bat脚本永久激活Windows系统

    每次重装完系统后,右下角会提示系统未激活,无法进行一些个性化设置. 在这里我自己写了一个bat脚本用于激活Windows系统.(仅供学习) 文件下载: 链接:https://pan.baidu.com ...

  6. SQLServer存储过程自制数据字典

    相信很多小伙伴都对[数据字典]很头疼. 小编刚入职的时候,老大丢一个项目过来,就一个设计文档,数据字典木有,字段说明木有, 全部都需要靠“联系上下文”来猜.所以小伙伴门一定要养成说明字段的习惯哦. 说 ...

  7. 跨域405(Method Not Allowed)问题

    zepot post没有问题,用plupload上传出现了这个错误,options过不去.显示Response for preflight has invalid http status code 4 ...

  8. 识别率很高的java文字识别技术

    java文字识别程序的关键是寻找一个可以调用的OCR引擎.tesseract-ocr就是一个这样的OCR引擎,在1985年到1995年由HP实验室开发,现在在Google.tesseract-ocr ...

  9. 从Android源码修改cpu信息

    cpuinfo 网上的文章都是怎么查看/proc/cpuinfo,一直以为这种东西没法改呢,我还是太天真了./proc/cpuinfo是个文件,只读,想直接写肯定不行的.今天研究了一下,发现它的输出逻 ...

  10. Identity Server 4 预备知识 -- OpenID Connect 简介

    我之前的文章简单的介绍了OAuth 2.0 (在这里: https://www.cnblogs.com/cgzl/p/9221488.html), 还不是很全. 这篇文章我要介绍一下 OpenID C ...