更新答案

信息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:

^{pr2}$
这让你:
# V is a white-black gradient from left to right
V = U[:,::-1]
# DEBUG
cv2.imwrite('V.jpg',V)

这给了V:

# 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)

这就是原因。希望您能看到这是如何正确的RGB表示个别的Y,U,V组件。在


综上所述,我认为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)和{}看起来不正确-它们应该正好是{}的一半,因为它们是以2:1的比率取样的。在

一旦你整理好了,我想你需要使用你的Y数组并附加U数组,然后是{}数组,这样你就有了一个连续的数组。然后需要将其传递给cvtColor(),代码为cv2.CV_YUV2BGR_NV21。在

在追加之前,您可能需要重塑数组的形状,例如im = Y.reshape(480,640)。在

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

我永远记不清OpenCV为图像打开模式(比如IMREAD_ANYDEPTH,IMREAD_GRAYSCALE)和{}提供的所有常量,所以这里有一个方便的方法来找到它们。我启动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

{to>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']