OpenCV4学习笔记(59)——高动态范围(HDR)成像

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

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

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

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

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

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

  1. 加载曝光图像序列
    首先,不管是哪一种方法,我们都需要加载一系列不同曝光时间(以s为单位)的图像,如果把这一系列图像单独存储在一个文件夹中,可以用以下方式读取并组织成一个曝光图像序列。
	//加载曝光图像序列
	vector<string>imgPath;
	glob("D:\\opencv_c++\\opencv_tutorial\\data\\images\\exposures\\", imgPath);
	vector<Mat> exposure_images;
	for (int i = 0;i < imgPath.size();i++)
	{
   
		Mat exposure_image = imread(imgPath[i]);
		exposure_images.push_back(exposure_image);
	}
  1. 加载曝光时间序列
    对于Debevec方法和Robertson方法来说,在进行HDR合成时需要同时传入曝光图像序列和曝光时间序列,而对于Mertens方法来说只需要传入曝光图像序列即可。这里还是需要进行加载曝光时间序列这一步骤。
    当把不同曝光时间用txt文件存储时,可以用以下方式来加载曝光时间序列。
	//加载曝光时间序列
	String exposureTimesPath = "D:\\opencv_c++\\Learning-OpenCV\\高动态(HDR)图像\\exposuresTime.txt";
	ifstream fp(exposureTimesPath);
	if (!fp.is_open())
	{
   
		cout << "can't open file" << endl;
		exit(-1);
	}
	vector<float> exposureTimes;
	while (!fp.eof())
	{
   
		string time;
		getline(fp, time);
		float t = float(atof(time.c_str()));
		exposureTimes.push_back(t);
	}
  1. 进行HDR合成
    (1)Robertson方法与Debevec方法
    使用Robertson方法和Debevec方法进行HDR图像合成时,需要将多张不同曝光时间的照片及其对应的曝光值进行加权平均,得到float32类型的高动态范围HDR图像,并且可以加入预先计算得到的相机响应函数(CRF)进行非线性合成。如果没有加入相机响应函数(CRF)这个参数,则会通过传入的不同曝光图像序列和不同曝光时间序列来进行计算得到一个线性CRF。
    不过,在OpenCV中对于相机响应函数这个参数的设置应该有些问题。如果不传入CRF这个参数,那么合成的HDR图像效果比较好,而一旦加入CRF参数,那么得到的HDR图像将会呈现非常差的效果。也就是说,当在OpenCV中合成HDR图像时,使用线性CRF得到的HDR图像,其效果相比起预先计算CRF后传入参数来得到的HDR图像要好得多。
    这个问题让我很疑惑,明明加入预先计算的相机响应函数后,应该得到更好的HDR效果才对,但是实际上恰恰相反,而且在网上找了很久也没有相关的解答。最终只发现在Stack Overflow上有一位网友也提出了相同的问题,并在讨论区有网友认为是OpenCV的合成HDR功能的API中已经加入了伽马矫正的内容,以至于再次进行非线性矫正的情况下反而会导致更差的效果。
    总而言之 ,从理论上来说,我们需要预先计算CRF来参与HDR图像合成才能得到好的效果,但是在OpenCV中并不一定需要这一步,至少在我以官网中的图像做实验时,不加入CRF参数能得到更好的效果。
    而且虽然官方文档中是有传入CRF参数的,但是我以相同的参数对相同的图像做处理时却得不到和官方文档中相同的HDR图像,反而是不加入CRF参数时效果更好。
    当我们合成得到HDR图像后,由于是在普通的低动态范围LDR显示器上进行显示,因此我们必须将HDR图像映射到保留大多数细节的8位范围的低动态范围LDR图像。这一步也称为色调映射,目的就是为了将我们得到的HDR图像正常显示出来,不过从高动态范围到低动态范围,肯定会牺牲一些图像信息。
    下面是Robertson方法与Debevec方法的代码演示:
void Debevec(vector<Mat>exposureImages
### 高动态范围成像HDR)相较于低动态范围成像(LDR)的优势 高动态范围成像HDR)能够更精确地捕捉和呈现现实世界中的光线强度差异,这使得其相比于低动态范围成像(LDR)具有显著的技术优势。以下是具体分析: #### 更宽的亮度范围 HDR技术的核心在于扩展图像的亮度范围,使其能够更好地反映真实世界的光照条件[^4]。这意味着,在同一幅图像中,HDR可以同时保留亮部细节(如太阳直射区域)以及暗部细节(如阴影下的物体),而不会出现过曝或欠曝的现象。 #### 减少伪影现象 当使用多张不同曝光时间的照片合成为一幅HDR图像时,如果源图片未经过适当对齐,则可能导致严重的人工痕迹——即所谓的“鬼影”。然而只要确保输入素材已正确校准并匹配好位置关系之后再进行处理操作就不会存在此类问题了[^2]。相比之下,LDR由于受到单一固定曝光设置限制,往往难以避免某些局部区域因过度曝光或者不足而导致的信息丢失. #### 提升视觉体验质量 通过应用色调映射(Tone Mapping),可以把原本超出标准RGB色彩空间所能表达的大范围光强变化压缩进适合屏幕设备再现的形式里去展现给观众看得到更加细腻逼真的画面效果[^1]. 这样一来不仅让整体观感更为舒适自然而且还能突出主体物象特征增强艺术表现力. ```python import cv2 import numpy as np def create_HDR_image(exposures): """ 使用OpenCV创建HDR图像。 参数: exposures (list): 不同曝光级别的图像列表 返回: hdr_img: 合成后的HDR图像 """ merge_mertens = cv2.createMergeMertens() hdr_img = merge_mertens.process(exposures) return hdr_img ``` 上述代码展示了如何利用 OpenCV 库函数 `createMergeMertens()` 来生成 HDR 图像的一个简单示例[^3]. ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值