OpenCV55:高动态范围成像|High Dynamic Range (HDR)

目标

在本章中,将学习

  • 了解如何根据曝光顺序生成和显示HDR图像
  • 使用曝光融合来合并曝光序列

理论

高动态范围成像(High-dynamic-range imaging,HDRI或HDR)是一种用于成像和摄影的技术,可以比标准数字成像或摄影技术重现更大的动态亮度范围。虽然人眼可以适应各种光照条件,但是大多数成像设备每通道使用8位,因此仅限于256级。当拍摄现实世界的照片时,明亮的区域可能会曝光过度,而黑暗的区域可能会曝光不足,因此无法一次曝光获取到所有细节。HDR成像适用于每个通道使用8位以上(通常为32位浮点值)的图像,从而允许更大的动态范围。

获取HDR图像的方法有多种,但是最常见的一种方法是使用以不同曝光值拍摄的场景照片。要综合这些曝光,了解相机的响应功能以及估算算法的功能是非常有用的。合并HDR图像后,必须将其转

换回8位才能在常规显示器上查看。此过程称为色调映射(tonemapping)。当场景或摄像机的对象在两次拍摄之间移动时会增加其他复杂性,因为应记录并调整具有不同曝光度的图像。

在本教程中,将展示两种算法(Debevec,Robertson),根据曝光序列生成和显示HDR图像,并演示了另一种曝光融合(Mertens)的方法,**该方法可以生成低动态范围图像,并且不需要曝光时间数据。**此外,估计相机响应函数(camera response function,CRF)对于许多计算机视觉算法都具有重要价值。HDR流水线的每个步骤都可以使用不同的算法和参数来实现,具体可 以参考一些其它资料。

曝光序列HDR

在本教程中,将查看以下场景,其中有4张曝光图像,曝光时间分别为15、2.5、1/4和1/30秒 (可以从Wikipedia下载图像)

exposures.jpg

1 将曝光图像加载到列表中

第一阶段只是将所有图像加载到列表中。此外需要常规HDR算法的曝光时间。要注意数据类型,因为图像应该是1通道或3通道8-bit(np.uint8),曝光时间的类型是float32

import cv2
import numpy as np

# load exposure images into a list
img_fn = ["img0.JPG", "img1.JPG", "img2.JPG", "img3.JPG"]
img_list = [cv2.imread(fn) for fn in img_fn]
exposure_times = np.array([15.0, 2.5, 0.25, 0.0333], dtype=np.float32)
2 将曝光合成HDR图像

在此阶段,将曝光序列合并为一张HDR图像。OpenCV中有两种可能性。

  • 第一种方法是Debevec
  • 第二种方法是Robertson

注意,HDR图像的类型为float32,而不是uint8,因为它包含所有曝光图像的完整动态范围。

# merge exposures to HDR image
merge_debevec = cv2.createMergeDebevec()
hdr_debevec = merge_debevec.process(img_list, times=exposure_times.copy())
merge_robertson = cv2.createMergeRobertson()

hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy())
3 色调映射HDR图像

将32位浮点HDR数据映射到[0…1]范围内。实际上,在某些情况下,该值可以大于1或小于0,稍后需要剪辑数据以避免溢出。

# Tonemap HDR image
tonemap1 = cv2.createTonemap(gamma=2.2)
res_debevec = tonemap1.process(hdr_debevec)

res_robertson = tonemap1.process(hdr_robertson)
4 使用Mertens融合曝光

在这里展示一种替代算法,用于合并曝光图像,而且不需要曝光时间,也不需要使用任何色调映射算法,因为Mertens算法已经为我们提供了[0…1]范围内的结果。

# Exposure fusion using mertens
merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)
5 转为8-bit并保存

为了保存或显示结果,需要将数据转换为[0…255]范围内的8位整数。

# convert datatype to 8-bit and save
res_debevec_8bit = np.clip(res_debevec*255, 0, 255).astype('uint8')
res_robertson_8bit = np.clip(res_robertson*255, 0, 255).astype('uint8')
res_mertens_8bit = np.clip(res_mertens*255, 0, 255).astype('uint8')

cv2.imwrite("ldr_debevec.jpg", res_debevec_8bit)
cv2.imwrite("ldr_robertson.jpg", res_robertson_8bit)
cv2.imwrite("ldr_mertens.jpg", res_mertens_8bit)

plt.subplot(131)
plt.imshow(res_debevec_8bit)

plt.subplot(132)
plt.imshow(res_robertson_8bit)

plt.subplot(133)
plt.imshow(res_mertens_8bit)

plt.show()

结果

不同的方法可以得到不同的结果,但是也要考虑到每种算法都有其他额外的参数,应该将它们附加以达到期望的结果。 最佳的实践就是尝试不同的方法,然后看看哪种方法最适合自己的场景

  • Debevec

    ldr_debevec.jpg

  • Robertson

    ldr_robertson.jpg

  • Mertenes Fusion

    fusion_mertens.jpg

估计相机响应函数

摄像机响应函数(CRF)使得我们可以将场景辐射度与测量强度值联系起来。CRF在某些计算机视觉算法(包括HDR算法)中非常重要。在这里,估计逆相机响应函数并将其用于HDR并。

# Estimate camera response function (CRF)
cal_debevec = cv2.createCalibrateDebevec()
crf_debevec = cal_debevec.process(img_list, times=exposure_times)
hdr_debevec = merge_debevec.process(img_list, times=exposure_times.copy(), response=crf_debevec.copy())
cal_robertson = cv2.createCalibrateRobertson()
crf_robertson = cal_robertson.process(img_list, times=exposure_times)
hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy(), response=crf_robertson.copy())

x = np.arange(256)

plt.subplot(121)
plt.plot(x, crf_debevec[:, 0, 0], c='r', marker='o')
plt.plot(x, crf_debevec[:, 0, 1], c='g', marker='o')
plt.plot(x, crf_debevec[:, 0, 2], c='b', marker='o')
plt.x

plt.subplot(122)
plt.plot(x, crf_robertson[:, 0, 0], c='r', marker='o')
plt.plot(x, crf_robertson[:, 0, 1], c='g', marker='o')
plt.plot(x, crf_robertson[:, 0, 2], c='b', marker='o')
plt.show()

相机响应函数由每个颜色通道的256长度向量表示。 对于此序列,得到以下估计:

crf.jpg

附加资源

  • 0
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

uncle_ll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值