3

I have been trying to convert a BGR captured frame into the YUYV format.

In OpenCV Python I can do convert YUYV into BGR with COLOR_YUV2BGR_YUY2 conversion code but I cannot do the reverse of this operation (there is no conversion code for this operation, I have tried COLOR_BGR2YUV but it is not converting correctly). I am curious about how to convert 3-channel BGR frame into the 2-channel YUYV frame.

Here you can see the code that I am using to change camera mode to capture YUYV and converting it into BGR, I am looking for the replacement of the cap.set(cv2.CAP_PROP_CONVERT_RGB, 0) so I can capture BGR and convert it into YUYV without cap.set(cv2.CAP_PROP_CONVERT_RGB, 0) (Because it is an optional capture setting and Windows DirectShow ignores this flag)

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)

And here is the debugger output to show the frame contents:

Link to the screenshot

I tried to understand the YUYV format but it has only 2-channels and down sampling process is quite complicated. I have checked the YUYV to BGR conversion methods but I could not find and mathematical conversion approaches (solutions are generally using ffmpeg utility from command line but I need to do it mathematically with numpy arrays I think)

Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Can Berk
  • 33
  • 6
  • 2
    How about cv2.cvtColorTwoPlane() ? It Converts an image from one color space to another where the source image is stored in two planes. – cyborg Dec 27 '21 at 14:39
  • In case you want "manual" conversion, take a look at my following [answer](https://stackoverflow.com/a/60902174/4926757). Don't use the code as is. Do some research... If you want accurate colors, you have to use the correct conversion formula. The popular non HDR standard is BT.709, but BT.601 is still used. There are also "limited range", where Y range is [16, 235] (used in video), and "full range" where Y range is [0, 255] (used in JPEG). – Rotem Dec 27 '21 at 21:41

1 Answers1

1

You can use the following code to convert your image to YUV and after that create YUYV from YUV. In this example an image is given as input to the program:

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))
  • Thank you so much, this makes the required conversion between the types in the best way and I think this answer is valid. Only problem is my frames that are coming from the camera have critical metadata about the frame and the data loss causes corruption on that part so I am not going to be able to use this method. Hope it helps someone else. – Can Berk Dec 28 '21 at 15:01