简体   繁体   English

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

[英]How to convert YUV_420_888 to BGR using opencv python?

I have three ndarray which is Y.shape(307200,) U.shape(153599,) V.shape(153599,).我有三个 ndarray,即 Y.shape(307200,) U.shape(153599,) V.shape(153599,)。 what is the efficient way to convert this to BGR using opencv python?使用 opencv python 将其转换为 BGR 的有效方法是什么? Those array are in YUV_420_888 format.这些数组采用YUV_420_888格式。

my_image which is 640*640 my_image 是 640*640

My code is我的代码是

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)

Updated Answer更新答案

The information here tells me that an Android NV21 image is stored with all the Y (Luminance) values contiguously and sampled at the full resolution followed by the V and the U samples interleaved and stored at 1/4 the resolution (1/2 the height by 1/2 the width).这里的信息告诉我,Android NV21 图像与所有 Y(亮度)值连续存储并以全分辨率采样,然后 V 和 U 样本交错并以分辨率的 1/4(高度的 1/2)进行存储宽度的 1/2)。 I have created a dummy NV21 frame below and converted it into OpenCV BGR format and that confirms the layout and the way OpenCV interprets it too.我在下面创建了一个虚拟的 NV21 框架并将其转换为 OpenCV BGR 格式,这也确认了布局和 OpenCV 解释它的方式。 All the code below works in order from top to bottom, so just remove the images and squidge all the lines up together to make a Python script:下面的所有代码都是按照从上到下的顺序运行的,所以只需删除图像并将所有行挤在一起就可以创建一个 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)

That gives Y:这给了 Y:

在此处输入图片说明

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

That gives U:这给了你:

在此处输入图片说明

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

That gives 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)

Which gives this.这给出了这个。 Hopefully you can see how that is the correct RGB representation of the individual Y, U, and V components.希望您能看到单个 Y、U 和 V 分量的正确 RGB 表示如何。

在此处输入图片说明

So, in summary, I believe a 2x2 image in NV21 image is stored with interleaved VU, like this:所以,总而言之,我相信 NV21 图像中的 2x2 图像是用交错的 VU 存储的,如下所示:

Y Y Y Y V U V U

and a 2x2 NV12 image is stored with interleaved UV, like this:并且 2x2 NV12 图像与交错 UV 一起存储,如下所示:

Y Y Y Y U V U V

and a YUV420 image (Raspberry Pi) is stored fully planar:并且 YUV420 图像(Raspberry Pi)完全平面存储:

Y Y Y Y U U V V

Original Answer原答案

I don't have your data to test with and your question is missing some details, but I see no-one is answering you after 5 hours, so I'll try and get you started... no-one said answers have to be complete.我没有要测试的数据,而且你的问题缺少一些细节,但我看到 5 小时后没有人回答你,所以我会试着让你开始......没有人说答案必须完整。

Firstly, I guess from your Y.shape(307200) that your image is 640x480 pixels, correct?首先,我从你的Y.shape(307200)猜测你的图像是 640x480 像素,对吗?

Secondly, your U.shape(153599) and V.shape(153599) look incorrect - they should be exactly half the Y.shape since they are sampled down at a rate of 2:1.其次,您的U.shape(153599)V.shape(153599)看起来不正确 - 它们应该正好是Y.shape一半,因为它们以 2:1 的速率采样。

Once you have got that sorted out, I think you need to take your Y array and append the U array, then the V array so you have one single contiguous array.一旦你解决了这个问题,我认为你需要拿你的Y数组并附加U数组,然后是V数组,这样你就有了一个连续的数组。 You then need to pass that to cvtColor() with the code cv2.CV_YUV2BGR_NV21 .然后,您需要使用代码cv2.CV_YUV2BGR_NV21将其传递给cvtColor()

You may need to reshape your array before appending, something like im = Y.reshape(480,640) .您可能需要在追加之前重塑您的数组,例如im = Y.reshape(480,640)

I know when you use the C++ interface to OpenCV, you must set the height of the image to 1.5x the actual height (whilst leaving the width unchanged) - so you may need to try that too.我知道当你使用 OpenCV 的 C++ 接口时,你必须将图像的高度设置为实际高度的 1.5 倍(同时保持宽度不变) - 所以你可能也需要尝试一下。

I can never remember all the constants OpenCV provides for image opening modes (like IMREAD_ANYDEPTH , IMREAD_GRAYSCALE ) and for cvtColor() , so here's a handy way of finding them.我永远不会记得 OpenCV 为图像打开模式(如IMREAD_ANYDEPTHIMREAD_GRAYSCALE )和cvtColor()提供的所有常量,所以这里有一个方便的方法来找到它们。 I start ipython and if am looking for the Android NV21 constants, I do:我启动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']

So the constant you need is probably COLOR_YUV2BGR_NV21所以你需要的常量可能是COLOR_YUV2BGR_NV21

The same technique works for parameters to imread() :同样的技术适用于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']

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM