3. HDR视频的色彩空间转换
任务说明
本案例实现BT.709(SDR)与BT.2020(HDR)色彩空间的主转换逻辑:将BT.709非线性RGB转换至BT.2020非线性RGB,并给出可逆的逆变换。转换过程包含RGB基色矩阵变换与传递函数(伽马/HLG)适配,确保色彩在跨空间转换时保持色相与亮度准确。
核心实现
import numpy as np
# BT.709 与 BT.2020 的 RGB 基色矩阵(线性光域)
# 矩阵 M709_to_2020: 将 BT.709 线性RGB 转换到 BT.2020 线性RGB
M709_to_2020 = np.array([
[ 0.6274039, 0.3292830, 0.0433131],
[ 0.0690973, 0.9195404, 0.0113623],
[ 0.0163916, 0.0880133, 0.8955951]
])
# 逆矩阵:BT.2020 线性RGB -> BT.709 线性RGB
M2020_to_709 = np.linalg.inv(M709_to_2020)
def bt709_oetf(linear):
"""BT.709 光电转换(OETF):线性光 -> 非线性信号"""
return np.where(linear <= 0.018,
4.5 * linear,
1.099 * np.power(linear, 0.45) - 0.099)
def bt709_eotf(nonlinear):
"""BT.709 电光转换(EOTF):非线性信号 -> 线性光"""
return np.where(nonlinear <= 0.081,
nonlinear / 4.5,
np.power((nonlinear + 0.099) / 1.099, 1/0.45))
def bt2020_hlg_oetf(linear):
"""BT.2020 HLG OETF:线性光 -> HLG 非线性信号(归一化到[0,1])"""
a, b, c = 0.17883277, 0.28466892, 0.55991073
return np.where(linear <= 1/12,
np.sqrt(3 * linear),
a * np.log(12 * linear - b) + c)
def bt2020_hlg_eotf(nonlinear):
"""BT.2020 HLG EOTF:HLG 非线性信号 -> 线性光"""
a, b, c = 0.17883277, 0.28466892, 0.55991073
return np.where(nonlinear <= 0.5,
(nonlinear ** 2) / 3,
(np.exp((nonlinear - c) / a) + b) / 12)
def convert_sdr_to_hdr(rgb_709_nonlinear):
"""
将 BT.709 非线性 RGB(SDR)转换为 BT.2020 HLG 非线性 RGB(HDR)
输入/输出均为 [0,1] 范围的非线性信号
"""
# 1. BT.709 非线性 -> 线性
linear_709 = bt709_eotf(rgb_709_nonlinear)
# 2. BT.709 线性 -> BT.2020 线性(基色矩阵变换)
linear_2020 = M709_to_2020 @ linear_709
# 3. BT.2020 线性 -> HLG 非线性
hlg_2020 = bt2020_hlg_oetf(linear_2020)
return hlg_2020
def convert_hdr_to_sdr(rgb_2020_hlg):
"""
将 BT.2020 HLG 非线性 RGB(HDR)转换为 BT.709 非线性 RGB(SDR)
输入/输出均为 [0,1] 范围的非线性信号
"""
# 1. HLG 非线性 -> 线性
linear_2020 = bt2020_hlg_eotf(rgb_2020_hlg)
# 2. BT.2020 线性 -> BT.709 线性
linear_709 = M2020_to_709 @ linear_2020
# 3. BT.709 线性 -> 非线性
rgb_709_nonlinear = bt709_oetf(linear_709)
return rgb_709_nonlinear
# 示例:SDR 肤色信号(BT.709 非线性)
sdr_color = np.array([0.8, 0.4, 0.3])
hdr_color = convert_sdr_to_hdr(sdr_color)
round_trip = convert_hdr_to_sdr(hdr_color)
print("SDR输入 (BT.709):", sdr_color)
print("HDR输出 (BT.2020 HLG):", np.round(hdr_color, 6))
print("往返还原 (BT.709):", np.round(round_trip, 6))
print("最大误差:", np.max(np.abs(round_trip - sdr_color)))
落地与验证
运行方式:保存为 color_space_convert.py,执行 python color_space_convert.py。需要 numpy 库(pip install numpy)。
验证方法:观察输出中“往返还原”值与原始SDR输入是否一致。由于矩阵变换与传递函数均为数学可逆操作,往返误差应接近浮点精度(约1e-6量级)。若误差在1e-5以下,说明正逆转换自洽,色彩空间转换链路正确。
判定标准
执行后若满足以下条件,则案例通过:
- 程序无异常退出,输出三行数值与最大误差;
- “最大误差”小于
1e-5,证明正逆转换数学自洽; - HDR输出值域在
[0,1]内(HLG信号合法范围)。