别再死记硬背了!用Python亲手画出Gamma、HLG、PQ曲线,彻底搞懂HDR传递函数

张开发
2026/4/17 9:22:31 15 分钟阅读

分享文章

别再死记硬背了!用Python亲手画出Gamma、HLG、PQ曲线,彻底搞懂HDR传递函数
用Python绘制HDR传递函数曲线从数学公式到视觉直觉在数字影像处理领域Gamma、HLG和PQ曲线是三种关键的传递函数它们决定了如何将现实世界中的光线强度映射到数字信号以及如何在显示设备上还原这些信号。对于开发者而言理解这些曲线的形状和背后的设计原理至关重要但传统的数学公式往往让人望而生畏。本文将带你用Python代码亲手绘制这些曲线通过可视化手段建立直观理解。1. 环境准备与基础概念在开始编码之前我们需要明确几个核心概念。传递函数本质上是一种非线性变换用于解决两个关键问题一是人眼对亮度的感知是非线性的二是数字存储的带宽有限。通过这种变换我们可以在有限的比特深度下更好地保留视觉上重要的信息。首先安装必要的Python库pip install numpy matplotlib然后导入我们将要使用的模块import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter传递函数分为两种基本类型OETF光电转换函数将场景光线转换为电信号EOTF电光转换函数将电信号转换为显示光线注意在实际应用中我们还需要考虑OOTF光-光转换函数它描述了从场景光线到显示光线的完整转换链。2. Gamma曲线实现与分析Gamma曲线是SDR标准动态范围内容的基础它的历史可以追溯到CRT显示器的物理特性。虽然现代显示技术已经不再依赖这种物理特性但Gamma校正仍然被广泛使用。2.1 BT.709 Gamma函数实现BT.709标准定义的Gamma曲线有一个独特的特点在低亮度区域使用线性段而在高亮度区域使用幂律曲线。这种设计是为了避免在暗部出现明显的量化噪声。def bt709_oetf(L): BT.709 OETF函数 alpha 1.099 beta 0.018 return np.where(L beta, 4.5 * L, alpha * np.power(L, 0.45) - (alpha - 1)) def bt709_eotf(V): BT.709 EOTF函数逆OETF alpha 1.099 beta 0.018 return np.where(V 4.5 * beta, V / 4.5, np.power((V alpha - 1) / alpha, 1/0.45))2.2 Gamma曲线可视化让我们绘制BT.709的OETF和EOTF曲线L np.linspace(0, 1, 1000) V bt709_oetf(L) L_recon bt709_eotf(V) plt.figure(figsize(12, 6)) plt.plot(L, V, labelOETF (编码)) plt.plot(V, L_recon, labelEOTF (解码), linestyle--) plt.title(BT.709 Gamma传递函数) plt.xlabel(线性光信号) plt.ylabel(非线性电信号) plt.legend() plt.grid(True) plt.show()从图中我们可以观察到几个关键特征在低亮度区域L 0.018曲线是线性的斜率为4.5在高亮度区域曲线遵循L^0.45的幂律关系整个曲线是单调递增的保证了可逆性提示线性段的引入是为了避免在极暗区域出现量化噪声这在8位色彩深度中尤为重要。3. HLG曲线实现与分析混合对数GammaHLG是由BBC和NHK联合开发的HDR高动态范围传递函数。它的独特之处在于结合了对数曲线和Gamma曲线的特性既保持了与SDR显示器的兼容性又扩展了动态范围。3.1 HLG函数实现HLG标准定义在ITU-R BT.2100中其核心公式分为两部分def hlg_oetf(E): HLG OETF函数 a 0.17883277 b 0.28466892 c 0.55991073 r 0.5 return np.where(E 1/12, np.sqrt(3 * E), a * np.log(12 * E - b) c) def hlg_oetf_inverse(E_prime): HLG OETF逆函数 a 0.17883277 b 0.28466892 c 0.55991073 return np.where(E_prime 0.5, (E_prime ** 2) / 3, (np.exp((E_prime - c) / a) b) / 12)3.2 HLG曲线可视化绘制HLG曲线并与Gamma曲线对比E np.linspace(0, 1, 1000) E_prime hlg_oetf(E) E_recon hlg_oetf_inverse(E_prime) plt.figure(figsize(12, 6)) plt.plot(E, E_prime, labelHLG OETF) plt.plot(E, bt709_oetf(E), labelBT.709 OETF, linestyle--) plt.title(HLG与BT.709传递函数对比) plt.xlabel(线性光信号) plt.ylabel(非线性电信号) plt.legend() plt.grid(True) plt.show()HLG曲线的特点包括在低亮度区域E ≤ 1/12使用平方根函数实际上是Gamma0.5在高亮度区域使用对数函数在交界点E1/12处函数值和导数都是连续的整体动态范围比Gamma曲线大得多4. PQ曲线实现与分析感知量化PQ曲线是由杜比实验室开发的另一种HDR传递函数正式名称为SMPTE ST 2084。PQ基于对人眼视觉系统的精确建模能够表示高达10,000尼特的亮度。4.1 PQ函数实现PQ曲线的数学表达式相对复杂包含多个拟合参数def pq_eotf(E_prime): PQ EOTF函数 m1 2610 / 16384 m2 2523 / 32 c1 3424 / 4096 c2 2413 / 128 c3 2392 / 128 E_prime_m2 np.power(E_prime, 1/m2) numerator np.maximum(E_prime_m2 - c1, 0) denominator c2 - c3 * E_prime_m2 return 10000 * np.power(numerator / denominator, 1/m1) def pq_eotf_inverse(F_D): PQ EOTF逆函数 m1 2610 / 16384 m2 2523 / 32 c1 3424 / 4096 c2 2413 / 128 c3 2392 / 128 Y np.power(F_D / 10000, m1) return np.power((c1 c2 * Y) / (1 c3 * Y), m2)4.2 PQ曲线可视化绘制PQ曲线并与前两种曲线对比E_prime_pq np.linspace(0, 1, 1000) F_D pq_eotf(E_prime_pq) E_prime_recon pq_eotf_inverse(F_D) plt.figure(figsize(12, 6)) plt.plot(F_D, E_prime_pq, labelPQ EOTF逆函数) plt.plot(F_D, hlg_oetf(F_D/10000), labelHLG OETF, linestyle--) plt.xscale(log) plt.title(PQ与HLG传递函数对比对数x轴) plt.xlabel(亮度尼特对数尺度) plt.ylabel(非线性电信号) plt.legend() plt.grid(True) plt.show()PQ曲线的显著特征包括覆盖的动态范围极大0.0001到10,000尼特曲线形状基于Barten视觉模型优化在低亮度区域比HLG更陡峭保留更多暗部细节在高亮度区域变化平缓有效利用编码空间5. 三种曲线综合对比与应用场景现在我们将三种传递函数放在同一坐标系中进行比较分析它们各自的特点和适用场景。5.1 归一化对比为了公平比较我们将所有曲线归一化到[0,1]范围L_norm np.linspace(0, 1, 1000) gamma bt709_oetf(L_norm) hlg hlg_oetf(L_norm) pq pq_eotf_inverse(L_norm * 10000) # PQ需要特殊处理 plt.figure(figsize(12, 6)) plt.plot(L_norm, gamma, labelBT.709 Gamma) plt.plot(L_norm, hlg, labelHLG) plt.plot(L_norm, pq, labelPQ) plt.title(三种传递函数归一化对比) plt.xlabel(归一化线性光信号) plt.ylabel(归一化非线性电信号) plt.legend() plt.grid(True) plt.show()从对比图中可以看出Gamma曲线的动态范围最小主要服务于SDR内容HLG曲线在低亮度区域与Gamma接近有利于兼容SDR显示PQ曲线在暗部更陡峭亮部更平缓充分利用编码空间5.2 应用场景分析每种传递函数都有其最适合的应用场景传递函数动态范围兼容性典型应用Gamma低 (~1000:1)仅SDR传统电视、网络视频HLG中 (~20000:1)SDR/HDR广播电视、直播PQ高 (~2000000:1)仅HDR电影制作、高端流媒体注意选择传递函数时需要考虑整个工作流程从内容创作到最终显示的各个环节。5.3 实际应用代码示例以下是一个完整的Python脚本可以生成三种传递函数的对比图并保存为高分辨率图片import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter # 定义传递函数 def bt709_oetf(L): return np.where(L 0.018, 4.5 * L, 1.099 * np.power(L, 0.45) - 0.099) def hlg_oetf(E): return np.where(E 1/12, np.sqrt(3 * E), 0.17883277 * np.log(12 * E - 0.28466892) 0.55991073) def pq_eotf_inverse(F_D): Y np.power(F_D / 10000, 2610/16384) return np.power((0.8359375 18.8515625 * Y) / (1 18.6875 * Y), 2523/32) # 创建画布 plt.figure(figsize(14, 8), dpi300) # 计算曲线数据 x np.linspace(0, 1, 1000) gamma bt709_oetf(x) hlg hlg_oetf(x) pq pq_eotf_inverse(x * 10000) # 绘制曲线 plt.plot(x, gamma, labelBT.709 Gamma, linewidth2.5) plt.plot(x, hlg, labelHLG (BT.2100), linewidth2.5) plt.plot(x, pq, labelPQ (ST 2084), linewidth2.5) # 设置图表样式 plt.title(HDR传递函数对比, fontsize16, pad20) plt.xlabel(归一化线性光信号, fontsize12) plt.ylabel(归一化非线性电信号, fontsize12) plt.legend(fontsize12, framealpha0.9) plt.grid(True, linestyle--, alpha0.6) # 保存图片 plt.savefig(hdr_transfer_functions_comparison.png, bbox_inchestight, dpi300) plt.close()这个脚本生成的图片可以直接用于技术文档或演示材料清晰地展示三种传递函数的差异。

更多文章