I want to read a YUV video with openCV. The YUV video is 1920*1080 and use the YUV422 format (I already tried to read this video with yuviewer and it worked)
I am using Python3.6.4 with an Anaconda environnement with OpenCV 3.3.1
First I tried this script https://stackoverflow.com/a/47815385/8236556 but this line
cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_Y422)
is giving me this error.
File "read-yuv-video.py", line 29, in <module>
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_UYVY)
cv2.error: C:\ci\opencv_1512688052760\work\modules\imgproc\src\color.cpp:11228: error: (-215) scn == 2 && depth == 0 in function cv::cvtColor
I also have this error when try to convert from Y444 or Y420 to RGB or RGBA or GREY. I didn't find the exact same error on google or stackoverflow. I tried to reinstall the opencv package but it didn't worked.
In my script below every cvtColor works except the last one. By working I mean it display the image but the wrong colors.
import numpy as np
import cv2
# filename = r'C:\myPath\voile.yuv'
filename = r'C:\myPath\credits.yuv'
yuv_file = open(filename, 'rb')
frame_len = 1920 * 1080 * 3/2
shape = (int(1080 * 1.5), 1920)
raw = yuv_file.read(int(frame_len))
yuv = np.frombuffer(raw, dtype=np.uint8)
yuv = yuv.reshape(shape)
yuv = cv2.resize(yuv, (0, 0), fx=0.5, fy=0.5)
cv2.imshow("raw yuv", yuv)
cv2.waitKey(0)
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV21)
cv2.imshow("YUV2BGR_NV21", bgr)
cv2.waitKey(0)
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV12)
cv2.imshow("YUV2BGR_NV12", bgr)
cv2.waitKey(0)
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_I420)
cv2.imshow("YUV2BGR_I420", bgr)
cv2.waitKey(0)
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_Y422)
cv2.imshow("YUV2BGR_Y422", bgr)
cv2.waitKey(0)
Edit
scn == 2 means the function needs a 2 channels image. I changed these lines:
frame_len = 1920 * 1080 * 2 # 4 Bytes for 2 pixels
shape = (height, width, 2) # To have a 2 channels image (not really working obviously)
and cv2.cvtColor is not throwing an error anymore but still not working properly. I assume my reshape is completely wrong.
My results:
I looked manually in the numpy.array and compared with YUView the value of pixels and the shape correspond to what I am expecting (the Y values then U then V) but that's not what opencv is displaying.
Why there is 4 images below the Y matrix in the raw frame?
More precisely, how should be the shape of the datas in input of the cv2.cvtColor function in my case?
As YUV 4:2:2 has some variants, it would be easier if you can find exactly what is your YUV format. I use Logitech Brio Webcam to shoot YUV videos with ffmpeg which gives me the YUV in (YUY2 / 0x32595559), yuyv422
. This is also the YUV 4:2:2 but has some differences in the order of bytes.
As YUV 4:2:2 compression ratio is 2/3, you were correct to use 2 bytes for 1 pixel. This worked for me.
frame_len = int(width * height * 2)
shape = (height, width, 2)
And to convert from YUV to BGR (opencv format):
bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_YUY2)