HDR视频中由于电光转换曲线的不同,技术标准也大致分为了杜比视界、HDR10+、HDR10、HLG等,目前常用的主要是以PQ曲线的HDR10和HLG。这两者之间的区别在HDR视频编码参数中进行过详细的说明。一般的HLG适用于广电(根据用户设备的峰值亮度动态的调整最高显示亮度),PQ适用于数码电脑等(绝对的亮度,如果设备达不到,则进行削峰)。他们之间根据不同的用户选择不同的技术标准。如果知道其中一个技术标准的HDR视频,其实是可以转换为另外一个的。
基本概念
色彩值(color value)
色彩值是用于描述一张图像中特定颜色分量(如R、G、B或Y)的数值。
数字编码值(digital code value)
一张图像信号值的数字表示,通常是非线性的颜色值。
电光转换函数(EOTF)
用于描述输入显示器的非线性颜色值(数字编码像素值)和显示器所显示的线性颜色值()之间的关系。
光电转换函数(OETF)
用于描述线性颜色值E与非线性颜色值(数字编码像素值,)之间的关系。注意这里的线性颜色值是自然场景中的颜色值。而EOTF中的光是显示器的线性颜色值。
之前也提到过,之所以有所谓的光电、电光转换函数,主要还是为了节省视频码率,在人眼对光线亮度的敏感区域分配更多的数值来表达光线的程度。
光光转换函数(OOTF)
用于描述相机捕获光线值()与显示器所显示光线强度之间的关系。OOTF一方面可以通过后期进行所谓的艺术渲染对色彩进行调整,可以看成是OETF、艺术调整和EOTF的连结,另一方面也是对HLG技术的关键,因为根据不同显示亮度峰值的设备,通过该函数进行光程度的重新映射。
EOTF、OETF、OOTF三者是相互关联的,所以三者中只有两个是独立的。给定任何两个可以计算第三个。
高动态范围(HDR)
图像或显示设备可以存储或显示的亮度等级范围要远大于传统成像系统。在SMPTE 2084标准中设定峰值亮度为10000 nits。
线性颜色值(Linear Color Value)
缩写记为L,归一化到[0, 1],与显示设备的输出光线强度成正比,但不与图像信号的编码值成正比,如场景线性光,显示线性光。
非线性值(Nonlinear Color Value)
缩写记为N,归一化到[0, 1],与图像信号的编码值成正比,但不予显示设备的输出光强度成正比。
电视信号链(Television signal chain)
描述从相机的信号采集到显示器显示的整个过程,包括相机和显示器两部分的非线性变化。相机采集部分的非线性化由OETF描述,显示器显示部分非线性化由EOTF描述,整个流程如下:
不同技术标准之间的光电、电光转换公式是不一样的。可从这里下载BT.2100技术标准文档,以及其他的参考标准,下面分别进行介绍
SDR
这个通常比较熟悉,就是平常常用的gamma校正。针对SDR的亮度范围100nits,通过经验以及实验,发现可以使用幂函数来拟合亮度和人眼感知这种非线性的映射,公式表示:
- X 是使用 0-1 之间的实数表示的输入亮度;
- Y 是使用 0-1 之间实数表示的输出亮度;
- 为设定的参数,通过调整的取值来调整输入输出亮度之间映射关系的方式,称之为 gamma 校正
encoding gamma 函数和display gamma 函数,对应OETF和EOTF
- 摄像机中会使用一种 encoding gamma 函数进行 gamma 校正,这里的 gamma 值小于 1。
- 显示阶段的使用一种 display gamma 函数来完成,这里的 gamma 值大于 1。
- 大部分计算机显示系统 encoding gamma 大约是 0.45(也就是 1/2.2),display gamma是2.2。
PQ
基于PQ的HDR系统是一个绝对系统,对于输入的线性场景光,根据创作者的意图,选择合适的OOTF将场景光转换为最终用于显示的显示光,利用PQ逆EOTF将显示光转换为非线性的电信号,到了显示终端再采用PQ的EOTF 将电信号还原为显示光显示,PQ规的是EOTF曲线,描述了显示亮度的绝对亮度,最高亮度是10000cd/m2,如果前端制作的是显示峰值亮度为10000cd/m的PQ节目,最终得到的显示光亮度也为1000cd/m.如果显示设备显示能力不匹配时,例如:显示设备的色域小于母带的色域或者显示设备的亮度范围要小于母带的亮度范围,那么,设备就会根据这些静态元数据将色域和亮度范围相对地缩小到显示设备的范围内.
电光转换方程EOTF:
电光转换的逆运算:Inverse EOTF
电光转换的逆运算并不是OETF,光电转换曲线是光线采集端(相机等)将光线信号转换成电信号(编码值)
表示非线性的像素编码值;
Y 表示对应的线性色彩值;
和Y成线性关系,表示对应的显示器光线输出值单位为nit。
m1= 2610/4096 ×1/4 = 0.1593017578125;
m2=2523/4096 ×128 = 78.84375;
c1= 3424/4096 = 0.8359375 =C3 - C2 + 1;
c2= 2413/4096×32 = 18.8515625;
c3= 2392/4096 × 32 = 18.6875;
因为PQ曲线表现光亮度的绝对性,从Inverse EOTF中的公式中可以提取到FD = OOTF[E]的信息。而FD最高亮度是表示的是10000nit。E在这里应当是表示的大自然场景(或者理解为摄影场景)的亮度(或者色彩度)。这里做了一个光光之间的转换。而经过了光光转换函数以后,Inverse EOTF就可以当成OETF的转换函数。
光光转换函数OOTF
在次提一句,由于PQ曲线显示亮度的绝对性,这些流程的参数一经制作就不再改变。比如说,拿到一个基于PQ转换曲线的MP4视频文件。其显示流程可表示成:
而在制作HDR视频文件时。,根据母带信息一经做了相关的光光转换。
HLG
HLG逆EOTF将电信号还原为场景光,再利用OOTF将场景光转换为显示光显示.HLG规定的是OETF曲线,描述了场景光的亮度当显示设备的亮度与原始场景光亮度不一致时,可以利用OOTF进行适配,而不需要额外的元数据.
不同于PQ转换曲线视频的播放设备必须和录制设备保持一致(或者向下兼容)才能正常显示画面,HLG对播放设备要求不是那么严格,是因为在播放前经过了scene luminance到display luminance的转换。
光电转换方程OETF
a = 0.17883277, b =1− 4a= 0.28466892, c = 0.5 − a ln(4a)== 0.55991073.
光光转换方程OOTF
之前已经介绍了,光光转换方程是自然光到显示器显示的光强度的映射方程。自然光亮度可以称为scene luminance(上面提到的场景光信号,线性光信号),显示器亮度可以成为display luminance。因此,带有S下标的一般都表示在自然光下的相关参数,带有D下标的是和显示器亮度有关的参数。HLG的光光转换方程为:
其中部分参数意义在PQ曲线中已经介绍。
与R,G,B的关系其实就是yuv和rgb格式转换的公式,这里就是表示scene luminance,当然他是在BT.2020标准下的。这个在之前介绍过。
是系统伽马射线 。显示器的标称峰值亮度为 1000cd/m2 时 ,其值为1.2
如果显示器的峰值亮度不是 1000cd/m2,那么可以通过下面的公式对伽马值进行调整
是以cd/m 2 为单位的用户增益变量。它代表 ,是显示器消色差像元的标称峰值亮度。
有光光转换也可以推出逆光光转换方程:
并且当不知道目标显示器的峰值亮度是,一般设为1.0。
电光转换方程EOTF
电光转换曲线是硬盘内的电信号转换成显示屏的光信号,在整个流程中有如下等价关系:
其中EOTF和OOTF就是上面所介绍的光电和光光转换方程。
逆光电转换方程:
a、b、c和光电转换方程中的参数一样,即a = 0.17883277, b =1− 4a= 0.28466892, c = 0.5 − a ln(4a)== 0.55991073.
β是用于提升用户黑色水平的变量
是以cd/m 2 为单位时消色差像素屏幕显示的额定峰值亮度
是以cd/m 2 为单位时黑色的屏幕显示亮度。
其中的即是
小节
通过以上分析可以看出PQ和HLG两者之间不仅仅是一个量化曲线的改变,而是整个系统的标示。三个关键术语OETF、OOTF、EOTF在不同的系统中,除了所用公式有所不同,在制作和使用过程中的顺序也有所不同。
PQ系统采用如下所示的模型设计,其中OOTF在摄像机中(或施加于制作过程中)
HLG系统采用如下所示的模型设计,其中OOTF在显示器中
OETF、EOTF和OOTF两两独立,之间的转换关系可以表示如下:
PQ方法由其EOTF定义。对于PQ,OETF可以使用上述等式的第三行从OOTD得出。用一种互补的方式,HLG方法由其OETF定义。对于HLG, EOTF可以使用上述等式的第二行从OOTF得出。
HLG与PQ曲线的互转
两个系统的转换是参考的BBC的流程,该流程里面提到了一个非常有用的HDR工具。
PQ->HLG:
整个流程可以如下图表示:
从目标结果上看是PQ Signal -> HLG Signal的过程。其余的均为显示过程。但是显示目标是Display light要保持一致。所以基于PQ曲线的最终显示要和HLG的一样。通过前面介绍的,HDR视频的制作以及显示流程。我们要通过HLG的(逆电光转换)。
并通过小节中的图二可知,HLG的EOTF过程包括inverse OETF + OOTF。那么
在上面的小节中我们已经知道,PQ方法由其EOTF定义,HLG方法由其OETF定义。现在整个流程就只剩inverse OOTF,通过下图求解
1)通过Figure可知需要知道输入Display Light = PQ(EOTF).即通过PQ曲线的电光曲线求得。
2)对第一步求得的亮度进行规范化,这一步主要是因为,PQ曲线表示亮度的绝对性,需要使用主监视器最高亮度把归一化线性光转换为显示线性光。主监视器最高亮度表示终端显示该信号所能达到的最高亮度,该亮度值可通过对信号内容进行分析得到,也可以通过元数据得到比如说在最高亮度为1000nit的显示屏上,经过相应元数据信息的处理后,大于1000bit亮度在该标准的显示器上是无法正常显示的,即,大于1000nit的都以1000nit进行显示,被clip。通过公式可以表示成:
Y即是PQ的EOTF公式的输出值,可在上面查找到。这里是想当重要的一个转换,因为,假如在PQ的EOTF后,得到的结果是RD,GD,BD。如果标准显示器为1000nit,那么下面通过中的 = 10*RD,=10*GD,=10*BD. 总之,这里是显示的nit值并进行了归一化,也可以想成将超过1000nit的值置为1000,并对0-1000规范化到0-1,(成为nit可能不太标准,因为nit是亮度,而我们这里都是RGB的颜色值)
3)通过,逆OOTF需要先求得Y,因此需要根据YUV-RGB在bt2020颜色空间下的转换公式进行求出:
下标是d标示,标示是display显示器上的值。
4)通过逆的伽马曲线得出场景亮度:,在HLG的OOTF介绍中说过,如果显示器和母带信息亮度峰值不同时,可以通过进行改变。并通过HLG的逆光光转换曲线:
得出场景颜色数值。
5)通过HLG的OETF的公式即可求得。这里应当注意的是,完全按照BT.2100-0标准定义的公式中的注意事项5a,在执行OETF公式时需要先乘以12.如果是注意事项5b则不需要。
HLG->PQ
首先看一下整体的流程:
和PQ->HLG一样,我们要达到的目的就是保持在同一显示器下转换前后两个格式观看的效果是一样的。也就是Display Light保持一致,目标是从Display Light-PQ Signal:
由于PQ方法由EOTF定义,那么inverse EOTF公式也能直接求出,这个在PQ曲线介绍中公式已经给出。所以重点还是在于HLG的EOTF。根据小节图二的信息,HLG的EOTF过程包括inverse OETF + OOTF。
其中,HLG的inverse OETF在HLG曲线中就已经介绍过,那么就只剩OOTF。
1)在HLG的inverse OETF中,我们还是按照已经归一化的公式(非归一化有其他公式),即
2)OOTF的计算过程也已经提到过,即:
这里的是目标PQ曲线的显示屏的亮度。
3)然后进行规范化:
其中代表着
4)通过PQ曲线的inverse EOTF即可得出结果:
c和m系列的值已经提到过。
其他
另一方面也可以通过使用3D look up table(LUT)的方式来进行两者的互转,但是前提条件是,在使用LUT时,一般都是R、G、B格式进行输入的。因此在使用是,如果是YUV格式,需要进行格式的转换。
PQ-HLG code
a_2020 = 0.2627
b_2020 = 0.6780
c_2020 = 0.0593
d_2020 = 1.8814
e_2020 = 1.4747
m1 = (2610.0) / (4096.0 * 4.0)
m2 = (2523.0 * 128.0) / 4096.0
c1 = (3424.0) / 4096.0
c2 = (2413.0 * 32.0) / 4096.0
c3 = (2392.0 * 32.0) / 4096.0
m2_inverse = 1.0/m2
m1_inverse = 1.0/m1
a = 0.17883277
b = 0.28466892
c = 0.55991073
hlg_tsd = 0.083333333
gamma = 1.2
def RGB2YUV_bt2020(R,G,B,w=960,h=540):
Y = a_2020 * R + b_2020 * G + c_2020 * B
Cb = (B - Y) / d_2020
Cr = (R - Y) / e_2020
Y = (219*Y + 16) * 4
Cb = (224*Cb + 128) * 4
Cr = (224*Cr + 128) * 4
Y = np.around(Y).astype(np.uint16)
Cb = np.around(Cb).astype(np.uint16)
Cr = np.around(Cr).astype(np.uint16)
Cb = cv.resize(Cb, (w, h), interpolation=cv.INTER_LINEAR)
Cr = cv.resize(Cr, (w, h), interpolation=cv.INTER_LINEAR)
return Y,Cb,Cr
def HLG_OETF(E):
E_p = np.where(E < hlg_tsd, np.power(3*E,0.5), a*np.log(12*E-b)+c)
return E_p
def pq_EOTF(E_p):
E_i = np.power(E_p,m2_inverse)
e_i = E_i - c1
E_0 = np.maximum(e_i, 0)
deno = c2 - c3*E_i
Y_i = E_0/deno
return np.power(Y_i, m1_inverse)
def YUV2RGB_bt2020(Y,U,V):
Cb = U
Cr = V
Y = (Y/4 - 16)/219
Cb = (Cb/4 - 128)/224
Cr = (Cr/4 - 128)/224
R = Y + e_2020 * Cr
G = Y - (a_2020 * e_2020 / b_2020) * Cr - (c_2020 * d_2020 / b_2020) * Cb
B = Y + d_2020 * Cb
R = R.clip(0.0, 1.0)
G = G.clip(0.0, 1.0)
B = B.clip(0.0, 1.0)
return R,G,B
def PQ2HLG_trans(Y,U,V,height, width):
R, G, B = YUV2RGB_bt2020(yuv[:, :, 0], yuv[:, :, 1], yuv[:, :, 2])
Rd = pq_EOTF(R)
Gd = pq_EOTF(G)
Bd = pq_EOTF(B)
Rd = np.minimum(Rd*10,1.0)
Gd = np.minimum(Gd*10,1.0)
Bd = np.minimum(Bd*10,1.0)
YD = 0.2627*Rd + 0.6780*Gd + 0.0593*Bd
YD_gamma = np.power(YD,(1-gamma)/gamma)
Rs = Rd * YD_gamma
Gs = Gd * YD_gamma
Bs = Bd * YD_gamma
hlg_R = HLG_OETF(Rs)
hlg_G = HLG_OETF(Gs)
hlg_B = HLG_OETF(Bs)
Y,Cb,Cr = RGB2YUV_bt2020(hlg_R,hlg_G,hlg_B,width//2,height//2)
return Y,Cb,Cr