'OpenCV Display Colored Cb Cr Channels

So I understand how to convert a BGR image to YCrCb format using cvtColor() and seperate different channels using split() or mixChannels() in OpenCV. However, these channels are displayed as grayscale images as they are CV_8UC1 Mats.

I would like to display Cb and Cr channels in color like Barns image on Wikipedia. I found this solution in Matlab, but how do I do it in OpenCV?

Furthermore, the mentioned solution displayed Cb and Cr channels by "fills the other channels with a constant value of 50%". My question is:

Is this the common way to display Cr Cb channels? Or is there any recommendations or specifications when displaying Cr Cb channels?



Solution 1:[1]

I made a code from scratch as described in answer. Looks like it's what you need.

Mat bgr_image = imread("lena.png");

Mat yCrCb_image;
cvtColor(bgr_image, yCrCb_image, CV_BGR2YCrCb);

Mat yCrCbChannels[3];
split(yCrCb_image, yCrCbChannels);

Mat half(yCrCbChannels[0].size(), yCrCbChannels[0].type(), 127);
vector<Mat> yChannels = { yCrCbChannels[0], half, half };
Mat yPlot;
merge(yChannels, yPlot);
cvtColor(yPlot, yPlot, CV_YCrCb2BGR);
imshow("y", yPlot);

vector<Mat> CrChannels = { half, yCrCbChannels[1], half };
Mat CrPlot;
merge(CrChannels, CrPlot);
cvtColor(CrPlot, CrPlot, CV_YCrCb2BGR);
imshow("Cr", CrPlot);

vector<Mat> CbChannels = { half, half, yCrCbChannels[2] };
Mat CbPlot;
merge(CbChannels, CbPlot);
cvtColor(CrPlot, CrPlot, CV_YCrCb2BGR);
imshow("Cb", CbPlot);
waitKey(0);

enter image description here

As for converting grayscale images to color format, usually in such case all color channels (B, G, R) set to one grayscale value. In OpenCV CV_GRAY2BGR mode implemented in that manner.

As for "fills the other channels with a constant value of 50%" I believe it's common way to visualize such color spaces as YCbCr and Lab. I did not find any articles and descriptions of this approach, but I think it's driven by visualization purposes. Indeed, if we fill the other channels with zero, fundamentally nothing has changed: we can also see the influence of each channel, but the picture does not look very nice:

enter image description here

So, the aim of this approach to make visualization more colorful.

Solution 2:[2]

For thoses who want the code in Python (which is the same as @akarsakov) here it is :

import cv2
import numpy as np

img = cv2.imread(r"lena.png")

imgYCC = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)

Y,Cr,Cb = cv2.split(imgYCC)

half = np.array([[127]*Y.shape[1]]*Y.shape[0]).astype(Y.dtype)

merge_Y = cv2.merge([Y, half, half])
merge_Cb = cv2.merge([half, half, Cb])
merge_Cr = cv2.merge([half, Cr, half])

merge_Y = cv2.cvtColor(merge_Y, cv2.COLOR_YCrCb2BGR)
merge_Cb = cv2.cvtColor(merge_Cb, cv2.COLOR_YCrCb2BGR)
merge_Cr = cv2.cvtColor(merge_Cr, cv2.COLOR_YCrCb2BGR)

cv2.imwrite(r'Y.png', merge_Y)
cv2.imwrite(r'Cb.png', merge_Cb)
cv2.imwrite(r'Cr.png', merge_Cr)

The result isn't the same by the way and more look like what we could find on google when we write Y Cb Cr images. Or maybe I did a mistake with split and/or BGR.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Panda50