python - 如何使用opencv python将YUV_420_888转换为BGR?

标签 python python-3.x numpy opencv

我有三个ndarray,分别是Y.shape(307200,) U.shape(153599,) V.shape(153599,)。使用 opencv python 将其转换为 BGR 的有效方法是什么?这些数组位于 YUV_420_888 中 格式。

my_image which is 640*640

我的代码是

Y= np.fromstring(Y, dtype=np.uint8)
U= np.fromstring(U, dtype=np.uint8)
V= np.fromstring(V, dtype=np.uint8)
Y= np.reshape(Y, (480,640))
U= np.reshape(U, (480,320))
V= np.reshape(V, (480,320))
YUV = np.append(Y,U)
YUV = np.append(YUV,V)
img = np.reshape(YUV,(960,640))
img = np.asarray(img, dtype = np.uint8)
img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV21)

最佳答案

更新答案

信息here告诉我,Android NV21 图像连续存储所有 Y(亮度)值,并以全分辨率采样,然后 V 和 U 采样交错并以 1/4 分辨率存储(1/2 高度乘以 1/2 宽度)。我在下面创建了一个虚拟 NV21 框架,并将其转换为 OpenCV BGR 格式,这也确认了布局和 OpenCV 解释它的方式。下面的所有代码都按从上到下的顺序运行,因此只需删除图像并将所有行组合在一起即可生成 Python 脚本:

#!/usr/bin/env python3

import cv2
import numpy as np

# Define width and height of image
w,h = 640,480

# Create black-white gradient from top to bottom in Y channel
f = lambda i, j: int((i*256)/h)
Y = np.fromfunction(np.vectorize(f), (h,w)).astype(np.uint8) 
# DEBUG
cv2.imwrite('Y.jpg',Y)

这给出了 Y:

enter image description here

# Dimensions of subsampled U and V
UVwidth, UVheight = w//2, h//2

# U is a black-white gradient from left to right
f = lambda i, j: int((j*256)/UVwidth)
U = np.fromfunction(np.vectorize(f), (UVheight,UVwidth)).astype(np.uint8)  
# DEBUG 
cv2.imwrite('U.jpg',U)

这给了你:

enter image description here

# V is a white-black gradient from left to right
V = U[:,::-1] 
# DEBUG 
cv2.imwrite('V.jpg',V)

这给出了 V:

enter image description here

# Interleave U and V, V first NV21, U first for NV12
U = np.ravel(U)
V = np.ravel(V)
UV = np.empty((U.size+V.size), dtype=np.uint8)
UV[0::2] = V
UV[1::2] = U

# Lay out Y plane, followed by UV
YUV = np.append(Y,UV).reshape((3*h)//2,w)

BGR = cv2.cvtColor(YUV.astype(np.uint8), cv2.COLOR_YUV2BGR_NV21)
cv2.imwrite('result.jpg',BGR)

这给出了这个。希望您能明白这如何是各个 Y、U 和 V 分量的正确 RGB 表示。

enter image description here

所以,总而言之,我相信 NV21 图像中的 2x2 图像是用交错 VU 存储的,如下所示:

Y Y Y Y V U V U

2x2 NV12 图像使用交错 UV 存储,如下所示:

Y Y Y Y U V U V

YUV420 图像(Raspberry Pi)完全平面存储:

Y Y Y Y U U V V

原始答案

我没有您的数据可供测试,并且您的问题缺少一些细节,但我发现 5 小时后没有人回答您,所以我会尝试让您开始...没有人说答案必须完整。

首先,我从您的 Y.shape(307200) 猜想您的图像是 640x480 像素,对吗?

其次,您的 U.shape(153599)V.shape(153599) 看起来不正确 - 它们应该恰好是 Y.shape 的一半code> 因为它们以 2:1 的比率进行采样。

一旦你解决了这个问题,我认为你需要获取 Y 数组并附加 U 数组,然后附加 V数组,这样你就有一个连续的数组。然后,您需要使用代码 cv2.CV_YUV2BGR_NV21 将其传递给 cvtColor()

您可能需要在附加之前 reshape 数组,例如 im = Y.reshape(480,640)

我知道当您使用 OpenCV 的 C++ 接口(interface)时,您必须将图像的高度设置为实际高度的 1.5 倍(同时保持宽度不变) - 所以您可能也需要尝试一下。

我永远记不起 OpenCV 为图像打开模式(例如 IMREAD_ANYDEPTHIMREAD_GRAYSCALE)和 cvtColor() 提供的所有常量,所以这是找到它们的便捷方法。我启动 ipython,如果要查找 Android NV21 常量,我会这样做:

import cv2

[i for i in dir(cv2) if 'NV21' in i]                                                                                                                       
Out[29]: 
['COLOR_YUV2BGRA_NV21',
 'COLOR_YUV2BGR_NV21',
 'COLOR_YUV2GRAY_NV21',
 'COLOR_YUV2RGBA_NV21',
 'COLOR_YUV2RGB_NV21']

所以你需要的常量可能是COLOR_YUV2BGR_NV21

相同的技术适用于 imread() 的参数:

items=[i for i in dir(cv2) if i.startswith('IMREAD')]                                                                                                                                                          

In [22]: items                                                                                                                                                      

['IMREAD_ANYCOLOR',
 'IMREAD_ANYDEPTH',
 'IMREAD_COLOR',
 'IMREAD_GRAYSCALE',
 'IMREAD_IGNORE_ORIENTATION',
 'IMREAD_LOAD_GDAL',
 'IMREAD_REDUCED_COLOR_2',
 'IMREAD_REDUCED_COLOR_4',
 'IMREAD_REDUCED_COLOR_8',
 'IMREAD_REDUCED_GRAYSCALE_2',
 'IMREAD_REDUCED_GRAYSCALE_4',
 'IMREAD_REDUCED_GRAYSCALE_8',
 'IMREAD_UNCHANGED']

关于python - 如何使用opencv python将YUV_420_888转换为BGR?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54566713/

相关文章:

python - min() arg 是一个带有错误索引的空序列

Python/Pygame : 2d angular momentum/inertia

python - 如何在Mac上通过anaconda安装openCV?

python - 当结果不匹配时,pandas 合并如何将默认 Nan 设置为 0

Python读取Excel单元格数据验证

python - python 中 <= 的输出很奇怪

python - 访问文件中的第 n 个 pickle

python - 这个语法在Python中是什么意思? def json_file_to_dict(_file : str) -> dict:?

python - 为不同大小的数组自动填充 np.nan

python - 让 pandas Wide_to_long() 函数考虑 stub 在列名的末尾而不是开头