多分辨率曝光融合在安卓平台上的实现

2017-03-17 09:51徐志伟黄伟峰张海
电脑知识与技术 2016年32期

徐志伟++黄伟峰++张海

摘要:数码成像设备只能表示非常有限的动态范围,因此亮度差异很大的物体很难在一副图像中清楚显示。曝光融合就是将不同曝光条件下采集的图像合并成一幅所有细节都清晰的图像,而多分辨率曝光融合是其中一种简单且高效的方法。该文阐述了该算法在安卓平台上的设计和实现方法,并在手机上进行测试,实验结果表明该算法能运行在手机上,为以后测试更多曝光融合算法提供了一个平台。

关键词:多分辨率曝光融合;安卓平台;系统实现

中图分类号:TP37 文献标识码:A 文章编号:1009-3044(2016)32-0262-02

1 背景

普通数码相机或具有拍照功能的手机已成为人们记录生活的主要工具。由于数码成像设备能表示的动态范围远低于现实世界的动态范围,因此亮度差异很大的两个对象难以在一幅图像中清晰成像。曝光融合是通过图像融合技术,将多幅不同曝光条件下采集的图像合成一幅更能反映现实景象,从而保证所有细节都比较清晰。这种算法简化了中间过程,不需要生成高动态范围图像,减少了相机响应函数估计误差对合成结果的影响,其中最具代表性的是多分辨率曝光融合算法[1]。

该算法由T. Mertens、J. Kautz和F. V. Reeth共同提出,其主要思想是:首先,根据对比度、饱和度和曝光度,为原始输入图像计算权值矩阵;然后,对图像进行拉普拉斯分解,而对权值矩阵进行高斯分解;最后,在对每一层的图像分别融合后,将所有层的融合结果合并成一幅图像。下面将介绍如何将该算法在安卓平台上實现。

2 多分辨率曝光融合在安卓平台上的实现

图1 多分辨率曝光融合系统的UML图

为了能在手机端运行曝光融合算法,这个系统至少包括连拍和多分辨率曝光融合两大功能。当选择连拍时,能进入拍照画面,并且能拍出多张具有不同曝光度的照片;当选择曝光融合时,能够对选定的多张图片进行融合并显示出结果图片。为了实现这些功能,我们设计的类及类间关系如图1所示。

类MainActivity是该系统的第一个界面,主要包括连拍和融合2个按钮,分别切换到拍照界面和融合界面。类CameraAty是拍照界面,不仅提供照片预览功能,还能通过多次启动拍照并在每次启动前修改相机曝光值,达到采集具有不同曝光度的照片的效果。类rongheActivity是融合界面,用以显示所有图像,并提供选择工具,一旦选中多幅图像后通过开始融合按钮,实现融合并显示结果。

类imageMap和类weightMap用来实现彩色图像和权值映射的基本操作,并在此基础上,类mulResDecompo实现了多分辨率曝光融合算法,其中3个主要成员函数exposure_fusion、gaussian_pyramid和laplacian_pyramid分别实现了融合算法的主体、高斯分解和拉普拉斯分解。用Java语言描述多分辨率曝光融合算法主体如下所示:

public Bitmap exposure_fusion(List wms, List bmps){

int nlev = (int)(Math.floor(Math.log((double)(Math.min(bmps.get(0).getWidth(),bmps.get(0).getHeight()))) / Math.log((double)2)));//根据输入图像的长度和宽度,自动计算图像分解的层数

List ans = new ArrayList();

for(int i = 0; i < wms.size(); i++){

List pyrW = gaussian_pyramid(wms.get(i), nlev);//对第i幅图像的权值矩阵进行高斯分解

List pyrB = laplacian_pyramid(bmps.get(i), nlev);//对第i幅图像进行拉普拉斯分解

for(int j = 0; j < nlev; j++){//逐层融合,每层得到1幅结果图像

if(i==0){

imageMap tmp = new imageMap();

tmp.setWidth(pyrB.get(j).getWidth());

tmp.setHeight(pyrB.get(j).getHeight());

tmp.setRed(new double[tmp.getWidth()*tmp.getHeight()]);

tmp.setGreen(new double[tmp.getWidth()*tmp.getHeight()]);

tmp.setBlue(new double[tmp.getWidth()*tmp.getHeight()]);

for(int x = 0; x < tmp.getWidth(); x++)

for(int y = 0; y < tmp.getHeight(); y++){

tmp.setARed(x, y, pyrB.get(j).getARed(x, y)* pyrW.get(j).getAWeight(x, y));

tmp.setAGreen(x, y, pyrB.get(j).getAGreen(x, y)* pyrW.get(j).getAWeight(x, y));

tmp.setABlue(x, y, pyrB.get(j).getABlue(x, y)* pyrW.get(j).getAWeight(x, y));

}

ans.add(tmp);

}

else

{

imageMap tmp = ans.get(j);

for(int x = 0; x < tmp.getWidth(); x++)

for(int y = 0; y < tmp.getHeight(); y++){

tmp.setARed(x, y, tmp.getARed(x, y)+pyrB.get(j).getARed(x, y)* pyrW.get(j).getAWeight(x, y));

tmp.setAGreen(x, y, tmp.getAGreen(x, y)+pyrB.get(j).getAGreen(x, y)* pyrW.get(j).getAWeight(x, y));

tmp.setABlue(x, y, tmp.getABlue(x, y)+pyrB.get(j).getABlue(x, y)* pyrW.get(j).getAWeight(x, y));

}

}

}

}

return reconstruct_laplacian_pyramid(ans);//將nlev幅结果图像合并成一幅输出

}

该算法的输入是原始彩色图像和权值矩阵,其中权值矩阵根据对比度、饱和度和曝光度计算得到[1],而输出则是融合后的结果图像。算法的主要过程是:

1)根据图像的长度和宽度,自动计算出图像分解的层数nlev;

2)gaussian_pyramid(weightMap a,int nlev)将权值矩阵分解为nlev层的高斯金字塔;

3)laplacian_pyramid(imageMap a,int nlev)将图像分解为nlev层的拉普拉斯金字塔;

4)将同一层的所有图像根据权值矩阵加权平均,得到nlev层结果图像;

5)reconstruct_laplacian_pyramid(List pyrI)将nlev个结果图像合并,其合并方法是从分辨率最低的开始,将每一层图像放大到与上一层图像大小相同后叠加上去,直到达到最高分辨率为止。

3 实现效果

程序运行后,单击拍照按钮,拍出3张曝光度不同的照片,并在单击图像融合后,能够对选定的3张图像进行融合处理,并得出最终的图像。图2显示了一组实验结果,其中第一行3幅图是待融合的输入图像,第二行是融合图像。实验效果表明该系统已实现算法的基本功能。此外,允许用户设置采集图像的数量,选出其中包含信息较多的图进行融合,就可以得到一张保留场景信息最多最好的图像。

图2 融合测试结果

4 结束语

本论文做了一种尝试,将多分辨率曝光融合算法在安卓平台上进行实现并测试通过,为以后测试更多曝光融合算法提供了一个平台。通过系统测试,我们也发现一些问题可以改进:

1)连拍需要一段时间才能完成,这段时间内相机即使有轻微抖动,融合后的图像也会呈现出重影。因为多分辨率曝光融合算法只对静态场景有效,所以可以尝试动态场景的融合算法。

2)因为该系统会产生一个图像序列和一个权值矩阵序列,所以运行时将耗费大量的内存,我们之后将进一步改进算法,尽量减少内存消耗。

参考文献:

[1] Mertens T. Exposure Fusion: A Simple and Practical Alternative to High Dynamic Range Photography[J]. COMPUTER GRAPHICS forum, 2009, 28(1):161-171.

[2] 李刚. 疯狂的Android讲义[M]. 2版.北京: 电子工业出版社, 2012.

[3] 黄隽实. Android开发最佳实践[M]. 北京: 机械工业出版社, 2013.