现在的位置: 首页 > 综合 > 正文

高效均值滤波(加入对边界的处理)

2017年03月15日 ⁄ 综合 ⁄ 共 3597字 ⁄ 字号 评论关闭

最新博客http://blog.csdn.net/qianqing13579/article/details/42324645修改了均值滤波算法,采用了OpenCV中的copyMakeBorder处理边界


之前在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将两幅图像做了减法,两幅图像基本一样

抱歉!评论已关闭.