一、PQ(Perceptual Quantizer)与 HLG(Hybrid Log-Gamma)的核心原理
-
PQ 曲线(SMPTE ST 2084)
- 目标:在绝对亮度范围内(0~10,000 尼特)优化人眼感知,通过非线性量化分配更多码值给暗部细节。
- 公式:
-
HLG 曲线(ARIB STD-B67)
- 目标:兼容 SDR 显示设备,使用相对亮度编码(基于场景亮度动态范围)。
- 分段函数:
二、代码实现:PQ/HLG 编码与显示驱动映射
以下示例以 Python 演示 PQ 编码和 HLG 解码,并模拟显示驱动的亮度映射逻辑:
import numpy as np
import matplotlib.pyplot as plt
# ======================= PQ 编码(OETF) =======================
def pq_eotf(Y):
Y = np.clip(Y, 0, 1) # 输入归一化亮度(0~1)
c1, c2, c3, c4 = 0.8359, 18.8516, 1.0, 18.6875
m1, m2 = 0.1593, 78.8438
numerator = np.maximum(c1 + c2 * (Y ** m1), 0)
denominator = c3 + c4 * (Y ** m1)
L = (numerator / denominator) ** m2
return L # 输出绝对亮度(需映射到显示器物理亮度)
# ======================= HLG 解码(EOTF) =======================
def hlg_oetf(E):
a, b, c = 0.17883277, 0.28466892, 0.55991073
mask = E <= 1/2 # 分段处理
Y = np.zeros_like(E)
Y[mask] = (E[mask] ** 2) / 3 # 暗部伽马解码
Y[~mask] = np.exp((E[~mask] - c) / a) + b # 亮部对数解码
return Y # 输出相对场景亮度(0~12 尼特,需显示器动态适配)
# ======================= 模拟显示驱动处理 =======================
def display_driver(signal, curve_type='PQ', max_nits=1000):
if curve_type == 'PQ':
# PQ 需要绝对亮度映射(根据显示器最大亮度缩放)
display_light = signal * max_nits # 假设显示器支持 max_nits 亮度
elif curve_type == 'HLG':
# HLG 转换为相对亮度(默认场景亮度 12 尼特,按显示器能力等比放大)
scene_ref_nits = 12
display_light = signal * (max_nits / scene_ref_nits)
else:
raise ValueError("Unsupported curve type")
return np.clip(display_light, 0, max_nits)
# ======================= 测试与可视化 =======================
# 生成测试信号:线性亮度阶梯
linear_Y = np.linspace(0, 1, 1024)
# PQ 编码 -> 显示驱动处理
pq_encoded = pq_eotf(linear_Y)
pq_display = display_driver(pq_encoded, 'PQ', 1000) # 假设显示器支持 1000 尼特
# HLG 编码 -> 显示驱动处理
hlg_encoded = hlg_oetf(linear_Y) # 此处假设输入为 HLG 电信号
hlg_display = display_driver(hlg_encoded, 'HLG', 500) # 假设显示器支持 500 尼特
# 绘制结果对比
plt.figure(figsize=(10,6))
plt.plot(linear_Y, pq_display, label='PQ (1000 nits)')
plt.plot(linear_Y, hlg_display, label='HLG (500 nits)')
plt.xlabel('Input Signal')
plt.ylabel('Display Brightness (nits)')
plt.title('HDR Display Driver Mapping: PQ vs HLG')
plt.legend()
plt.grid(True)
plt.show()
三、显示驱动的作用与代码解释
-
PQ 的显示驱动处理
- 关键逻辑:将 PQ 编码的绝对亮度值(0~10,000 尼特)按显示器最大亮度(如 1000 尼特)线性缩放。
- 代码实现:
display_driver
函数中,对 PQ 信号直接乘以显示器支持的最大亮度值。 - 影响:若显示器亮度不足,高光细节会被压缩(例如 5000 尼特内容在 1000 尼特屏上显示为 1000 尼特)。
-
HLG 的显示驱动处理
- 关键逻辑:根据 HLG 的相对亮度(默认场景参考亮度 12 尼特),按显示器能力动态扩展。
- 代码实现:将 HLG 解码后的亮度值按比例放大至显示器支持范围(如 500 尼特)。
- 优势:在低亮度显示器(如 500 尼特)上仍能保持场景亮度层次感,无需元数据支持。
四、实际应用场景对比
特性 | PQ | HLG |
---|---|---|
亮度编码 | 绝对亮度(0~10,000 尼特) | 相对亮度(基于场景动态范围) |
兼容性 | 需 HDR 显示设备 | 兼容 SDR/HDR 显示设备 |
典型应用 | HDR10、杜比视界 | 广播电视、实时流媒体 |
显示驱动处理 | 依赖静态元数据(MaxCLL/MaxFALL) | 动态适配显示器亮度范围 |
五、总结
通过 PQ 和 HLG 的代码实现与显示驱动模拟,可以看出:
- PQ 适合追求极致画质的场景(如影院级 HDR),但依赖高亮度硬件和精确元数据。
- HLG 更适用于广播和流媒体,兼顾不同设备的显示能力。
- 显示驱动 需根据算法类型动态调整亮度映射策略,以正确还原 HDR 内容。