使用cv2.COLOR_YUV2BGR_Y422进行cvtColor转换时出错-错误:(-215)scn == 2 && depth == 0,函数为cv :: cvtColor

7
我希望使用openCV读取一个YUV视频,该视频分辨率为1920*1080,采用YUV422格式(我已尝试使用yuviewer读取此视频且成功)。我正在使用Python3.6.4和Anaconda环境下的OpenCV 3.3.1。
最初我尝试了这个脚本https://dev59.com/enE95IYBdhLWcg3wn_Rr#47815385,但是这行代码:
cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_Y422)

出现了这个错误。

  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

当我尝试将Y444或Y420转换为RGB、RGBA或GREY时,也遇到了这个错误。 在Google或Stackoverflow上没有找到完全相同的错误。 我尝试重新安装opencv包,但它没有起作用。 在我的脚本中,每个cvtColor都有效,除了最后一个。我所说的有效是指它显示了图像,但颜色不正确。
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)

编辑

scn == 2 表示该函数需要一张包含两个通道的图像。 我更改了以下这些行:

frame_len = 1920 * 1080 * 2 # 4 Bytes for 2 pixels
shape = (height, width, 2) # To have a 2 channels image (not really working obviously)

现在cv2.cvtColor没有报错了,但仍然不能正常工作。我认为我的reshape完全错误。

我的结果:

我手动查看了numpy.array并与YUView比较了像素值和形状,符合我的预期(先是Y值,然后是U再是V),但这不是opencv显示的。

为什么在原始帧的Y矩阵下面有4个图像?

更准确地说,在我的情况下,输入cv2.cvtColor函数的数据应该是什么形状?


1
scn 表示“源图像的通道数”。| 不同的YUV变体使用不同数量的位来表示一个像素。例如,Y422每2个像素使用4字节,因此OpenCV期望一个2通道图像。显然情况并非如此,因为当您加载数据时,您加载了1.5字节/像素,并将其视为单通道。同样,Y444使用3字节/像素,因此如果输入图像实际上使用该格式,则会丢失一半的数据。 - Dan Mašek
@DanMašek 现在函数“工作”了(没有抛出错误),但图像的颜色和形状是错误的。这两个通道应该包含什么?在我的新脚本中,我使用yuv.reshape(height,width,2),但我不知道reshape如何工作,也不知道如何考虑数据的形状。在我得到的帧中,前1920 * 1080个像素是Y,接下来的1920 * 1080/2是U,然后是相同数量的V。 - amarion
使用ffmpeg首先将视频转换后,我已经能够使用opencv读取该视频。https://dev59.com/xGUo5IYBdhLWcg3wxBwe - amarion
然后我的目标是使用sk-video计算一些指标,它还使用ffmpeg在skvideo.io.vread函数中加载视频。然后您可以通过使用matplotlib显示矩阵来测试格式是否正确。在格式化视频之前,您可以使用以下方法测试其YUV格式: YUView:大多数情况下猜测正确的格式 yuvplayer:轻量级 - amarion
以下是我案例中的vread函数: video = skvideo.io.vread( filename, height=1080, width=1920, num_frames=num_frames, backend='ffmpeg', verbosity=0, as_grey=True, inputdict={ '-r': '20', '-pix_fmt': 'yuv422p', '-video_size': '1920x1080' } ) - amarion
1个回答

1
作为YUV 4:2:2有一些变体,如果您能确定您的YUV格式,那将更容易。我使用Logitech Brio网络摄像头拍摄使用ffmpeg录制的YUV视频,它给出了(YUY2 / 0x32595559), yuyv422的YUV。这也是YUV 4:2:2,但字节顺序有所不同。
由于YUV 4:2:2的压缩比是2/3,您正确地使用了2个字节来表示1个像素。这对我有效。
frame_len = int(width * height * 2)
shape = (height, width, 2)

而将YUV转换为BGR(opencv格式):

bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_YUY2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接