如何使用NumPy将sRGB转换为NV12格式?

2024-06-26 02:41:40 发布

您现在位置:Python中文网/ 问答频道 /正文

NV12格式定义了YUV颜色空间的特定颜色通道顺序,共有420个子采样。
NV12格式主要用于视频编解码流水线。在

libyuv description of NV12

NV12 is a biplanar format with a full sized Y plane followed by a single chroma plane with weaved U and V values. NV21 is the same but with weaved V and U values. The 12 in NV12 refers to 12 bits per pixel. NV12 has a half width and half height chroma channel, and therefore is a 420 subsampling.

在NV12环境中,YUV格式主要指YCbCr颜色空间。
NV12元素为每个元素8位(uint8类型)。
在帖子的上下文中,YUV元素是在“有限范围”的标准:Y范围是[16235],U,V范围是[16240]。在

sRGB是PC系统使用的标准颜色空间。
在post上下文中,sRGB颜色分量的范围是[0255](uint8类型)。
RGB元素排序与post无关(假设3个颜色平面)。在

目前至少有2种可能的YCbCr格式适用于NV12:

NV12元素排序示例:
YYYYYY
YYYYYY
UVUVUV

NV12

RGB到NV12的转换可以通过以下阶段来描述:

  • 颜色空间转换-从sRGB转换为YUV颜色空间。在
  • 色度下采样-在每个轴上以x2的因子缩小U,V通道(从YUV444转换为YUV420)。在
  • 色度元素交错-排列U,V元素为U,V,U,V。。。在

下图说明了应用6x6像素的图像大小的转换阶段:

RGBtoNV12

如何使用NumPy将sRGB转换为NV12?

注意:
这个问题涉及到演示转换过程的Python实现(post不适用于OpenCV实现等现有函数)。在


Tags: and元素is颜色格式with空间post
1条回答
网友
1楼 · 发布于 2024-06-26 02:41:40

使用NumPy将sRGB转换为NV12格式

帖子的目的是演示转换过程。
下面的Python实现使用NumPy,并故意避免使用OpenCV。在

RGB到NV12转换级:

  • 颜色空间转换-从sRGB转换为YUV颜色空间:
    使用sRGB到YCbCr的转换公式。
    将每个RGB三倍乘以3x3转换矩阵,并添加一个3个偏移量的向量。
    帖子显示了BT.709和BT.601的转换(唯一的区别是系数矩阵)。在
  • 色度下采样-在每个轴上将U、V通道缩小x2倍(从YUV444转换为YUV420)。
    该实现使用双线性插值将U、V的大小调整为每个轴的0.5倍。
    注:双线性插值不是最佳的下采样方法,但通常足够好。
    代码不使用cv2.resize,而是使用每2x2像素的平均值(结果相当于双线性插值)。
    注意:如果输入解析在两个维度上都不均匀,则实现失败。在
  • 色度元素交错-将U、V元素排列为U、V、U、V…
    通过数组索引操作实现。在

以下是将RGB转换为NV12标准的Python代码示例:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

do_use_bt709 = True; # True for BT.709, False for BT.601

RGB = mpimg.imread('rgb_input.png')*255.0     # Read RGB input image, multiply by 255 (set RGB range to [0, 255]).
R, G, B = RGB[:, :, 0], RGB[:, :, 1], RGB[:, :, 2]  # Split RGB to R, G and B numpy arrays.
rows, cols = R.shape

# I. Convert RGB to YUV (convert sRGB to YUV444)
#################################################
if do_use_bt709:
    # Convert sRGB to YUV, BT.709 standard
    # Conversion formula used: 8 bit sRGB to "limited range" 8 bit YUV (BT.709).
    Y =  0.18258588*R + 0.61423059*G + 0.06200706*B + 16.0
    U = -0.10064373*R - 0.33857195*G + 0.43921569*B + 128.0
    V =  0.43921569*R - 0.39894216*G - 0.04027352*B + 128.0
else:
    # Convert sRGB to YUV, BT.601 standard.
    # Conversion formula used: 8 bit sRGB to "limited range" 8 bit YUV (BT.601).
    Y =  0.25678824*R + 0.50412941*G + 0.09790588*B + 16.0
    U = -0.14822290*R - 0.29099279*G + 0.43921569*B + 128.0
    V =  0.43921569*R - 0.36778831*G - 0.07142737*B + 128.0


# II. U,V Downsampling (convert YUV444 to YUV420)
##################################################
# Shrink U and V channels by a factor of x2 in each axis (use bi-linear interpolation).
#shrunkU = cv2.resize(U, dsize=(cols//2, rows//2), interpolation=cv2.INTER_LINEAR)
#shrunkV = cv2.resize(V, dsize=(cols//2, rows//2), interpolation=cv2.INTER_LINEAR)

# Each element of shrunkU is the mean of 2x2 elements of U
# Result is equvalent to resize by a factor of 0.5 with bi-linear interpolation.
shrunkU = (U[0: :2, 0::2] + U[1: :2, 0: :2] + U[0: :2, 1: :2] + U[1: :2, 1: :2]) * 0.25
shrunkV = (V[0: :2, 0::2] + V[1: :2, 0: :2] + V[0: :2, 1: :2] + V[1: :2, 1: :2]) * 0.25


# III. U,V Interleaving
########################
# Size of UV plane is half the number of rows, and same number of columns as Y plane.
UV = np.zeros((rows//2, cols))  # Use // for integer division.

# Interleave shrunkU and shrunkV and build UV palne (each row of UV plane is u,v,u,u,v...)
UV[:, 0 : :2] = shrunkU
UV[:, 1 : :2] = shrunkV

# Place Y plane at the top, and UV plane at the bottom (number of rows NV12 matrix is rows*1.5)
NV12 = np.vstack((Y, UV))

# Round NV12, and cast to uint8 (use floor(x+0.5) instead of round to avoid "bankers rounding").
NV12 = np.floor(NV12 + 0.5).astype('uint8')


# Write NV12 array to binary file
NV12.tofile('nv12_output.raw')

# Display NV12 result (display as Grayscale image).
plt.figure()
plt.axis('off')
plt.imshow(NV12, cmap='gray', interpolation='nearest')
plt.show()

示例RGB输入图像:
RGB input

NV12结果(显示为灰度图像):
NV12 output as Grayscale

相关问题 更多 >