Introduction
In the previous tutorial, we got familiar with the image pyramids concept. Now in this tutorial, we will see the color conversion feature of OpenCV. The mapping of colors from the real life to what the computer shows is not a straightforward process. That is why several organizations have come with different ideas and mechanisms to present the real life colors in the digital world of the computer graphics as close as possible. Those organizations have developed several color spaces. OpenCV supports most of them. We will see how to convert from one color space to another using ready OpenCV functions.
Color conversion between different color spaces
As we know, the human eye (and similar to it the digital cameras) can recognize the red, green and blue colors and recreate the other colors from these three. The color spaces, which are currently in use, are also based on these three colors. You can convert from one color space to other using different matrices. An example is the conversion from XYZ color space to RGB and vice versa. Using the below matrices we can convert between the two color spaces.


There is a lot of information on this topic available in Wikipedia as well in the great book of Richard Szeliski – Computer Vision: Algorithms and Applications. Check these sources to get more familiar with the concept of color spaces.
Here we will see how to use one OpenCV function in order to convert between the color spaces – cvtColor().
Color conversion between RGB and BGR
The first type of conversion, which we are going to look at, is the conversion between RGB and BGR. By default, when loading a colorful image, OpenCV stores the information for a pixel color in BGR order (Blue, Green, Red). First is the blue color value, then the green and last – the red value. However, if our algorithm needs to have the red value first, we can convert from BGR to RGB. OpenCV offers a wide variety of color conversions – around 150 to be precise. We will briefly mention them when describing the source codes.
Let us look at the source code for this conversion.
// Convert color image with alpha channel to color image without alpha channel void convertColorBGRAToColorBGR() { // Paths to the input and output image std::string l_pathToInputImage{ "../Resources/love.png" }; std::string l_pathToOutputImage{ "../Resources/love_bgr.png" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrix Mat l_outputImage; // Convert the colors cvtColor(l_image, l_outputImage, COLOR_BGRA2BGR); // Save the result image imwrite(l_pathToOutputImage, l_outputImage); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
We do the standard things – load an image from a file and check if we have loaded it correctly. Then we create one output matrix to hold the result.
The OpenCV function
Now, we call the function to convert the colors. The function cvtColor() in OpenCV is responsible for converting between different color spaces. As a first argument we provide the input image and as a second argument – the output matrix. Here, we are interested in the third argument. It is one enum cv::ColorConversionCodes, which holds many values. Each one of them represents one type of color space conversion. For example, we have BGR2BGRA, which will add additional alpha channel with value 255 to each pixel. There is BGRA2BGR (we use it in our example), which will remove the alpha channel. We have BGR2RGB, which will convert the pixel values from BGR (loaded by default) to RGB. And so on and so forth. In the first example, we will use those conversions, which are between BGR and RGB and their variants.
The result
As I said, in our example we will remove the alpha channel from the input image. Once the color conversion finishes, we will output the result to another file. I do this in order to show the difference between the input and the output. When I display the result to a window, it will look the same as the input and you will not be able to see the difference. Lastly, I show the result nevertheless.
See the result of the conversion below. The input image has some alpha (no white parts). In the result image, the white parts are the alpha, replaced by white color instead.

Color conversion between color image and grayscale image
The next example, which we are going to see, is the conversion from colorful image to a grayscale one. Again, if you look at the cv::ColorConversionCodes enum, you will see values like BGR2GRAY, RGB2GRAY, and GRAY2BGR and so on. We will use them in order to convert from colorful image to grayscale image. Note that GRAY2BGR will not colorize a grayscale image. It will only make it use 3 bytes for each pixel instead of one but the image will still be grayscale. In the future tutorials, we will see how to colorize an image. Let us look at the code.
// Convert color image to grayscale image void convertColorToGrayscale() { // Path to the input image std::string l_pathToInputImage{ "../Resources/city.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrix Mat l_outputImage; // Convert the colors cvtColor(l_image, l_outputImage, COLOR_BGR2GRAY); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result image namedWindow("Result", WINDOW_NORMAL); cv::imshow("Result", l_outputImage); }
There is nothing special about the code. We load an image from a file and check if it as loaded correctly. Then we create an output matrix to hold the results.
The OpenCV function
Next, we call the cvtColor() function with COLOR_BGR2GRAY in order to convert from BGR color space (the default in OpenCV for color images) to grayscale. There are several enum values, which convert from colorful image to grayscale. You have the option to convert from grayscale to RGB/BGR, but as I mentioned above, this will not colorize the image. There are also options to convert from the YUV color space to grayscale and even from Bayer image to grayscale. You can try the other options. For the Bayer options, I do not have any particular example, because this will be useful when reading images from a camera. We will do this in later tutorials.
Lastly, we display the results. The result on my side look like below. As you can, OpenCV has converted the color image to a grayscale one.

Conversion from BGR/RGB color space to another color space
The last example that I will show is the conversion between BGR/RGB and other color spaces. From this link, you can find more information about the formulas, used in the conversion process. Here is the source code:
// Convert between different color spaces void convertBGRRBGColorToXXXColor() { // Path to the input image std::string l_pathToInputImage{ "../Resources/city.jpg" }; // Create an object to hold the image data of the first image Mat l_image; // Read the image date from a file with no change to color scheme l_image = imread(l_pathToInputImage, IMREAD_UNCHANGED); // Check if we have read the first image data correctly if (!l_image.data) { std::cout << "No image data \n"; return; } // Create the output image matrices Mat l_outputImageBGR2XYZ; Mat l_outputImageRGB2XYZ; Mat l_outputImageBGR2YCrCb; Mat l_outputImageRGB2YCrCb; Mat l_outputImageBGR2HSV; Mat l_outputImageRGB2HSV; Mat l_outputImageBGR2Lab; Mat l_outputImageRGB2Lab; Mat l_outputImageBGR2Luv; Mat l_outputImageRGB2Luv; Mat l_outputImageBGR2HLS; Mat l_outputImageRGB2HLS; // Convert the colors cvtColor(l_image, l_outputImageBGR2XYZ, COLOR_BGR2XYZ); cvtColor(l_image, l_outputImageRGB2XYZ, COLOR_RGB2XYZ); cvtColor(l_image, l_outputImageBGR2YCrCb, COLOR_BGR2YCrCb); cvtColor(l_image, l_outputImageRGB2YCrCb, COLOR_RGB2YCrCb); cvtColor(l_image, l_outputImageBGR2HSV, COLOR_BGR2HSV); cvtColor(l_image, l_outputImageRGB2HSV, COLOR_RGB2HSV); cvtColor(l_image, l_outputImageBGR2Lab, COLOR_BGR2Lab); cvtColor(l_image, l_outputImageRGB2Lab, COLOR_RGB2Lab); cvtColor(l_image, l_outputImageBGR2Luv, COLOR_BGR2Luv); cvtColor(l_image, l_outputImageRGB2Luv, COLOR_RGB2Luv); cvtColor(l_image, l_outputImageBGR2HLS, COLOR_BGR2HLS); cvtColor(l_image, l_outputImageRGB2HLS, COLOR_RGB2HLS); // Display the input image namedWindow("Input", WINDOW_NORMAL); cv::imshow("Input", l_image); // Display the result images namedWindow("Result BGR2XYZ", WINDOW_NORMAL); cv::imshow("Result BGR2XYZ", l_outputImageBGR2XYZ); namedWindow("Result RGB2XYZ", WINDOW_NORMAL); cv::imshow("Result RGB2XYZ", l_outputImageRGB2XYZ); namedWindow("Result BGR2YCrCb", WINDOW_NORMAL); cv::imshow("Result BGR2YCrCb", l_outputImageBGR2YCrCb); namedWindow("Result RGB2YCrCb", WINDOW_NORMAL); cv::imshow("Result RGB2YCrCb", l_outputImageRGB2YCrCb); namedWindow("Result BGR2HSV", WINDOW_NORMAL); cv::imshow("Result BGR2HSV", l_outputImageBGR2HSV); namedWindow("Result RGB2HSV", WINDOW_NORMAL); cv::imshow("Result RGB2HSV", l_outputImageRGB2HSV); namedWindow("Result BGR2Lab", WINDOW_NORMAL); cv::imshow("Result BGR2Lab", l_outputImageBGR2Lab); namedWindow("Result RGB2Lab", WINDOW_NORMAL); cv::imshow("Result RGB2Lab", l_outputImageRGB2Lab); namedWindow("Result BGR2Luv", WINDOW_NORMAL); cv::imshow("Result BGR2Luv", l_outputImageBGR2Luv); namedWindow("Result RGB2Luv", WINDOW_NORMAL); cv::imshow("Result RGB2Luv", l_outputImageRGB2Luv); namedWindow("Result BGR2HLS", WINDOW_NORMAL); cv::imshow("Result BGR2HLS", l_outputImageBGR2HLS); namedWindow("Result RGB2HLS", WINDOW_NORMAL); cv::imshow("Result RGB2HLS", l_outputImageRGB2HLS); }
As usual, we start by loading an image from a file. This time we create more output matrices, to hold all the different variants of color spaces.
The OpenCV function
We call the cvtColor() function several times with different values for the third parameter in order to make different conversions. First, we make a conversion from BGR/RGB to XYZ color space. Then we convert from BGR/RGB to YCrCb. Next, we convert to HSV and to HSL, which is similar to HSV. Following is a conversion to L*a*b*. Finally, we convert from BGR/RGB to L*u*v. Please, check the provided link for more information about the different color spaces.
The result
Once all the conversions are over, we display them in different windows. You can see from the image below how each conversion result looks like. Notice, that each one of them provides a different result.

There are also Bayer to BGR/RGB conversions but we will look at them when we dealing with reading image frames from a camera. For now, I think we have seen enough color conversions.
Conclusion
In this tutorial, we saw how to convert from one image color space to another. This will be useful in the future. Remember that we have one function, capable of all the conversions we saw. Experiment with the provided code samples and see the differences.
As always, the code is available in GitHub and at the end of this tutorial as an archive.
Next thing we will see is color mapping and the way to pseudo colorize images.

Passionate developer, loving husband and caring father. As an introvert programming is my life. I work as a senior software engineer in a big international company. My hobbies include playing computer games (mostly World of Warcraft), watching TV series and hiking.