您的位置:首页 > 运维架构

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

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

运动模糊的数学原理

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

为了便于用数学语言描述图像及其变换,现作如下规定:图像的左上角为坐标原点(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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: