You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python将.hdr文件转换为带完整色彩的可见格式?

HDR转可见格式的色彩异常问题与解决方案

问题描述

我需要将.hdr文件转换为可见格式,使用Photomatix Pro软件完成转换后得到了满意的全彩结果:
转换效果示例

但使用以下Python代码(基于OpenCV和Matplotlib)转换时,输出图像色彩异常:
Python转换效果

原代码:

from pathlib import Path
import cv2

current_folder = Path().resolve()

filename = "hdr"
hdr_path = str(Path(current_folder, filename + ".hdr"))


img = cv2.imread(hdr_path,flags=cv2.IMREAD_ANYDEPTH)

import matplotlib.pyplot as plt

plt.imshow(img)
plt.axis('off')
result_path = Path(current_folder, filename + '.png')
plt.savefig(result_path)

问题根源

  1. 色彩空间不匹配:OpenCV默认以BGR格式读取图像,而Matplotlib显示时采用RGB格式,直接显示会导致色彩反转。
  2. 缺失色调映射:HDR图像动态范围远超普通显示设备,必须通过色调映射压缩动态范围,才能还原出类似专业软件的全彩效果,原代码未做此处理。

可行解决方案

方案1:OpenCV自带Drago色调映射(兼顾色彩与对比度)

from pathlib import Path
import cv2
import numpy as np
import matplotlib.pyplot as plt

current_folder = Path().resolve()
filename = "hdr"
hdr_path = str(Path(current_folder, filename + ".hdr"))

# 读取HDR图像并转换色彩空间
hdr_img = cv2.imread(hdr_path, flags=cv2.IMREAD_ANYDEPTH)
hdr_img_rgb = cv2.cvtColor(hdr_img, cv2.COLOR_BGR2RGB)

# 应用Drago色调映射,参数可按需调整
tonemap = cv2.createTonemapDrago(gamma=2.2, saturation=1.0, bias=0.85)
ldr_img = tonemap.process(hdr_img_rgb)
# 转换为8位图像格式
ldr_img_8bit = np.uint8(ldr_img * 255)

# 保存结果(转回BGR适配OpenCV保存逻辑)
result_path = Path(current_folder, filename + '_corrected.png')
cv2.imwrite(str(result_path), cv2.cvtColor(ldr_img_8bit, cv2.COLOR_RGB2BGR))

# 预览效果
plt.imshow(ldr_img_8bit)
plt.axis('off')
plt.show()

方案2:OpenCV Mantiuk色调映射(接近Photomatix风格)

Mantiuk算法在色彩保留和对比度优化上更贴近专业HDR软件效果:

from pathlib import Path
import cv2
import numpy as np

current_folder = Path().resolve()
filename = "hdr"
hdr_path = str(Path(current_folder, filename + ".hdr"))

hdr_img = cv2.imread(hdr_path, flags=cv2.IMREAD_ANYDEPTH)
# 转换到Lab色彩空间单独处理亮度通道
hdr_img_lab = cv2.cvtColor(hdr_img, cv2.COLOR_BGR2LAB)
l_channel, a_channel, b_channel = cv2.split(hdr_img_lab)

# 应用Mantiuk色调映射
tonemap_mantiuk = cv2.createTonemapMantiuk(gamma=1.0, scale=0.7, saturation=1.1)
l_channel_tonemapped = tonemap_mantiuk.process(l_channel)
l_channel_8bit = np.uint8(l_channel_tonemapped * 255)

# 合并通道并转回BGR格式
tonemapped_lab = cv2.merge((l_channel_8bit, a_channel, b_channel))
tonemapped_img = cv2.cvtColor(tonemapped_lab, cv2.COLOR_LAB2BGR)

# 保存图像
result_path = Path(current_folder, filename + '_mantiuk.png')
cv2.imwrite(str(result_path), tonemapped_img)

方案3:OpenEXR+PIL灵活处理

若需更底层的HDR文件解析,可使用OpenEXR库读取,再搭配PIL完成格式转换:

from pathlib import Path
import OpenEXR
import Imath
import numpy as np
from PIL import Image

current_folder = Path().resolve()
filename = "hdr"
hdr_path = str(Path(current_folder, filename + ".hdr"))

# 读取HDR文件的RGB通道
file = OpenEXR.InputFile(hdr_path)
dw = file.header()['dataWindow']
size = (dw.max.x - dw.min.x + 1, dw.max.y - dw.min.y + 1)

pt = Imath.PixelType(Imath.PixelType.FLOAT)
r = np.frombuffer(file.channel('R', pt), dtype=np.float32)
g = np.frombuffer(file.channel('G', pt), dtype=np.float32)
b = np.frombuffer(file.channel('B', pt), dtype=np.float32)

# 重组为RGB图像矩阵
rgb = np.stack((r, g, b), axis=1).reshape(size[1], size[0], 3)

# 伽马校正+归一化完成简单色调映射
gamma = 2.2
rgb_tonemapped = np.power(np.clip(rgb, 0, 1), 1/gamma)
rgb_8bit = (rgb_tonemapped * 255).astype(np.uint8)

# 保存图像
result_path = Path(current_folder, filename + '_exr.png')
Image.fromarray(rgb_8bit).save(result_path)

注意事项

  • 不同HDR图像需调整色调映射参数(如gamma、saturation),才能匹配Photomatix Pro的输出效果。
  • 提前安装依赖:pip install opencv-python numpy openexr pillow

内容的提问来源于stack exchange,提问作者Luke Ha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 06:06:26