首页 > 编程知识 正文

图像处理中值滤波,均值滤波例题

时间:2023-05-04 14:01:28 阅读:156862 作者:333

图像噪声通常是指图像中除图像之外的信息,例如图像中的斑点和粒子,这些多余的错误消息会干扰成像物体的显示,影响图像的质量,因此往往需要通过图像滤波(也称为图像去噪)来去除这些噪声典型的图像滤波算法包括平均滤波、zldxbc滤波、中值滤波器、双边滤波、非局部平均滤波、以及近年来热的基于深度学习的图像滤波。 本章详细介绍了均值滤波算法的原理以及C的实现和优化。

首先,让我们来看看写Opencv代码的独特篮球。 他们写的代码不仅稳定性好,而且执行效率也非常高。 很多时候,我们花了很大力气写同样的算法,发现性能比Opencv的接口函数差很多。 所以,虽然有失去的心理落差,但要有学习的态度,追赶大人物的脚步,精益求精,相信我们自己也能行。

平均值滤波,即计算各像素点周围的像素点(包括该点)的平均值。 作为该像素点滤波后值,通常取以该像素点为中心的矩形窗口内的所有像素点来计算平均值。 矩形窗的大小通常为3 * 3、5 * 5、9 * 9、2n 1(* )2n1 )。 窗口越大,滤镜效果越好,但图像会变得越模糊,因此需要根据情况设置矩形窗口的大小。 例如,3*3窗口的平均滤波可以通过从周围9点(包括本身)计算平均值来获得,如下图所示。

上图中点(x,y )的滤波器值用公式表示。

(2n 1 ) * ) 2n 1 )窗口时,点) x、y )的平均滤波器值可通过以下公式计算:

为了解决图像边缘像素点落在完整的矩形窗口内的问题,通常将图像的上、下边界扩展n行,将左右边界扩展n列,在实际计算中仅计算图像的原始像素点的窗口平均值。 例如,如果矩形窗口为3*3,则n的值为1。 在这种情况下,扩展边界的图像如下图所示。

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

voidblur_mean(matsrc,Mat dst,int winsize ) if ) winsize1) /如果窗口的边不是奇数,则加1为奇数。 因为只有当窗口的边缘为奇数时,当前像素点才是窗口的中心点) winsize=1。 }constintwinsize_2=winsize/2; //winsize_2是上述公式的nconstfloatwinsize _ num=winsize * winsize; //2n1(* ) 2n1) Mat src_board; 调用Opencv的copyMakeBorder函数以调用边界copymakeborder(src,src_board,winsize_2,winsize_2,winsize_2,winsize_2 const int col=src_board.cols; matdst_tmp(src.size ),CV_8UC1 ); //列for(intI=winsize_2; i row-winsize_2; I//行循环,图像的原始行{for(intj=winsize_2; jcol-winsize_2; j//列循环,图像的原始列{ float sum=0.0; //计算各像素点周围矩形区域内的所有像素点的累加和for (inty=0; y winsize; y ) for(intx=0; x winsize; x () sum=src _ board.ptr uchar (I-winsize _ 2y ) [j-winsize_2 x]; (//求累加后,求窗口像素的平均值。 当前像素点的过滤值dst_tmp.ptruchar(I-winsize_2) [j-winsize_2]=(uchar ) ) sum/winsize_num 0.5; }dst_tmp.copyto(dst ); }执行上述代码,对1帧1024*1024的图像进行平均滤波后的结果如下图所示。 可以看出,随着窗口大小的增大,滤波图像变得更加模糊,整体时间也大幅增加。 由此可以判断,在滤波的计算中,主要花费时间的是窗口内像素点的累加。

原图

3*3窗口,耗时17 ms

="text-align: center"> 

11*11窗口,耗时147.8 ms

21*21窗口,耗时535.4 ms

前面两篇文章中主要讲解了积分图的计算,根据积分图的特点,可以使用积分图来简化矩形窗口内像素累加和的计算,如下图所示,蓝色矩形区域内点的像素累加和,可以使用其四个顶点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_num      sum = _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五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。