图像噪声,通常指图像中除了成像物体之外的其它信息,比如斑点和颗粒,这些额外的错误信息干扰了成像物体的显示,影响成像质量,所以往往需要通过图像滤波(也称为图像去噪)来消除这些噪点。常见的图像滤波算法有均值滤波、高斯滤波、中值滤波、双边滤波、非局部均值滤波,以及近几年火热的基于深度学习的图像滤波等。本章节将详细讲解均值滤波算法的原理,以及C++实现和优化。

首先膜拜一下那些写Opencv代码的大佬们,他们写的代码不仅稳定性良好,运行效率也超级高,很多时候我们费尽心思写了一个相同的算法,发现性能与Opencv的接口函数相比还是差了许多,所以会有一丢丢的心理落差,但是抱着学习的态度,追赶大佬的脚步,精益求精,相信我们自己也是可以的!

均值滤波,也就是计算每一个像素点周围像素点(包括该点)的平均值,作为该像素点滤波之后的值,通常取以该像素点为中心的矩形窗口内的所有像素点来计算平均值,矩形窗口的大小一般为3*3,5*5,9*9,...,(2n+1)*(2n+1)。窗口越大,滤波效果越好,但是图像也变得更加模糊,所以需要根据实际情况设置矩形窗口的大小。比如3*3窗口的均值滤波如下图所示,点(x,y)的滤波值由其周围9个点(包括其自身)计算平均值得到。

图中点(x,y)的滤波值用公式表示为:

对于(2n+1)*(2n+1)窗口,点(x,y)的平均滤波值可根据如下公式计算:

为了解决图像边缘像素点取不到完整矩形窗口的问题,通常先把图像的上、下边界扩充n行,左右边界扩充n列,实际计算时,只计算图像原有像素点的窗口平均值。比如当矩形窗口为3*3,则n的值为1,这种情况下扩充边界的示意图如下图所示:

根据以上原理,基于Opencv和C++的均值滤波实现代码如下:

void blur_mean(Mat src, Mat &dst, int winsize)
{if(winsize&1)   //如果窗口的边不是奇数,则加1使其为奇数,因为只有窗口的边为奇数的时候当前像素点才是窗口的中心点{winsize += 1;}const int winsize_2 = winsize/2;    //winsize_2 就是上述公式中的nconst float winsize_num = winsize*winsize;   //(2n+1)*(2n+1)Mat src_board;//调用Opencv的copyMakeBorder函数扩充边界copyMakeBorder(src, src_board, winsize_2, winsize_2, winsize_2, winsize_2, BORDER_REFLECT);const int row = src_board.rows;   //行const int col = src_board.cols;Mat dst_tmp(src.size(), CV_8UC1);   //列for(int i = winsize_2; i < row-winsize_2; i++)  //行循环,只计算图像的原有行{for(int j = winsize_2; j < col-winsize_2; j++)  //列循环,只计算图像的原有列{float sum = 0.0;//计算每一个像素点周围矩形区域内所有像素点的累加和for(int y = 0; y < winsize; y++){for(int x = 0; x < winsize; x++){sum += src_board.ptr<uchar>(i-winsize_2+y)[j-winsize_2+x];}}//求得累加和之后再求窗口像素的平均值。作为当前像素点的滤波值dst_tmp.ptr<uchar>(i-winsize_2)[j-winsize_2] = (uchar)(sum/winsize_num + 0.5);}}dst_tmp.copyTo(dst);
}

运行以上代码,对一帧1024*1024的图像进行均值滤波,得到的结果如下图所示。可以看到,随着窗口尺寸的增加,滤波图像变得更加模糊,整体耗时也大幅度增加,由此可以判断在滤波的计算过程中,主要耗时点为计算窗口内像素点的累加和。

根据积分图的特点,可以使用积分图来简化矩形窗口内像素累加和的计算,如下图所示,蓝色矩形区域内点的像素累加和,可以使用其四个顶点A、B、C、D的积分值来计算

假设A、B、C、D的积分值分别为I(A)、I(B)、I(C)、I(D),那么蓝色区域的像素累加和可以按照下式计算:

将上述积分图计算矩形区域内像素和的原理应用于均值滤波中,可以大大简化运算。对于每一个像素点,其计算滤波值的计算量由原本的(2n+1)*(2n+1)次加法,简化为2次加法和1次减法。

使用积分图优化加速的均值滤波代码如下:

void blur_mean_integral(Mat src, Mat &dst, int winsize)
{if(winsize&1){winsize += 1;}const int winsize_2 = winsize/2;const float winsize_num = 1.0/(winsize*winsize);Mat src_board;copyMakeBorder(src, src_board, winsize_2, winsize_2, winsize_2, winsize_2, BORDER_REFLECT);Mat integral;Integal_row(src_board, integral);    //计算积分图const int row = src_board.rows;const int col = src_board.cols;dst.create(src.size(), CV_8UC1);for(int i = winsize_2; i < row-winsize_2; i++){for(int j = winsize_2; j < col-winsize_2; j++){//使用矩形区域四个顶点的积分值来计算区域内的x像素累加和float sum = integral.ptr<float>(i+winsize_2)[j+winsize_2] - integral.ptr<float>(i-winsize_2)[j+winsize_2] - integral.ptr<float>(i+winsize_2)[j-winsize_2] + integral.ptr<float>(i-winsize_2)[j-winsize_2];//得到累加和之后再计算平均值dst.ptr<uchar>(i-winsize_2)[j-winsize_2] = (uchar)(sum*winsize_num + 0.5);}}
}

运行以上代码,取窗口大小为21*21,同样对一帧1024*1024的图像进行均值滤波,耗时由535.4 ms减小到6.78 ms,可以看到,整体耗时大大减小。在使用积分图的基础上,再进行SSE指令的优化,可以进一步减小计算耗时:

void blur_mean_integral(Mat src, Mat &dst, int winsize)
{if(winsize&1){winsize += 1;}const int winsize_2 = winsize/2;const float winsize_num = 1.0/(winsize*winsize);Mat src_board;copyMakeBorder(src, src_board, winsize_2, winsize_2, winsize_2, winsize_2, BORDER_REFLECT);Mat integral;Integal_row(src_board, integral);const int row = src_board.rows;const int col = src_board.cols;dst.create(src.size(), CV_8UC1);for(int i = winsize_2; i < row-winsize_2; i++){float *p1 = integral.ptr<float>(i-winsize_2);float *p2 = integral.ptr<float>(i+winsize_2);uchar *p3 = dst.ptr<uchar>(i-winsize_2);int j = winsize_2;for(; j < col-winsize_2-4; j+=4)   //列循环按4列展开,即每次循环同时计算4个点的滤波值{/*float sum = p2[j+winsize_2] - p1[j+winsize_2] - p2[j-winsize_2] + p1[j-winsize_2];p3[j-winsize_2] = (uchar)(sum*winsize_num + 0.5);sum = p2[j+winsize_2+1] - p1[j+winsize_2+1] - p2[j-winsize_2+1] + p1[j-winsize_2+1];p3[j-winsize_2+1] = (uchar)(sum*winsize_num + 0.5);sum = p2[j+winsize_2+2] - p1[j+winsize_2+2] - p2[j-winsize_2+2] + p1[j-winsize_2+2];p3[j-winsize_2+2] = (uchar)(sum*winsize_num + 0.5);sum = p2[j+winsize_2+3] - p1[j+winsize_2+3] - p2[j-winsize_2+3] + p1[j-winsize_2+3];p3[j-winsize_2+3] = (uchar)(sum*winsize_num + 0.5);*///以下的SSE指令代码对应上方的C++代码__m128 a3, a2, a1, a0;//将4个点的同一方向顶点的像素值加载到__m128变量中//a3 : p2[j+winsize_2+3] p2[j+winsize_2+2] p2[j+winsize_2+1] p2[j+winsize_2]//a2 : p1[j+winsize_2+3] p1[j+winsize_2+2] p1[j+winsize_2+1] p1[j+winsize_2]//a1 : p2[j-winsize_2+3] p2[j-winsize_2+2] p2[j-winsize_2+1] p2[j-winsize_2]//a0 : p1[j-winsize_2+3] p1[j-winsize_2+2] p1[j-winsize_2+1] p1[j-winsize_2]a3 = _mm_loadu_ps(&p2[j+winsize_2]);a2 = _mm_loadu_ps(&p1[j+winsize_2]);a1 = _mm_loadu_ps(&p2[j-winsize_2]);a0 = _mm_loadu_ps(&p1[j-winsize_2]);//(a3-a2)+(a0-a1)__m128 sum = _mm_add_ps(_mm_sub_ps(a3, a2), _mm_sub_ps(a0, a1));__m128 winnum = _mm_set1_ps(winsize_num);  //winsize_num winsize_num winsize_num winsize_numsum = _mm_mul_ps(sum, winnum);  //sum中有4个浮点数,winnum中也有4个浮点数,两者对应位置的浮点数相乘__m128i sum_i = _mm_cvtps_epi32(sum);   //四舍五入取整p3[j-winsize_2+3] = (uchar)sum_i.m128i_i32[3];p3[j-winsize_2+2] = (uchar)sum_i.m128i_i32[2];p3[j-winsize_2+1] = (uchar)sum_i.m128i_i32[1];p3[j-winsize_2] = (uchar)sum_i.m128i_i32[0];}for(; j < col-winsize_2; j++){float sum = p2[j+winsize_2] - p1[j+winsize_2] - p2[j-winsize_2] + p1[j-winsize_2];p3[j-winsize_2] = (uchar)(sum*winsize_num + 0.5);}}
}

使用SSE指令优化之后,同样对1024*1024的图像,取窗口21*21进行滤波,耗时由6.78 ms减少到3.98 ms。由此可知还是有一定优化效果的。

数字图像处理之均值滤波相关推荐

  1. 领域平均法matlab代码实验,数字图像处理邻域平均法滤波实验报告matlab实现.doc...

    数字图像处理邻域平均法滤波实验报告matlab实现 数字图像处理 实验报告 实验三 邻域平均法滤波 学号 姓名 实验三 邻域平均法滤波 一.实验内容 选取噪声较明显的图像,分别采用3*3.5*5.7* ...

  2. 数字图像处理之平滑滤波

    数字图像处理之平滑滤波                                          by方阳 版权声明:本文为博主原创文章,转载请标出转载地址 http://www.cnblog ...

  3. 【图像处理】 均值滤波、中值滤波和高斯滤波

    [图像处理] 均值滤波.中值滤波和高斯滤波 均值滤波 中值滤波 高斯滤波 结语 均值滤波 均值滤波是一种线性滤波,会导致图像模糊. 均值滤波器卷积核:卷积核中心点对应原图上的位置的值,变为卷积核覆盖的 ...

  4. matlab 均值滤波_数字图像处理基础 — 高斯滤波

    高斯滤波,本文主要讲其如何通过C语言实现.不太擅长写理论性质的文章,这里仅仅阐述自己怎么实现以及简单的优化过程. 通常我们对获取的图像进行进一步处理时,往往需要先进行一次降噪,而通常我们选择的是高斯滤 ...

  5. 数字图像处理-频率域滤波原理

    from:https://blog.csdn.net/forrest02/article/details/55510711?locationNum=15&fps=1 写在前面的话 作者是一名在 ...

  6. [数字图像处理]图像复原--逆滤波

    1.逆滤波的问题点       图像的老化,可以视为以下这样的一个过程.一个是退化函数的影响(致使图片模糊,褪色等),一个可加性噪声的影响. 用算式表示为      前几篇博文,主要是介绍可加性噪声的 ...

  7. 数字图像处理之频域滤波

    前段时间看了很多的概念和知识,发现因为是走马观花的过了一遍,所以看得稀里糊涂的,然后许多地方混淆了概念,特别是关于图像频率域的部分的理解(包括图像频率域滤波之类的),所以下面总结一下这段时间重新看&l ...

  8. matlab 数字图像滤波,数字图像处理 (基于Matlab) 滤波

    <数字图像处理> 实验报告 一.实验目的(不少于200字) 一.第一个实验用的是各种空间域的方式来滤波,也就是直接把图像和空间滤波器的模板做卷积,当 然图像处理很重要的一个部分还有频域的处 ...

  9. 图像处理:均值滤波算法

    目录 前言 概念介绍 基本原理 Opencv实现均值滤波 Python手写实现均值滤波 参考文章 前言 在此之前,我曾在此篇中推导过图像处理:推导五种滤波算法(均值.中值.高斯.双边.引导).这在此基 ...

最新文章

  1. 使用OpenCV,Python和dlib进行眨眼检测及计数
  2. wireshark数据包分析实战
  3. matlab神经网络工具箱创建神经网络,matlab神经网络工具箱创建神经网络
  4. html视频标签不显示,HTML视频标签无法正确显示视频
  5. matplolib绘图
  6. 美柚-产品原型图(高保真) 一个拥有腾讯产品梦的小精灵
  7. SQL Server 锁
  8. 性能测试--jmeter响应数据中文乱码【12】
  9. gp数据库运维:远程登录 杀进程
  10. python pil_Python PIL composite()用法及代码示例
  11. 程序员不要和陌生人说话——漫谈一些有趣的架构原则
  12. tezos multisig baker
  13. 【java基础】IO流是啥?有啥用?(上)
  14. 图像的仿射变换:cv2.warpAffine()
  15. AWS宣布Amazon EKS在AWS中国(宁夏)区域和AWS中国(北京)区域正式商用
  16. EPLAN P8部件库 EPLAN P8部件库,包含低压电气 控制系统设计常用品牌型号,全部部件均为本人整理自己创建,可大大提高电气控制行业同仁的工作效率!
  17. 【Python特性】Python中的下划线和双下划线是什么意思?
  18. 最强Android教程!怒斩获了30家互联网公司offer,赶紧收藏!
  19. 萨姆休斯顿州立大学计算机专业,美国萨姆休斯顿州立大学校园环境
  20. 【180930】C#纸牌小游戏源码

热门文章

  1. Binder(二)简介
  2. 即时通讯源码基IM源码内核开发采用[uniapp]封装技术
  3. C语言memcpy函数和memmove函数
  4. [GitHub] JavaScript 趋势榜项目(第41周)
  5. 如何在 Linux 命令行中切换用户
  6. 【头歌】大数据从入门到实战 - 第2章 分布式文件系统HDFS
  7. 告诉你真正的WDS及部署经验
  8. 道光天和号酒当中的花香、果香是否存在呢?
  9. 数据库中复合主键的应用场景
  10. 最菜/高级的莫名其妙C程序