之前在51CTO博客中http://qianqing13579.blog.51cto.com/5255432/1590213,写过均值滤波,但是没有加入对边界的处理,昨天晚上,完成了对边界的处理,代码贴出来,跟大家分享交流一下,没有做太多的优化
void Blur(const Mat &image_Src, Mat &image_Dst, Size size_Aperture) { /////////////step 1.重新分配图像(如果需要)////////////////////////////// //新图像的大小 int width_Dst=image_Src.cols; int height_Dst=image_Src.rows; image_Dst.create(Size(width_Dst,height_Dst),CV_8UC1);//如果重新分配,之前的空间会扔掉 //////////////////////////////step 2.创建一副新图像(对源图像加以扩充)//////////////////////////////////////////// //新图像大小 int width_Extend=size_Aperture.width>>1; int height_Extend=size_Aperture.height>>1; int width_New=width_Dst+2*width_Extend;//宽度左右各扩充width_Extend int height_New=height_Dst+2*height_Extend;//高度上下各扩充height_Extend //创建新图像 Mat image_New(Size(width_New,height_New),CV_8UC1,Scalar(0)); //拷贝源图像到新图像 int widthStep_New=image_New.cols;//新图像的步长 int widthStep_Src=image_Src.cols;//源图像的步长 int width_Src=width_Dst; int height_Src=height_Dst; uchar *row_Src=image_Src.data; uchar *row_New=image_New.data+height_Extend*widthStep_New+width_Extend; for (int y=0;y<=height_Src-1;++y)//纵坐标 { //列 uchar *col_Src=row_Src; uchar *col_New=row_New; for (int x=0;x<=width_Src-1;++x)//横坐标 { //处理每个像素 col_New[0]=col_Src[0]; //下一个像素 col_Src++; col_New++; } //下一行 row_Src+=widthStep_Src; row_New+=widthStep_New; } ////////////////////////////step 3.滤波/////////////////////////////////////// //滑动窗口 int width_Aperture=size_Aperture.width; int height_Aperture=size_Aperture.height; //计算需要滤波像素的起点坐标 int startX=width_Aperture>>1; int startY=height_Aperture>>1; //每列的灰度值和 int *sum_PerCol=new int[width_New]; //对新图像做滤波处理 row_New=image_New.data+startY*widthStep_New+startX; uchar *row_Dst=image_Dst.data;//第一行 uchar *row_Aperture_New=image_New.data; for (int y=startY;y<=height_New-startY-1;++y) { //列 //uchar *col_New=row_New; uchar *col_Dst=row_Dst; uchar *col_Aperture_New=row_Aperture_New; //计算每列height_Aperture个像素的灰度值和 //第一行,计算所有列的和 if (y==startY) { for (int k=0;k<=width_New-1;++k) { sum_PerCol[k]=0; //每列第一个指针 uchar *col_PerLine=col_Aperture_New+k; for (int t=0;t<=height_Aperture-1;++t) { sum_PerCol[k]+=col_PerLine[0]; col_PerLine+=widthStep_New;//下一行 } } } else//非第一行 { for (int k=0;k<=width_New-1;++k) { //每列第一个指针 uchar *col_=col_Aperture_New+k; sum_PerCol[k]-=col_[0-widthStep_New];//减上面 sum_PerCol[k]+=col_[0+(height_Aperture-1)*widthStep_New];//加下面 } } //计算width_Aperture行的列总和 int sum_Aperture=0; for (int x=startX;x<=width_New-startX-1;++x) { //每行第一个元素,求width_Aperture个列和 if (x==startX) { for (int k=0;k<=width_Aperture-1;++k) { sum_Aperture+=sum_PerCol[k]; } } else//非第一个元素 { //减去左边 sum_Aperture-=sum_PerCol[x-startX-1]; //加上右边 sum_Aperture+=sum_PerCol[x+startX]; } //////////////////边界处理:计算滑动窗口内灰度值非零的像素点个数/////////////////// //中间区域:窗口内所有像素点 int pixelCount=width_Aperture*height_Aperture; //上边界:部分像素点 if (y<=2*startY) { int w=(x+1)<width_Aperture?(x+1):width_Aperture; pixelCount=(y+1)*w; } //左边界 if(x<=2*startX) { int h=(y+1)<height_Aperture?(y+1):height_Aperture; pixelCount=(x+1)*h; } //下边界 if (y>=height_New-2*startY) { int w=(x+1)<width_Aperture?(x+1):width_Aperture; pixelCount=(height_New-y)*w; } //右边界 if(x>=width_New-2*startX) { int h=(y+1)<=height_Aperture?(y+1):height_Aperture; pixelCount=(width_New-x)*h; //最右下角(宽度和高度都在减小):这个角特别注意,需要特殊处理 if (y>=height_New-2*startY) { int h=height_New-y; pixelCount=(width_New-x)*h; } } //求均值 uchar meanValue=sum_Aperture/pixelCount; col_Dst[0]=meanValue; //滑动一个像素 col_Dst++; //col_New++; } //下一行 //row_New+=width_New; row_Dst+=width_Dst; row_Aperture_New+=width_New; } }
算法运行之前,需要配置一下OpenCV,算法核心与OpenCV没有太多关联
与OpenCV中的blur函数对比了一下
测试环境:VS2008 Release版本,Lena.bmp,迭代16次,窗口大小:Size(5,3)
平均运行时间,OpenCV为3ms,上面的算法为6ms,慢了整整一倍啊!后面还需要更多的优化工作。
其中OpenCV的结果图与上面的算法结果图基本一致,我用PS将两幅图像做了减法,两幅图像基本一样
原文地址:http://blog.csdn.net/qianqing13579/article/details/41978219