视频ToneMapping(HDR转SDR)中的颜色空间转换问题(BT2020转BT709,YCbCr、YUV和RGB)

笔者按,最近在做视频TM的相关工作,具体是给定一个HDR视频(10bit的YUV420格式),要对其进行TM,写了一个算法但总是有非常离谱的色差,尤其是红色和蓝色通道。仔细检查之后发现是拿到的HDR视频的颜色空间是BT2020的,但转换后的SDR视频是BT709的,需要先对颜色空间进行降级才可以进行处理。这里记录一下处理过程。

首先贴两个地址

[1] ​​​​​​RECOMMENDATION ITU-R BT.2087-0 - Colour conversion from Recommendation ITU-R BT.709 to Recommendation ITU-R BT.2020

[2] REPORT ITU-R BT.2407-0 - Colour gamut conversion from Recommendation ITU-R BT.2020 to Recommendation ITU-R BT.709

这两个都是ITU搞出来的标准纲领性文件。第一个文件讲了怎么把BT709转到2020(包括YUV、RGB的处理办法),第二个讲了怎么把BT2020转换到BT709(但只有RGB信号)。

在文献[2]中,简单粗暴地给出了一个示意图

E'RGB指的是“归一化的非线性RGB值”,而E_RGB指的是“归一化的线性RGB值”。

但在算法中,我拿到的数据是10bit的YUV420数据,所以需要先把10bitYUV420数据转换到E'RGB。怎么转?文献没提。但文献[1]中将如何将709转换到2020时,给了一个图

这里除了 E'RGB和E_RGB之外,还出现了E'YCBCR和D'YCBCR。其中E'YCBCR指的是“归一化的YCBCR值”,而D'YCBCR指的是“量化的YCBCR值”

所以我这里明白了,我在算法输入端所拿到的所谓10bitYUV420数据,实际上就是这个D'YCBCR值。那么接下来,我们结合两篇文献,就可以推导出相应过程了。

Step 1. 将D’YCbCr(2020)转为E’YCbCr(2020)

其实就是如下过程的反过程

 简单推导,得

        E_Y = ((D_Y / 4) - 16) / 219
        E_Cb = ((D_Cb / 4) - 128) / 224
        E_Cr = ((D_Cr / 4) - 128) / 224

Step 2. 将E’YCbCr(2020)转为E’RGB(2020)

文献[1]中给出了反过程

所以这里只要做一个简单的矩阵求逆(这里直接给出了逆)

需要注意的是,下面给出的代码中的E_YCbCr和E_RGB这样的变量,其形状都是height x width x 3的,所以这里讨巧做了一个线性代数的转换,将左乘变成了右乘。下面很多地方都利用了这个方法,后续就不再做解释说明了。

        m_YCbCr2020_to_RGB2020 = np.array([[1.00000000e+00, -7.82308321e-18, 1.47460000e+00],
                                           [1.00000000e+00, -1.64553127e-01, -5.71353127e-01],
                                           [1.00000000e+00, 1.88140000e+00, 2.38961873e-17]])
        E_RGB = np.matmul(E_YCbCr, m_YCbCr2020_to_RGB2020.T)

Step 3. 将E’RGB(2020)转为E RGB(2020)

        E_RGB = np.power(E_RGB, 2)
        # 另一个版本是
        # E_RGB = np.power(E_RGB, 2.4)

Step 4. 将E RGB(2020)转为E RGB(709)

        m_RGB2020_to_RGB709 = np.array([[1.66051121, -0.58771059, -0.07280062],
                                        [-0.12456141,  1.13296051, -0.00839911],
                                        [-0.01816769, -0.1005606,  1.11872828]])
        E_RGB = np.matmul(E_RGB, m_RGB2020_to_RGB709.T)

Step 5. 将E RGB(709)转为E’RGB(709)

        E_RGB = np.power(E_RGB, 1/2)
        # 另一个版本是
        # E_RGB = np.power(E_RGB, 1/2.4)

Step 6.  E’RGB(709)转为D’RGB(709)

【这里是以10bit为例的,如果是8bit,去掉后面的*4即可】

D_RGB = ((E_RGB * 219 + 16) * 4).astype("uint16")

这样转换过后,就没有了色偏问题。

猜你喜欢

转载自blog.csdn.net/q274488181/article/details/125449511
今日推荐