使用OpenCV Python从BGR转换为YUYV

3

我一直在尝试将BGR捕获的帧转换为YUYV格式。

在OpenCV Python中,我可以使用COLOR_YUV2BGR_YUY2转换代码将YUYV转换为BGR,但是我无法执行此操作的反向转换(没有转换代码)。我尝试了COLOR_BGR2YUV,但它没有正确转换。我想知道如何将3通道的BGR帧转换为2通道的YUYV帧。

这里您可以看到我正在使用的代码,将相机模式更改为捕获YUYV并将其转换为BGR,我正在寻找替换cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)的方法,以便我可以捕获BGR并将其转换为YUYV而不需要cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)(因为它是一个可选的捕获设置,Windows DirectShow忽略此标志)。

import cv2
import numpy as np

cap = cv2.VideoCapture(4)
_, frame = cap.read()
cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)  # How to replace this line with another BGR to YUYV conversion?
_, frame_rgb_off = cap.read()
bgr_cvt = cv2.cvtColor(frame_rgb_off, cv2.COLOR_YUV2BGR_YUY2)

以下是调试器输出,显示帧内容:

截图链接

我试图理解YUYV格式,但它只有两个通道,并且降采样过程非常复杂。我已经检查了YUYV到BGR的转换方法,但我没有找到数学转换方法(解决方案通常使用命令行中的ffmpeg实用程序,但我认为需要使用numpy数组进行数学处理)。


2
cv2.cvtColorTwoPlane() 怎么样?它可以将一个由两个平面存储的源图像从一种颜色空间转换为另一种。 - cyborg
如果你需要“手动”转换,请查看我以下的答案。不要直接使用代码,需要进行一些研究... 如果你想要准确的颜色,就必须使用正确的转换公式。流行的非HDR标准是BT.709,但BT.601仍在使用中。还有“有限范围”,其中Y范围是[16, 235](用于视频),以及“全范围”,其中Y范围是[0, 255](用于JPEG)。 - Rotem
1个回答

1
您可以使用以下代码将图像转换为YUV,然后从YUV创建YUYV。在此示例中,将图像作为程序输入:
您可以使用以下代码将图像转换为YUV,然后从YUV创建YUYV。在此示例中,将图像作为程序输入:
import cv2
import numpy as np

# Load sample image
img_bgr = cv2.imread("home.jpg")
cv2.imshow("original", img_bgr)
cv2.waitKey(0)

# Convert from BGR to YUV
img_yuv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YUV)

# Converting directly back from YUV to BGR results in an (almost) identical image
img_bgr_restored = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)
cv2.imshow("converted", img_bgr_restored)
cv2.waitKey(0)
diff = img_bgr.astype(np.int16) - img_bgr_restored
print("mean/stddev diff (BGR => YUV => BGR)", np.mean(diff), np.std(diff))

# Create YUYV from YUV
y0 = np.expand_dims(img_yuv[...,0][::,::2], axis=2)
u = np.expand_dims(img_yuv[...,1][::,::2], axis=2)
y1 = np.expand_dims(img_yuv[...,0][::,1::2], axis=2)
v = np.expand_dims(img_yuv[...,2][::,::2], axis=2)
img_yuyv = np.concatenate((y0, u, y1, v), axis=2)
img_yuyv_cvt = img_yuyv.reshape(img_yuyv.shape[0], img_yuyv.shape[1] * 2, 
int(img_yuyv.shape[2] / 2))

# Convert back to BGR results in more saturated image.
img_bgr_restored = cv2.cvtColor(img_yuyv_cvt, cv2.COLOR_YUV2BGR_YUYV)
cv2.imshow("converted", img_bgr_restored)
cv2.waitKey(0)

diff = img_bgr.astype(np.int16) - img_bgr_restored
print("mean/stddev diff (BGR => YUV => YUYV => BGR)", np.mean(diff), np.std(diff))

非常感谢,这种方式可以最好地完成所需的类型转换,我认为这个答案是有效的。唯一的问题是我的相机传来的帧包含关键元数据,数据丢失会导致该部分损坏,因此我将无法使用这种方法。希望能对其他人有所帮助。 - Can Berk

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