OpenCV实现运动模糊图像的模拟

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/johnhany/article/details/8251369

        产生模糊和噪声的原因有很多,比如拍摄环境的不稳定、拍摄设备的不精密、拍摄对象的快速运动、空气气流的扰动、储存与传输过程电路产生的错误等,本文要考虑的是由于拍摄对象和拍摄设备相对运动引起的运动模糊。关于噪声,其种类和产生的原因也是多种多样,比如白噪声、椒盐噪声、闪烁噪声、褐色噪声等。由于本文关注的重点在于对运动模糊的处理,所以对噪声统一处理为加性的随机噪声。

运动模糊的数学原理

运动模糊,是在拍摄设备快门打开的时间内,物体在成像平面上的投影发生平移或旋转,使接受的影像彼此发生重叠。

        为了便于用数学语言描述图像及其变换,现作如下规定:图像的左上角为坐标原点(0,0),图像的长度方向为x轴,宽度方向为y轴,整个图像落在第一象限。

        假设无任何模糊和噪声的真实图像为f(x,y),模糊图像为g(x,y)。由于运动模糊是由图像彼此重叠造成的,所以成立:


        其中,Cx为图像在方向上的平移速度,Cy为在方向上的平移速度,T为快门打开时间即产生模糊图像的时间,n(x,y)为加性噪声。

计算机实现细节

        为了简化计算过程,我假设只有运动模糊而没有任何加性噪声,而且产生模糊的运动是沿x方向的。

        对于真实图像,模糊图像自然是原始图像的叠加,但对于数字图像,由于像素信息由数值表示,不能简单地将相应像素值相加,而是将像素信息缩小后相加,否则会使亮度成倍增加,使图像严重失真。

例子一枚

原图像:



模糊处理后的图像:


代码

/* opencv version 2.3.1 */
#include "stdafx.h"
#include "highgui.h"
#include "cv.h"

void motionblur(IplImage* in, IplImage* out, int steps_x)
{
	int cnl,step;
	int length=in->widthStep;
	for(int y=0;y<in->height;y++)
	{
		uchar* pin=(uchar*)(in->imageData+y*in->widthStep);
		uchar* pout=(uchar*)(out->imageData+y*out->widthStep);
		int temp;
		for(int x=0;x<in->width;x++)
		{
			for(cnl=0;cnl<3;cnl++)
			{
				float sum = (float)pin[3*x+cnl]/steps_x;
				for(step=1;step<steps_x;step++)
				{
					if(step<=x)
						temp=step;
					else
						temp=step+x;
					sum += (float)pin[3*x+cnl-temp*3]/steps_x;
				}
				pout[3*x+cnl] = (uchar)sum;
			}
		}
	}
}

int main()
{
	IplImage* img = cvLoadImage("H:\\original.jpg");
	cvNamedWindow("Origin",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("Blur",CV_WINDOW_AUTOSIZE);
	cvShowImage("Origin",img);
	IplImage* blur = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
	motionblur(img,blur,10);
	cvShowImage("Blur",blur);
	cvSaveImage("H:\\original_mblur.jpg",blur);
	cvWaitKey(0);
	cvReleaseImage(&img);
	cvReleaseImage(&blur);
	cvDestroyWindow("From");
	cvDestroyWindow("To");
	return 0;
}

一些问题

    对边界的处理

        最简单的处理方法是忽略,也就是在边界附近仅利用现有的图像内像素进行计算。这样会在边界处留有一列未处理的像素,在其内侧的像素逐渐获得模糊处理直到模糊长度达到预设值。
从代码可以看出,我的处理方法是让边界处尽量利用内侧的像素,但这样使图像的边缘看起来像是拉伸过一样。
        实际上,还可以使用数学方法推算边界外的图像信息,利用它们完成对边界的正确处理。

    颜色的不连续

        从图像可以发现,这个方法对图案较复杂的图像可以产生很好的效果,但在颜色变化比较平缓的区域,模糊之后容易产生很明显的色阶。这说明仅仅靠叠加一系列相邻像素获得模糊效果是不够的,还需要在模糊处理的过程中进行平滑滤波操作,使模糊后的图像更平滑。
更新:
@RuifDu 提到色阶是用char计算累加的运算误差造成的,我改用浮点数计算,产生了正常的结果。我把图片和代码都已经更新。并在博客内提供了cpp版本代码:http://johnhany.net/2013/12/opencv-filter-template/

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试