OpenCV4学习笔记(59)

您所在的位置:网站首页 合成hdr用什么软件最好 OpenCV4学习笔记(59)

OpenCV4学习笔记(59)

2023-12-20 18:24| 来源: 网络整理| 查看: 265

今天要整理记录的笔记是与高动态范围HDR成像相关的内容,主要参考学习的来源为OpenCV官方文档。

首先需要了解什么是高动态范围HDR,由维基百科定义可知:

高动态范围成像(英语:High Dynamic Range Imaging,简称HDRI或HDR),在计算机图形学与电影摄影术中,是用来实现比普通数位图像技术更大曝光动态范围(即更大的明暗差别)的一组技术。高动态范围成像的目的就是要正确地表示真实世界中从太阳光直射到最暗的阴影这样大的范围亮度。

也就是说,HDR图像相比起我们平常所见的图像来说,其像素取值范围更大、深度更深,一般的图像可能是8位的无符号字节类型,而HDR图像则一般为32位浮点类型,所以HDR图像所能存储的图像信息相比起一般图像要多得多,最直观的视觉感受就是:HDR图像的明亮处和灰暗处都能够呈现出比较好的细节,不会出现严重的过曝和欠曝问题。

但也正因为HDR图像存储的信息量之大、深度之深,以至于我们不能直接进行显示,会出现一片白茫茫的情况。而需要先进行色调映射后才可以正常显示。

下面就跟随着官方文档的步骤,来学习实现HDR图像的合成与显示。在OpenCV中,提供了三种合成HDR图像的方式,分别是Debevec方法、Robertson方法、Mertens方法,由于这三种方式使用起来具有一定的相似性,所以下面并行进行演示。

加载曝光图像序列 首先,不管是哪一种方法,我们都需要加载一系列不同曝光时间(以s为单位)的图像,如果把这一系列图像单独存储在一个文件夹中,可以用以下方式读取并组织成一个曝光图像序列。 //加载曝光图像序列 vectorimgPath; glob("D:\\opencv_c++\\opencv_tutorial\\data\\images\\exposures\\", imgPath); vector exposure_images; for (int i = 0;i cout //auto Debevec_response = createCalibrateDebevec(); //Mat response; //Debevec_response->process(exposureImages, response, exposureTimes); auto merge_Debevec = createMergeDebevec(); Mat hdr; merge_Debevec->process(exposureImages, hdr, exposureTimes); //由于是在普通的LDR显示器上进行显示,因此我们必须将HDR图像映射到保留大多数细节的8位范围的低动态范围LDR图像。 //这是进行色调映射的主要目标,伽玛校正值设置为2.2f适用于大多数情况 Mat ldr; auto tonemap = createTonemap(2.2f); tonemap->process(hdr, ldr); //HDR图像进行色调映射后得到的LDR图像取值范围在 [ 0 , 1 ] ,所以乘255将范围拉伸到 [ 0 , 255 ] ldr = ldr * 255; //将float32类型转化为uchar8类型 ldr.convertTo(ldr, CV_8UC3); imshow("Debevec_HDR", hdr); imshow("Debevec_LDR", ldr); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Debevec_LDR.png", ldr); } void Robertson(vectorexposureImages, vectorexposureTimes) { //auto Robertson_response = createCalibrateRobertson(); //Mat response; //Robertson_response->process(exposureImages, response, exposureTimes); auto merge_Robertson = createMergeRobertson(); Mat hdr; merge_Robertson->process(exposureImages, hdr, exposureTimes); //由于是在普通的LDR显示器上进行显示,因此我们必须将HDR图像映射到保留大多数细节的8位范围的低动态范围LDR图像。 //这是进行色调映射的主要目标,伽玛校正值设置为2.2f适用于大多数情况 Mat ldr; auto tonemap = createTonemap(2.2f); tonemap->process(hdr, ldr); //HDR图像进行色调映射后得到的LDR图像取值范围在 [ 0 , 1 ] ,所以乘255将范围拉伸到 [ 0 , 255 ] ldr = ldr * 255; ldr.convertTo(ldr, CV_8UC3); imshow("Robertson_HDR", hdr); imshow("Robertson_LDR", ldr); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Robertson_LDR.png", ldr); }

(2)Mertens方法 对于Mertens方法来说,只需要传入不同曝光时间的图像序列就可以了,该方法使用对比度、饱和度和曝光度的好坏来对像素加权,而不是使用拉普拉斯金字塔来对图像进行加权。得到的图像权重被构造为对比度、饱和度和曝光度良好的加权平均值。 由于Mertens方法是进行不同曝光时间图像的融合,并且直接生成由HDR图像转化来的低动态范围图像,所以生成的图像不需要进行色调映射。 生成的图像取值范围在 [ 0 , 1 ] 之间,可以通过乘以255将取值范围拉伸到 [ 0 , 255 ],并且转换为8位图像进行显示。在官方文档中还建议应用伽马校正或线性色调映射来提升显示效果,OpenCV中提供了三种色调映射方法,这里使用的是createTonemap(1.0f),其中参数的默认值是1.0f,不过取2.2f能适用于大多数场景。 当我们不清楚图像的曝光时间,或者不需要得到HDR图像时,可以直接使用Mertens方法来进行曝光融合,得到的低动态范围图像也是由HDR图像转换而来,同样在明亮处和灰暗处都有更好的细节体现。 下面是Mertens方法的代码演示:

void Mertens(vectorexposureImages) { auto merge_mertens = createMergeMertens(); Mat fusion; merge_mertens->process(exposureImages, fusion); //进行伽马矫正,需根据实际图像调节参数,2.2f可满足大多数显示情况 /*auto tonemap = createTonemap(2.2f); tonemap->process(fusion, fusion);*/ fusion = fusion * 255; fusion.convertTo(fusion, CV_8UC3); imshow("Mertens", fusion); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Mertens.png", fusion); }

到这里就分别以不同方法给出了OpenCV中HDR图像的合成步骤,下面是完整的代码演示:

#include #include #include #include #include using namespace std; using namespace cv; void Debevec(vectorexposureImages, vectorexposureTimes); void Robertson(vectorexposureImages, vectorexposureTimes); void Mertens(vectorexposureImages); int main() { //加载曝光图像序列 vectorimgPath; glob("D:\\opencv_c++\\opencv_tutorial\\data\\images\\exposures\\", imgPath); vector exposure_images; for (int i = 0;i cout auto merge_mertens = createMergeMertens(); Mat fusion; merge_mertens->process(exposureImages, fusion); //进行伽马矫正,需根据实际图像调节参数,2.2f可满足大多数显示情况 /*auto tonemap = createTonemap(2.2f); tonemap->process(fusion, fusion);*/ fusion = fusion * 255; fusion.convertTo(fusion, CV_8UC3); imshow("Mertens", fusion); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Mertens.png", fusion); } //使用Debevec方法进行HDR合成,将多张曝光时间不同的照片及其对应的曝光值进行加权平均,得到float32类型的高动态范围HDR图像 //需要传入曝光图像序列和对应的曝光时间 void Debevec(vectorexposureImages, vectorexposureTimes) { //auto Debevec_response = createCalibrateDebevec(); //Mat response; //Debevec_response->process(exposureImages, response, exposureTimes); auto merge_Debevec = createMergeDebevec(); Mat hdr; merge_Debevec->process(exposureImages, hdr, exposureTimes); //由于是在普通的LDR显示器上进行显示,因此我们必须将HDR图像映射到保留大多数细节的8位范围的低动态范围LDR图像。 //这是进行色调映射的主要目标,伽玛校正值设置为2.2f适用于大多数情况 Mat ldr; auto tonemap = createTonemap(2.2f); tonemap->process(hdr, ldr); //HDR图像进行色调映射后得到的LDR图像取值范围在 [ 0 , 1 ] ,所以乘255将范围拉伸到 [ 0 , 255 ] ldr = ldr * 255; //将float32类型转化为uchar8类型 ldr.convertTo(ldr, CV_8UC3); imshow("Debevec_HDR", hdr); imshow("Debevec_LDR", ldr); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Debevec_LDR.png", ldr); } //使用Robertson方法进行HDR图像合成,将多张曝光时间不同的照片及其对应的曝光值进行加权平均,得到float32类型的高动态范围HDR图像 //需要传入曝光图像序列和对应的曝光时间 void Robertson(vectorexposureImages, vectorexposureTimes) { //auto Robertson_response = createCalibrateRobertson(); //Mat response; //Robertson_response->process(exposureImages, response, exposureTimes); auto merge_Robertson = createMergeRobertson(); Mat hdr; merge_Robertson->process(exposureImages, hdr, exposureTimes); //由于是在普通的LDR显示器上进行显示,因此我们必须将HDR图像映射到保留大多数细节的8位范围的低动态范围LDR图像。 //这是进行色调映射的主要目标,伽玛校正值设置为2.2f适用于大多数情况 Mat ldr; auto tonemap = createTonemap(2.2f); tonemap->process(hdr, ldr); //HDR图像进行色调映射后得到的LDR图像取值范围在 [ 0 , 1 ] ,所以乘255将范围拉伸到 [ 0 , 255 ] ldr = ldr * 255; ldr.convertTo(ldr, CV_8UC3); imshow("Robertson_HDR", hdr); imshow("Robertson_LDR", ldr); imwrite("D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\Robertson_LDR.png", ldr); }

分别看一下不同方法合成的HDR图像的效果如何,首先看一下所使用的曝光图像序列: 在这里插入图片描述 我们使用上述16张不同曝光时间的图像进行合成HDR图像,三种方法效果图如下: Debevec_LDR.png Robertson_LDR.png Mertens.png 从上到下分别是Debevec方法、Robertson方法、Mertens方法得到的HDR图像显示效果,总的来说在亮处和暗处都呈现出更多的细节,但是Debevec方法和Robertson方法在色调映射这一步骤上仍然需要更多的调试,可以选取不同参数取值或选取不同的色调映射方法来进行尝试,以获得更好的效果。在这里,我们只是尝试还原了官方文档中的HDR效果,虽然官网中演示代码在合成HDR图像时加入了CRF参数而我们的演示代码中并没有,但是效果还是比较相似的。而一旦加入相机响应函数CRF,就会导致效果变得很差,甚至严重偏色,至于原因我还没找到,希望有了解这个的朋友能指导我一下。

最后,虽然在这组图像中,Mertens方法得到的HDR效果是最好的,但并不意味着对于所有图像都是如此,我们在实际使用时还需要分别测试不同方法对于我们实际图像的呈现效果,并且还需要对色调映射的不同方法、不同参数进行调试。只有经过不断调试、对比,才能得到最符合我们实际情况的HDR成像方法以及参数设置。

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3