文章目录
- 一、简介:
- 二、多曝光融合方案:
- 三、算法实现步骤
- 3.1 读取图像与曝光时间:
- 3.2 计算响应曲线并合并
- 3.3 色调映射
- 四:整体代码实现
- 五:效果
一、简介:
在摄影和计算机视觉领域,高动态范围(HDR)技术已经成为了捕捉丰富细节和真实感图像的重要手段。然而,要实现高质量的HDR效果,我们需要对多张不同曝光时间的图像进行融合处理。本文将探讨多曝光融合技术的基本原理和应用,帮助您深入了解这一技术如何捕捉更丰富、更真实的世界。
在自然界中,我们的眼睛能够感知从最暗到最亮的广阔亮度范围。然而,传统的相机传感器和显示设备却无法捕捉到这一完整的亮度范围,导致图像在亮度上出现失真。为了解决这一问题,HDR技术应运而生。HDR技术通过拍摄多张不同曝光时间的图像,并将其融合为一张包含更广泛亮度范围的图像,从而在视觉上更接近真实世界的亮度。多曝光融合是实现HDR效果的关键步骤。在这一过程中,我们需要拍摄多张不同曝光时间的图像,然后将这些图像融合为一张HDR图像。多曝光融合技术能够捕捉到更多细节,特别是在高光和阴影区域,从而使得图像在视觉上更加真实和生动。
在本文中,我将深入探讨多曝光融合技术的基本原理、常用算法以及实际应用并通过示例和代码,帮助您了解如何使用Python和OpenCV库来实现多曝光融合。
二、多曝光融合方案:
我们首先将读取的图片封装成一个列表。接着,我们根据图像内容和曝光时间来计算相机的CRF(相机响应函数),这一步骤对于后续图像融合至关重要。利用计算得到的CRF,我们将多曝光图像进行融合,以获得更丰富的图像细节。最后,通过色彩映射技术,将融合后的多曝光图片进行映射处理,使得最终生成的图片在色彩上更加饱满、自然。
三、算法实现步骤
3.1 读取图像与曝光时间:
代码如下(示例):
def readImagesAndTimes():
"""
该函数用于读取多张图像及其对应的曝光时间。
1. 首先,定义一个曝光时间数组,其中包含四张图像的曝光时间,单位为秒。
2. 接着,定义一个文件名列表,包含四张图像的路径。
3. 使用一个循环遍历文件名列表,对于每个文件名,使用OpenCV的imread函数读取图像。
4. 将读取到的图像添加到images列表中。
5. 循环结束后,返回images列表和曝光时间数组。
:return: images: 包含四张图像的列表。
times: 包含四张图像曝光时间的数组。
"""
times = np.array([1 / 30.0, 0.25, 2.5, 15.0], dtype=np.float32) # 定义曝光时间数组
filenames = ["F:\ccccccc/img09.jpg", "F:\ccccccc/img08.jpg", "F:\ccccccc/img04.jpg", "F:\ccccccc/img01.jpg"] # 定义文件名列表
images = [] # 创建一个空列表来存储图像
for filename in filenames: # 遍历文件名列表
im = cv2.imread(filename) # 使用OpenCV的imread函数读取图像
images.append(im) # 将读取到的图像添加到images列表中
return images, times # 返回images列表和曝光时间数组
3.2 计算响应曲线并合并
计算相机响应曲线(CRF)的过程可以简述如下:
首先,通过分析不同曝光时间下的图像数据,计算出相机的响应曲线,即CRF。这一步通常涉及对图像的亮度进行采样,并使用数学模型(如多项式或指数函数)来拟合这些采样点,从而得到一个能够描述相机如何将场景亮度转换为数字信号的函数。
然后,利用得到的CRF,对多张具有不同曝光时间的图像进行融合处理。这一过程包括以下步骤:
- 将每张图像的像素值根据CRF转换为场景亮度值。
- 对转换后的亮度值进行加权平均,以平衡不同曝光图像之间的亮度差异。
- 将融合后的亮度值重新映射回像素值,得到一张具有宽动态范围的单张图像。
代码如下(示例):
# 创建一个用于计算相机响应函数(CRF)的对象
calibrateDebevec = cv2.createCalibrateDebevec()
# 使用该对象处理多张图像和对应的曝光时间,以计算CRF
responseDebevec = calibrateDebevec.process(images, times)
# 创建一个用于合并多张图像的对象
mergeDebevec = cv2.createMergeDebevec()
# 使用该对象处理多张图像、曝光时间以及计算出的CRF,以合并为一张HDR图像
hdrDebevec = mergeDebevec.process(images, times, responseDebevec)
3.3 色调映射
常见的色调映射方法有三种分别为
1. Drago色调映射:
特点:Drago色调映射算法是基于感知的,它试图模拟人眼对亮度的适应能力。该算法特别强调在低亮度区域保持细节,同时在高亮度区域避免过曝。
参数:通常包括一个对比度参数,用于调整图像的整体对比度。
效果:产生的图像通常具有较好的视觉舒适度和细节保留,特别是在暗部区域。
2. Reinhard色调映射:
特点:Reinhard色调映射算法是基于全局对比度压缩的,它通过调整图像的亮度,使得图像的亮度分布符合特定的统计特性(例如,亮度直方图的均值)。
参数:可能包括亮度、对比度、饱和度和白色点等参数,允许用户对最终图像的外观进行精细调整。
效果:产生的图像通常具有自然的亮度和对比度,但可能在极端亮度和暗度区域丢失一些细节。
3. Mantiuk色调映射:
特点:Mantiuk色调映射算法强调在压缩动态范围的同时保持图像的局部对比度。它使用了一种称为“细节增强”的技术,可以在保留更多细节的同时避免晕轮效应(halos)。
参数:通常包括对比度、饱和度和亮度参数,这些参数可以帮助用户根据需要调整图像的视觉风格。
效果:产生的图像通常具有更高的对比度和更丰富的细节,尤其是在高光和阴影区域。这种算法特别适合于需要强调场景细节和结构的场景。
# 创建一个用于Drago色调映射的对象,并设置对比度参数
tonemapDrago = cv2.createTonemapDrago(1.0, 0.7)
# 使用Drago色调映射对象处理HDR图像,得到LDR图像
ldrDrago = tonemapDrago.process(hdrDebevec)
# 调整LDR图像的亮度,使其更接近标准显示设备的范围
ldrDrago = 3 * ldrDrago
# 将调整后的LDR图像保存为jpg格式
cv2.imwrite("ldr-Drago.jpg", ldrDrago * 255)
# 创建一个用于Reinhard色调映射的对象,并设置对比度参数
tonemapReinhard = cv2.createTonemapReinhard(1.5, 0, 0, 0)
# 使用Reinhard色调映射对象处理HDR图像,得到LDR图像
ldrReinhard = tonemapReinhard.process(hdrDebevec)
# 将Reinhard色调映射后的LDR图像保存为jpg格式
cv2.imwrite("ldr-Reinhard.jpg", ldrReinhard * 255)
# 创建一个用于Mantiuk色调映射的对象,并设置对比度参数
tonemapMantiuk = cv2.createTonemapMantiuk(2.2, 0.85, 1.2)
# 使用Mantiuk色调映射对象处理HDR图像,得到LDR图像
ldrMantiuk = tonemapMantiuk.process(hdrDebevec)
# 调整LDR图像的亮度,使其更接近标准显示设备的范围
ldrMantiuk = 3 * ldrMantiuk
# 将Mantiuk色调映射后的LDR图像保存为jpg格式
cv2.imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255)
四:整体代码实现
import cv2
import numpy as np
def readImagesAndTimes():
times = np.array([1 / 30.0, 0.25, 2.5, 15.0], dtype=np.float32)
filenames = ["F:\ccccccc/img09.jpg", "F:\ccccccc/img08.jpg", "F:\ccccccc/img04.jpg", "F:\ccccccc/img01.jpg"]
images = []
for filename in filenames:
im = cv2.imread(filename)
images.append(im)
return images, times
if __name__ == '__main__':
# Read images and exposure times
print("Reading images ... ")
images, times = readImagesAndTimes()
calibrateDebevec = cv2.createCalibrateDebevec()
responseDebevec = calibrateDebevec.process(images, times)
mergeDebevec = cv2.createMergeDebevec()
hdrDebevec = mergeDebevec.process(images, times, responseDebevec)
# Save HDR image.
cv2.imwrite("hdrDebevec.hdr", hdrDebevec)
print("saved hdrDebevec.jpg ")
# # Tonemap using Drago's method to obtain 24-bit color image
tonemapDrago = cv2.createTonemapDrago(1.0, 0.7)
ldrDrago = tonemapDrago.process(hdrDebevec)
ldrDrago = 3 * ldrDrago
cv2.imwrite("ldr-Drago.jpg", ldrDrago * 255)
# # Tonemap using Reinhard's method to obtain 24-bit color image
tonemapReinhard = cv2.createTonemapReinhard(1.5, 0, 0, 0)
ldrReinhard = tonemapReinhard.process(hdrDebevec)
cv2.imwrite("ldr-Reinhard.jpg", ldrReinhard * 255)
# # Tonemap using Mantiuk's method to obtain 24-bit color image
tonemapMantiuk = cv2.createTonemapMantiuk(2.2, 0.85, 1.2)
ldrMantiuk = tonemapMantiuk.process(hdrDebevec)
ldrMantiuk = 3 * ldrMantiuk
cv2.imwrite("ldr-Mantiuk.jpg", ldrMantiuk * 255)
五:效果
不同曝光图像:
融合后的图像:
drago:
Reinhard:
Mantiuk: