Я пытаюсь использовать OpenCV версии 4.1.0 до python для преобразования плоского изображения YUV 4: 2: 0 в RGB и пытаюсь понять, как отформатировать массив для передачи в функцию cvtColor
. У меня есть все 3 канала как отдельные массивы, и я пытаюсь объединить их для использования с cv2.cvtColor
. Я использую cv2.cvtColor(yuv_array, cv2.COLOR_YUV420p2RGB)
. Я понимаю, что yuv_array
должен быть в 1,5 раза больше исходного изображения (именно так выглядит массив yuv из cvtColor
с использованием cv2.COLOR_RGB2YUV_YV12
), и я должен поместить компоненты УФ в нижнюю половину yuv_array
и канал Y в верхнюю часть массива.
Я не могу понять, как каналы U и V должны быть отформатированы в нижней части этого массива. Я пытался чередовать их и просто помещать их обоих туда-сюда. С обоими методами я попытался поставить сначала U, потом V, а также наоборот. Все методы приводят к артефактам в результирующем изображении. Вот мой код и пример изображения:
import os
import errno
import numpy as np
import cv2
fifo_names = ["/tmp/fifos/y_fifo", "/tmp/fifos/u_fifo", "/tmp/fifos/v_fifo"]
#teardown; delete fifos
import signal, sys
def cleanup_exit(signal, frame):
print ("cleaning up!")
for fifo in fifo_names:
os.remove(fifo)
sys.exit(0)
signal.signal(signal.SIGINT, cleanup_exit)
signal.signal(signal.SIGTERM, cleanup_exit)
#make fifos
for fifo in fifo_names:
try:
os.mkfifo(fifo);
except OSError as oe:
if oe.errno == errno.EEXIST:
os.remove(fifo)
os.mkfifo(fifo)
else:
raise()
#make individual np arrays to store Y,U, and V channels
#we know the image size beforehand -- 640x360 pixels
yuv_data = []
frame_size = []
fullsize = (360, 640)
halfsize = (180, 320)
for i in range(len(fifo_names)):
if (i == 0):
size = fullsize
else:
size = halfsize
yuv_data.append(np.empty(size, dtype=np.uint8));
frame_size.append(size)
#make array that holds all yuv data for display with cv2
all_yuv_data = np.empty((fullsize[0] + halfsize[0], fullsize[1]), dtype=np.uint8)
#continuously read yuv images from fifos
print("waiting for fifo to be written to...")
while True:
for i in range(len(fifo_names)):
fifo = fifo_names[i]
with open(fifo, 'rb') as f:
print("FIFO %s opened" % (fifo))
all_data = b''
while True:
data = f.read()
print("read from %s, len: %d" % (fifo,len(data)))
if len(data) == 0: #then the fifo has been closed
break
else:
all_data += data
yuv_data[i] = np.frombuffer(all_data, dtype=np.uint8).reshape(frame_size[i])
#stick all yuv data in one buffer, interleaving columns
all_yuv_data[0:fullsize[0],0:fullsize[1]] = yuv_data[0]
all_yuv_data[fullsize[0]:,0:fullsize[1]:2] = yuv_data[1]
all_yuv_data[fullsize[0]:,1:fullsize[1]:2] = yuv_data[2]
#show each yuv channel individually
cv2.imshow('y', yuv_data[0])
cv2.imshow('u', yuv_data[1])
cv2.imshow('v', yuv_data[2])
#convert yuv to rgb and display it
rgb = cv2.cvtColor(all_yuv_data, cv2.COLOR_YUV420p2RGB);
cv2.imshow('rgb', rgb)
cv2.waitKey(1)
Приведенный выше код пытается чередовать информацию по столбцам U и V.
Я также попытался использовать следующую команду для размещения Информация о каналах U и V в массив all_yuv_data
:
#try back-to-back
all_yuv_data[0:fullsize[0],0:fullsize[1]] = yuv_data[0]
all_yuv_data[fullsize[0]:,0:halfsize[1]] = yuv_data[1]
all_yuv_data[fullsize[0]:,halfsize[1]:] = yuv_data[2]
Изображение - это кадр видео, полученный с помощью libav из другой программы. Фрейм имеет формат AV_PIX_FMT_YUV420P
, , описываемый как"планарный YUV 4: 2: 0, 12bpp, (1 образец Cr & Cb на 2x2 Y выборки)".
Вот Каналы yuv для образца изображения, отображаемого в оттенках серого:
Y Канал:
U Канал:
В Канал:
и соответствующее преобразование RGB (это было из использования выше Метод чередования, аналогичные артефакты видны при использовании метода «спина к спине»):
RGB-изображение с артефактами:
Как мне разместить информацию о каналах u и v в all_yuv_data
?
Отредактировано Марком Сетчеллом после этой точки
Я считаю, что ожидаемый результат: