簡體   English   中英

如何使用opencv python將YUV_420_888轉換為BGR?

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

我有三個 ndarray,即 Y.shape(307200,) U.shape(153599,) V.shape(153599,)。 使用 opencv python 將其轉換為 BGR 的有效方法是什么? 這些數組采用YUV_420_888格式。

my_image 是 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)

更新答案

這里的信息告訴我,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:

在此處輸入圖片說明

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

這給了你:

在此處輸入圖片說明

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

這給出了這個。 希望您能看到單個 Y、U 和 V 分量的正確 RGB 表示如何。

在此處輸入圖片說明

所以,總而言之,我相信 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一半,因為它們以 2:1 的速率采樣。

一旦你解決了這個問題,我認為你需要拿你的Y數組並附加U數組,然后是V數組,這樣你就有了一個連續的數組。 然后,您需要使用代碼cv2.CV_YUV2BGR_NV21將其傳遞給cvtColor()

您可能需要在追加之前重塑您的數組,例如im = Y.reshape(480,640)

我知道當你使用 OpenCV 的 C++ 接口時,你必須將圖像的高度設置為實際高度的 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']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM