从技术上讲,为了得到类似于图1a中降雪效果,我们需要构造三层雪花图像,并且每一层的雪花数量、雪花大小、雪花的模糊程度都应该有所不同。雪花数量可以通过交互式参数进行设定,雪花大小可以通过随机函数进行随机分配,而雪花的模糊可以通过高斯模糊或者圆盘模糊算子进行滤波获得。此外,尽管在图1中几乎所有的雪花都是垂直于地面降落,这可能是因为当时没有刮风。但是,在风力的作用下雪花呈一定角度降落更常见。为了模拟这种效果,可以考虑使用动态模糊算子进行滤波。为了将高斯模糊及圆盘模糊和动态模糊区分开,我们称前两类模糊为静态模糊。
有了上述考虑,我们就可以提出如下的飞雪场景合成算法:
Step1:将一副不含飞雪的原始图像读入到内存中;
Step2:为三个和原始图像大小相同的掩膜图像分配内存空间,这三个掩膜图像每一个分别对应着一层雪花图像,并且初始化为全0值。
Step3:交互式为每一层雪花图像指定雪花点数、雪花大小、模糊半径、模糊方差、动态大小、运动方向等参数。其中雪花点数和雪花大小将用于控制雪花的密集度,模糊半径和模糊方差将用于控制雪花静态模糊的程度,动态大小和运动方向一方面控制雪花运动的方向,另一方面也控制雪花的动态模糊程度。
Step4:根据Step3指定的雪花点数、雪花大小,对每一层内的每一朵雪花的位置和大小进行随机确定,然后根据模糊半径、模糊方差,通过使用高斯或者圆盘模糊算子进行滤波以获得静态模糊效果,最后根据动态大小、运动方向,通过使用动态模糊算子进行滤波以获得动态滤波效果。
Step5:将三层雪花图像和原始图像进行融合,以得到最后的合成图像。
在上述5个步骤中,Step1、2、3和5涉及到程序的界面编程,而Step4是飞雪场景合成算法的核心,它涉及到两个关键子程序,而这两个子程序都将被Step5中被调用。此外,在Step5中也有一个图像两两合成子程序。因此我们先介绍这三个核心子程序,然后在第3节结合界面编程技术一起介绍Step1、2、3和5。
如Step4所述,首先应该对雪花团的位置和大小进行随机分配。为此,我们可以用随机函数rand来随机分配每个雪花团的中心点(row,col)位置和雪花团所占方形像素区域的半长xsize,然后将方形局部区域(row – xsize:row + xsize,col – xsize:col + xsize)设置为最大亮度值255,即可得到随机雪花团的初始图像。参考代码段1:
%---------------------------------------------------------------------------------------------------------------------------------------
%代码段1
function [maskImage] = sub_makeRandPoints(height,width,pointNumber,pointSize)
%函数功能:
% 对雪花的位置和大小进行初始分配,产生和原始图像大小相等的随机雪花团的初始图像
%参数说明:
% 输入参数:
% height:原始图像的高等
% width:原始图像的宽度
% pointNumber:用于控制雪花团的密集程度,值越大,雪花团越密集
% pointSize:最大雪花团的半长,和随机函数rand一起决定每个具体雪花团的大小
% 输出参数:
% maskImage:保存随机雪花团的初始图像
%--------------------------------------------------------------------------
%生成一个和原始图像大小相等的雪花团初始图像,初始值全为0
maskImage = zeros(height,width);
%对每个雪花团的中心点随机分配其行坐标和列坐标的位置。由于rand函数产生的随机数都是归一化
%的,也即只产生[0,1]之间的随机数,因此在后面应该乘上高度或者宽度才能得到真正的行列坐标。
rowLocation = rand(1,pointNumber);
colLocation = rand(1,pointNumber);
%对每个雪花团随机分配其团的大小,该值也是归一化的,在后面应该乘以pointSize以确定每个具体
%雪花团的大小
rsize = rand(1,pointNumber);
%初始化for循环中的变量,以满足matlab使用JIT技术进行for循环加速
row = 0;%临时保存每个雪花团中心点的行坐标
col = 0;%临时保存每个雪花团中心点的列坐标
xsize = 1;%临时保存每个雪花团的半长
pointIter = 1;%for循环的迭代计数器
startRow = 0;%和stopRow一起确定每个雪花团的行坐标区域
stopRow = 0;
startCol = 0;%和stopCol一起确定每个雪花团的列坐标区域 stopCol = 0;
|