opencv-python图像增强四:多曝光融合(方法一)


一、简介:

在摄影和计算机视觉领域,高动态范围(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,对多张具有不同曝光时间的图像进行融合处理。这一过程包括以下步骤:

  1. 将每张图像的像素值根据CRF转换为场景亮度值。
  2. 对转换后的亮度值进行加权平均,以平衡不同曝光图像之间的亮度差异。
  3. 将融合后的亮度值重新映射回像素值,得到一张具有宽动态范围的单张图像。

代码如下(示例):

# 创建一个用于计算相机响应函数(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:在这里插入图片描述

根据提供的引用内容,有两种常见的基于OpenCV图像增强算法可以使用C++实现: 1. 基于Retinex理论的图像增强算法:Retinex理论是一种常见的图像增强方法,它通过对图像的亮度和对比度进行调整来提高图像的质量。以下是一个使用OpenCV和C++实现的基于Retinex的图像增强算法的示例代码: ```cpp #include <opencv2/opencv.hpp> cv::Mat enhanceImage(cv::Mat image) { cv::Mat enhancedImage; // 使用Retinex算法增强图像 cv::xphoto::createSimpleRetinex()->apply(image, enhancedImage); return enhancedImage; } int main() { // 读取图像 cv::Mat image = cv::imread("image.jpg"); // 图像增强 cv::Mat enhancedImage = enhanceImage(image); // 显示增强后的图像 cv::imshow("Enhanced Image", enhancedImage); cv::waitKey(0); return 0; } ``` 2. Zhang-Suen细化算法:Zhang-Suen细化算法是一种用于提取图像骨架的二值图像处理算法。以下是一个使用OpenCV和C++实现的Zhang-Suen细化算法的示例代码: ```cpp #include <opencv2/opencv.hpp> cv::Mat thinningImage(cv::Mat image) { cv::Mat binaryImage; // 将图像转换为二值图像 cv::cvtColor(image, binaryImage, cv::COLOR_BGR2GRAY); cv::threshold(binaryImage, binaryImage, 128, 255, cv::THRESH_BINARY); // 使用Zhang-Suen细化算法提取图像骨架 cv::ximgproc::thinning(binaryImage, binaryImage, cv::ximgproc::THINNING_ZHANGSUEN); return binaryImage; } int main() { // 读取图像 cv::Mat image = cv::imread("image.jpg"); // 图像细化 cv::Mat thinnedImage = thinningImage(image); // 显示细化后的图像 cv::imshow("Thinned Image", thinnedImage); cv::waitKey(0); return 0; } ``` 请注意,以上示例代码仅为演示目的,实际使用时可能需要根据具体需求进行适当的调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值