HDR转SDR实践之旅(七)Gamma、HLG、PQ公式详解
本篇文章讲的就是Gamma、HLG、PQ公式的各种参数详细解释,帮忙开发者更好理解HDR究竟是怎么回事
HDR视频的传递函数
视频用传递函数Gamma、HLG、PQ压缩亮度,然而大多数开发对传递函数的参数不了解导致使用时出现问题,本篇文章讲的就是Gamma、HLG、PQ公式的各种参数详细解释。如果你觉得有所收获,来给HDR转SDR开源代码点个赞吧,你的鼓励是我前进最大的动力。
SDR视频的传递函数使用Gamma函数,HDR视频为了存储更大范围的亮度使用HLG(Hybrid Log-Gamma混合对数)、PQ(Perceptual Quantization感知量化),如下图所示就是Gamma、HLG、PQ曲线图。
元数据
HDR视频有四种格式,视频格式不同传递函数也不一样。
HDR视频 | 传递函数 | 元数据 | 位数 |
---|---|---|---|
PQ10 | PQ | ST-2084无元数据 | 10位 |
HDR10 | PQ/HLG | ST-2086静态元数据 | 10位 |
HDR10+ | PQ | ST-2094-40动态元数据 | 10位 |
Dolby Vision | PQ | ST-2094-10动态元数据 | 10位/12位 |
注意:
-
HDR视频播放时需要根据每一帧的亮度信息调整效果,但是亮度信息计算很慢不适合放在播放阶段,为了解决这个问题会在视频制作时就直接生成亮度信息,亮度信息就是所谓的元数据(metadata)。H265的元数据放在SEI/VUI中,解码时只要识别即可不影响原先的解码流程,又能直接利用元数据生成HDR效果。
-
下图就是SEI(Supplemental Enhancement Information补充增强信息)中的元数据
- display_primaries是色域三原色
- white_point是白点
- display_mastering_Luminance就是制作HDR视频的显示器亮度
-
下图就是VUI(Video Usability Information视频可用信息)中的元数据。
- colour_parimaries表明哪个色域
- transfer_characteristics表明使用哪个传输函数
- matrix_coeffs表明使用哪个YUV转RGB矩阵。
-
按总体亮度还是每帧亮度又分为ST2086静态元数据和ST2094动态元数据(ST是电影电视工程师协会的英文缩写),ST2094-10、ST2094-20、ST2094-30、ST2094-40分别对应杜比、飞利浦、特艺和三星四家公司。
-
位深就是每个通道颜色的存储位数,SDR视频是8位,HDR视频10位/12位。
传递函数是怎么设计的
传递函数只要有Gamma函数就行了,为什么还要有HLG、PQ函数呢?因为Gamma只能产生1000的对比度(0.1-100的亮度),HLG能产生20000的对比度(0.005-1000亮度),PQ甚至产生2000000对比度(0.0005-10000亮度)。三个函数解决的问题不一样,Gamma函数解决8位的暗部细节问题,HLG函数既兼容Gamma函数又能处理10位数据,PQ函数能最大幅度利用10位或12位数据。
上图是网上找到的Gamma、HLG、PQ三条曲线,曲线可以自己动手用公式画出来。
亮度感知模型
那么为什么传递函数的曲线要这么设计呢?
不同的传递函数其实是根据不同的数学模型计算出来的,合适的传递函数需要考虑人眼对于亮度变化的察觉阈值(术语最小可觉差
),传递函数要与最小可觉差相贴合,不能太大也不能太小,太大会导致色阶断层,太小会浪费数据带宽。如果亮度用L表示,最小可觉差用△L表示,设计传递函数曲线其实就是找合适的
△
L
L
\frac{△L}{L}
L△L曲线。
上图所有传递函数的曲线都用 △ L L \frac{△L}{L} L△L表示,横坐标是L,纵坐标是 △ L L \frac{△L}{L} L△L,曲线下方区域小于最小可觉差,曲线上方区域大于最小可觉差。
注意:
-
根据韦伯费希纳定律,亮度感知是对数均匀,对应的编码方式就是Log编码,该编码对0-1000亮度适用,在 △ L L \frac{△L}{L} L△L图中是一条红色横线,而用物理亮度和视觉亮度关系表示就是下图,S-log是索尼相机的log曲线。
-
根据史蒂文斯幂定律,亮度感知是立方根均匀,对应的编码方式就是Gamma编码,SDR视频用的传递函数就是Gammma编码,只不过因为屏幕绝对亮度不高选用平方根而不是立方根,该编码对0-100亮度更适用,在 △ L L \frac{△L}{L} L△L图中就是一条蓝色斜线。下图就是史蒂文斯幂定律测出来的值,其中点光源的幂指数0.5和BT709 Gamma使用的0.45很接近。
-
根据Schreiber Curve定律(1992年Schreiber发现的规律),亮度感知暗处是平方根均匀、明处是对数均匀,对应编码就是HLG编码,下方黄色曲线就是带HLG的 △ L L \frac{△L}{L} L△L图。
HLG用物理亮度和视觉亮度关系表示就是下图,HLG前半部分贴合Gamma曲线后半部分是LOG曲线,这也是为什么HLG叫混合对数编码的原因。
-
根据Barten Ramp视觉模型(1992年Barten发表的论文模型),Baren Ramp曲线是人类最小可觉差模型,越贴合Baren Ramp曲线视觉越平滑,PQ曲线尽量贴合Baren ramp曲线,对应编码就是PQ函数,在 △ L L \frac{△L}{L} L△L图中是一条绿色曲线,用物理亮度和视觉亮度关系表示就是下图。
传递函数公式
传递函数的公式代码在zimg中可以看到,但是公式中的参数都不解释很容易一脸懵逼,为了尽可能地把公式解释清楚花了好几天查阅了各种资料,争取把每个参数是什么、参数是怎么设计考虑的都讲明白,没讲明白的参数欢迎大家在评论区讲解。
首先大家要先明白传递函数是为了转换线性光和非线性电,其中各种符号如下
- O E T F OETF OETF表示把自然场景的场景光 O O O转换成电信号 E E E
- O E T F − 1 OETF^-1 OETF−1表示把电信号 E E E转换成自然场景的场景光 O O O
- O O T F OOTF OOTF表示把自然场景的场景光 O O O转换成屏幕的显示光 O O O, O O O和 O O O不一样,
- O O T F − 1 OOTF^-1 OOTF−1表示把屏幕的显示光 O O O转换成自然场景的场景光 O O O
- E O T F EOTF EOTF表示把电信号 E E E转换成屏幕的显示光 O O O,该过程和 O E T F OETF OETF不是完全可逆的,中间会经过 O O T F OOTF OOTF处理,即 E O T F = O E T F − 1 ∗ O O T F EOTF = OETF^{-1}*OOTF EOTF=OETF−1∗OOTF
- E O T F − 1 EOTF^-1 EOTF−1表示把屏幕的显示光 O O O转换成电信号 E E E
注意:
- E代表电,O代表光。
- O有两种,自然场景的场景光和屏幕的显示光,
- 在转换过程中以场景光为基准叫场景参考,以显示光为参考叫显示参考。拍摄用时场景参考转换效果更好,编辑时用显示参考转换效果更好。
BT709 Gamma
BT709 Gamma函数一般都直接简化成了OETF x 0.45 x^{0.45} x0.45曲线或者EOTF x 2.2 x^{2.2} x2.2讲解,但是其实在亮度很小时Gamma函数其实是条直线,因为如果全部使用 x 0.45 x^{0.45} x0.45曲线的话会丢失黑色阴影附近的值,如下图所示BT709 Gamma和Gamma2.2还是有一定区别的。
OETF
注意:
-
L就是场景光信号(范围 [ 0 , 1 ] [0,1] [0,1]),V就是电信号也就是非线性RGB(范围 [ 0 , 1 ] [0,1] [0,1])
-
理论上 x 0.45 x^{0.45} x0.45曲线也可以,但是屏幕反光会导致暗部细节丢失,需要把暗部变暗也就是曲线前半段往下拉。如果乘以小于1的系数会把整段曲线都往下拉,怎么解决呢?设系数为 α \alpha α,曲线变成 α ∗ x 0.45 \alpha*x^{0.45} α∗x0.45, x = 1 x=1 x=1时该曲线的值等于 α \alpha α, α \alpha α小于1需要把 α \alpha α变成 1 1 1,很简单加上 1 − α 1-\alpha 1−α就行,公式从 x 0.45 x^{0.45} x0.45变成了 α ∗ x 0.45 + 1 − α \alpha*x^{0.45}+1-\alpha α∗x0.45+1−α
-
α ∗ x 0.45 + 1 − α \alpha*x^{0.45}+1-\alpha α∗x0.45+1−α曲线的前半段小于0,BT709把前半段曲线变成斜率为4.5的直线解决负数问题(斜率为什么选4.5没找到资料),设前半段分界线 x x x值等于 β \beta β,那么公式变成了
{ 4.5 ∗ x , x < β , 直线 α ∗ x 0.45 + 1 − α , β < = x < = 1 , 曲线 \left \{ \begin{aligned} &4.5*x, x<\beta ,\ 直线\\ &\alpha*x^{0.45}+1-\alpha, \beta<=x<=1 ,\ 曲线\\ \end{aligned} \right. {4.5∗x,x<β, 直线α∗x0.45+1−α,β<=x<=1, 曲线
为了平滑上述公式中的两条线,列出以下方程
{ 4.5 ∗ β = α ∗ β 0.45 + 1 − α ,两条线连接处相等 4.5 = 0.45 ∗ α ∗ β − 0.55 ,两条线连接处的导数相等 \left \{ \begin{aligned} &4.5*\beta = \alpha*\beta^{0.45}+1-\alpha,两条线连接处相等\\ &4.5= 0.45*\alpha*\beta^{-0.55},两条线连接处的导数相等\\ \end{aligned} \right. {4.5∗β=α∗β0.45+1−α,两条线连接处相等4.5=0.45∗α∗β−0.55,两条线连接处的导数相等最终算出 α = 1.099 , β = 0.018 \alpha = 1.099,\beta = 0.018 α=1.099,β=0.018,也就是前面公式值的由来。
-
经过BT709处理过后的Gamma0.45反而更接近 x 0.5 x^{0.5} x0.5。
EOTF
注意:
上述公式就是OETF的逆过程
HLG
HLG刚开始是英国BBC和日本NHK电视台为了让HDR视频兼容SDR屏幕提出来的ARIB STD-B67(ARIB是日本无线工业及商贸联合会英文缩写),ITU(国际电联)把ARIB STD-B67纳入了BT2100标准,两个标准的公式实际是一样的只是做了换算。所谓HLG兼容SDR屏幕,不是指HDR视频能在SDR屏幕上播放,而是当屏幕兼容BT2020色域时屏幕亮度不够亮时自动根据屏幕亮度调整效果从而降低设备成本。
HLG只定义了OETF,EOTF是从OETF算出来的 O E T F = O E T F − 1 ∗ O O T F OETF =OETF^{-1}*OOTF OETF=OETF−1∗OOTF,如下图所示在拍摄时用 O E T F OETF OETF把场景光信号压缩成电信号,播放时通过 E O T F − 1 EOTF^{-1} EOTF−1逆转成场景光信号,场景光信号还要用 O O T F OOTF OOTF变成屏幕光信号。
OETF
ARIB STD-B67
BT2100HLG
注意:
-
E是显示光信号也就是线性RGB, E ′ E' E′就是电信号也就是非线性RGB
-
HLG公式分两部分,$\sqrt{E} 不就是 不就是 不就是E^{0.5} 吗,这就是为什么说 H L G 前半部分曲线是 G a m m a 函数的原因。 吗,这就是为什么说HLG前半部分曲线是Gamma函数的原因。 吗,这就是为什么说HLG前半部分曲线是Gamma函数的原因。ln(E) 不就是 不就是 不就是log_e(E)$吗,这就是为什么说HLG后半部分曲线是LOG函数的原因,其他r、a、b、c无非是调整曲线的幅度和偏移。
-
ARIB STD-B67的E范围是 [ 0 , 12 ] [0,12] [0,12],BT2100HLG的E范围是 [ 0 , 1 ] [0,1] [0,1],ARIB STD-B67的 r r r取0.5再乘上范围12就变成BT2100HLG,范围取12表示动态范围扩大了12倍。
-
r=0.5表示BT2100HLG把50%的颜色定义成了SDR,这也是BT2100也叫做50%HLG的原因,在BT2408中把75%的颜色定义成了SDR也叫做75%HLG。注意50%HLG和75%HLG的公式没变,r还是0.5,只是100%SDR对应的亮度发生了变化,50%HLG的100%SDR所对应亮度是100nit,75%HLG的100%SDR所对应亮度是203nit。100%SDR分割了SDR和HDR也叫做参考白电平,参考白电平拍摄时作为曝光基准,播放时作为白色字幕的颜色。
-
a = 0.17883277 a=0.17883277 a=0.17883277, b = 1 − 4 a = 0.28466892 b = 1 - 4a = 0.28466892 b=1−4a=0.28466892,$ c= 0.5 - a* ln(4*a)=0.55991073$,这些值都是为了平滑连接HLG的两段曲线从以下方程算出来的
{ 3 ∗ E = a ∗ l n ( 12 ∗ E − b ) + c , E = 1 12 3 ∗ E d E = a ∗ l n ( 12 ∗ E − b ) + c d E , E = 1 12 E ′ = a ∗ l n ( 12 ∗ E − b ) + c , E = 1 , E ′ = 1 \left \{ \begin{aligned} \sqrt{3*E} & = a*ln(12*E-b)+c,E=\frac{1}{12}\\ \frac{\sqrt{3*E}}{dE}&=\frac{a*ln(12*E-b)+c}{dE}, E=\frac{1}{12}\\ E' & = a*ln(12*E-b)+c,E=1, E'=1\\ \end{aligned} \right. ⎩ ⎨ ⎧3∗EdE3∗EE′=a∗ln(12∗E−b)+c,E=121=dEa∗ln(12∗E−b)+c,E=121=a∗ln(12∗E−b)+c,E=1,E′=1- 第一个等式表示两条线连接处相等
- 第二个等式表示两条线连接处的导数相等。
- 第三个等式表示曲线最右边的点
O E T F − 1 OETF^{-1} OETF−1
注意:
上述公式就是EOTF的逆过程
OOTF
F D = α Y S γ − 1 ∗ E S γ = 1.2 + 0.42 ∗ l o g 10 L W 1000 \begin{aligned} &F_D = \alpha Y_S^{\gamma-1}*E_S\\ &\gamma = 1.2+0.42*log_{10} \frac{L_W}{1000} \end{aligned} FD=αYSγ−1∗ESγ=1.2+0.42∗log101000LW
注意:
- F D F_D FD 和 E S E_S ES都是光信号,只是 F D F_D FD表示显示光, E S E_S ES表示场景光, Y S Y_{S} YS 表示场景光RGB转换出的亮度, L W L_W LW为当前屏幕的最大亮度
- HLG没有元数据能实现不同屏幕下的肤色看起来差不多就是因为上述公式中的 γ \gamma γ是可变的, γ \gamma γ随着屏幕亮度变化, Y S γ − 1 Y_S^{\gamma-1} YSγ−1又关联了视频亮度,最终HLG的相对亮度虽然没有PQ的绝对亮度那么精准但是够简单。屏幕亮度为1000时候 γ \gamma γ是1.2,这是祖祖辈辈传下来的OOTF,因为SDR时代拍摄时使用BT709的OETF γ \gamma γ近似0.5,显示时用BT1886的EOTF γ \gamma γ等于2.4,自然OOTF就是 0.5 ∗ 2.4 = 1.2 0.5*2.4 =1.2 0.5∗2.4=1.2。
- α \alpha α用于自定义调整强度。
EOTF
F D = O O T F [ O E T F − 1 [ m a x ( 0 , ( 1 − β ) ∗ E ′ + β ) ] ] β = 3 ∗ ( L B L W ) 1 γ \begin{aligned} &F_D = OOTF[OETF^{-1}[max(0,(1-\beta)*E'+\beta)]]\\ &\beta = \sqrt{3*(\frac{L_B}{L_W})^{\frac{1}{\gamma}}} \end{aligned} FD=OOTF[OETF−1[max(0,(1−β)∗E′+β)]]β=3∗(LWLB)γ1
注意:
- F D F_D FD表示显示光信号也就是线性RGB, E ′ E' E′就是电信号也就是非线性RGB
- β \beta β用来增大黑电平(定义什么颜色算是黑色), L B L_B LB表示黑电平的亮度也就是当前屏幕的最小亮度, L W L_W LW表示白电平(定义什么颜色算是白色)的亮度也就是当前屏幕的最大亮度
PQ
PQ只定义了EOTF,OETF是从EOTF算出来的 O E T F = O O T F ∗ E O T F − 1 OETF =OOTF* EOTF^{-1} OETF=OOTF∗EOTF−1,如下图所示在拍摄时先用OETF先把场景信号编码成电信号,显示时用 E O T F EOTF EOTF解码成显示光信号。注意观察PQ的OOTF在拍摄环节而HLG的OOTF在显示环节,个人感觉之所以不一样是因为PQ是绝对亮度体系对于亮度的处理当然要在拍摄时处理保证和屏幕无关、HLG是相对亮度体系对于亮度的处理要在显示时根据屏幕的亮度而变化。
EOTF
F D = 10000 ( m a x [ ( E ′ 1 m 2 − c 1 ) , 0 ] c 2 − c 3 ∗ E ′ 1 m 2 ) 1 m 1 \begin{aligned} &F_D = 10000\left(\frac{max[(E'^{\frac{1}{m_2}}-c_1), 0]}{c2-c3 * E'^{\frac{1}{m_2}} }\right) ^{\frac{1}{m_1}} \end{aligned} FD=10000(c2−c3∗E′m21max[(E′m21−c1),0])m11
注意:
- F D F_D FD表示显示光信号也就是线性RGB, E ′ E' E′就是电信号也就是非线性RGB
- PQ分割SDR和HDR的界限是58%,这也是PQ又叫做58%PQ的原因,58%PQ所对应的亮度也是203nit。
- PQ公式的参数是怎么算出来的没找到资料,只知道和Barten Ramp模型的公式有关。
m 1 = 2610 16384 = 1305 8192 = 0.1593017578125 m 2 = 128 2523 4096 = 2523 32 = 78.84375 c 1 = 3424 4096 = 107 128 = 0.8359375 = c 3 − c 2 + 1 c 2 = 32 2413 4096 = 2413 128 = 18.8515625 c 3 = 32 2392 4096 = 2392 128 = 18.6875 \begin{aligned} &m_1 = \frac{2610}{16384} = \frac{1305}{8192} = 0.1593017578125 \\ &m_2 = 128 \frac{2523}{4096} = \frac{2523}{32} = 78.84375 \\ &c_1 = \frac{3424}{4096} = \frac{107}{128} = 0.8359375 = c_3 - c_2 + 1 \\ &c_2 = 32 \frac{2413}{4096} = \frac{2413}{128} = 18.8515625 \\ &c_3 = 32 \frac{2392}{4096} = \frac{2392}{128} = 18.6875 \\ \end{aligned} m1=163842610=81921305=0.1593017578125m2=12840962523=322523=78.84375c1=40963424=128107=0.8359375=c3−c2+1c2=3240962413=1282413=18.8515625c3=3240962392=1282392=18.6875
E O T F − 1 EOTF^{-1} EOTF−1
E ′ = ( c 1 + c 2 ∗ Y m 1 1 + c 3 ∗ Y m 1 ) m 2 \begin{aligned} &E' = \left(\frac{c1+c2*Y^{m1}}{1+c3*Y^{m1} }\right)^{m2} \end{aligned} E′=(1+c3∗Ym1c1+c2∗Ym1)m2
注意:
上述公式就是EOTF的逆过程
OOTF
F D = O O T F [ E ] = G 1886 [ G 709 [ E ] ] E ′ = G 709 [ E ] = { 267.84 E , E < = 0.0003024 1.099 ( 59.5208 E ) 0.45 − 0.099 , E > 0.0003024 F D = G 1886 = 100 E ′ 2.4 \begin{aligned} &F_D = OOTF[E] = G_{1886}[G_{709}[E]]\\ &E'=G_{709}[E] =\left \{ \begin{aligned} &267.84E, E<=0.0003024\\ &1.099(59.5208E)^{0.45}-0.099, E>0.0003024\\ \end{aligned} \right. \\ &F_D =G_{1886}=100E'^{2.4}\\ \end{aligned} FD=OOTF[E]=G1886[G709[E]]E′=G709[E]={267.84E,E<=0.00030241.099(59.5208E)0.45−0.099,E>0.0003024FD=G1886=100E′2.4
注意:
-
F D F_D FD和 E E E都是光信号,只是 F D F_D FD表示场景光, E E E表示显示光
-
PQ的OOTF其实是模拟BT1886色域的屏幕显示BT709的过程,个人感觉是为了兼容以前的SDR信号。
-
G 709 G_{709} G709和BT709的OETF是一样的,只是让E乘上了59.5208( 59.5208 ∗ 4.5 = 267.84 , 0.0003024 ∗ 59.5208 = 0.018 59.5208*4.5= 267.84,0.0003024*59.5208 = 0.018 59.5208∗4.5=267.84,0.0003024∗59.5208=0.018),之所以乘这个数按BT2039的说法它代表了HDR相对于SDR的扩展比例, 如下图所示就是BT2039中的描述,59.5208是从BT709的OETF和BT1886的EOTF中算出来的
说直白点就是下方曲线中Y=100(Y=1表示100亮度,Y=100表示10000亮度)时X是59.5208
-
G 1886 G_{1886} G1886和BT1886的EOTF是一样的都是Gamma2.4,只是乘以100,之所以乘以100是因为PQ的最大亮度是10000而BT1886的最大亮度是100,10000/100=100是为了放大范围。
OETF
E ′ = O E T F [ E ] = E O T F − 1 [ O O T F [ E ] ] \begin{aligned} &E'= OETF[E] =EOTF^{-1}[OOTF[E]]\\ \end{aligned} E′=OETF[E]=EOTF−1[OOTF[E]]
注意:
E
E
E表示显示光信号也就是线性RGB,
E
′
E'
E′就是电信号也就是非线性RGB
问题思考
下面2个问题留给大家思考
- PQ公式中的值是怎么从Barten Ramp视觉模型算出来的
- BT709的Gamma函数前半部分直线斜率4.5是根据什么决定的
系列文章
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)