Error trying to use cvtColor with cv2.COLOR_YUV2BGR_Y422 - error: (-215) scn == 2 && depth == 0 in function cv::cvtColor

amarion picture amarion · Mar 19, 2018 · Viewed 7.9k times · Source

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?

Answer

biendltb picture biendltb · Apr 3, 2019

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)