Sunday 11 October 2015

Splitting Colour images into its respective RGB channels

This tutorial gives a deep insight of splitting and merging function of opencv. Thus enabling us to split a color image into their respective RGB channels:

We want to split a color image into its three channels called "Red" ,"Green" and "Blue".
Splitting a color image into its respective RGB channels gives us an idea about the component of color which is present in an original image.
OpenCV provides built in function called “split()” for this purpose.
Syntax:
C++: void split(const Mat& src, Mat* mvbegin)
Parameters:        
src – input multi-channel array.
mv – output array or vector of arrays

In the first variant of the function the number of arrays must match src.channels(); the arrays themselves are reallocated, if needed.

The function “merge()” does just the opposite to that of split.
It creates one multichannel array out of several single-channel ones.

Syntax:
C++: void merge(const Mat* mv, size_t count, OutputArray dst)

Parameters:        
mv – input array or vector of matrices to be merged; all the matrices in mv  must have the same size and the same depth.
count – number of input matrices when mv is a plain C array; it must be greater than zero.
dst – output array of the same size and the same depth as mv[0].

The number of channels will be the total number of channels in the matrix array.
The functions merge merge several arrays to make a single multi-channel array.

Here is the code below:
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main()
{

    Mat image;
    image = imread("C:\\Users\\arjun\\Desktop\\aaa.png", CV_LOAD_IMAGE_COLOR);   // Read the file

    if(! image.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

   
 namedWindow( "Original Image", CV_WINDOW_AUTOSIZE );
 imshow( "Original Image", image );

    Mat rgbchannel[3];
    // The actual splitting.
    split(image, rgbchannel);

 namedWindow("Blue",CV_WINDOW_AUTOSIZE);
 imshow("Red", rgbchannel[0]);

 namedWindow("Green",CV_WINDOW_AUTOSIZE);
 imshow("Green", rgbchannel[1]);

 namedWindow("Red",CV_WINDOW_AUTOSIZE);
 imshow("Blue", rgbchannel[2]);

    waitKey(0);//Wait for a keystroke in the window
    return 0;
}

Input:
opencv rgb image

Output:
opencv blue channel image split

opencv green channel image split

opencv red channel image split


Note: 
You might have observed that here we get grayscale images instead of Red,Green and Blue colours separately after splitting the colour image.
Reason:
Split function splits the multichannel image into single channel arrays containing the identical pixel value of the original image.
So since we have created single channel images,opencv imshow function treats it as a grayscale image.
For a colour image, we need to create a three channel image.


The code for that is given below:
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

int main()
{
    Mat image=imread("C:\\Users\\arjun\\Desktop\\aaa.png",1);    
    namedWindow("Original Image",1);
 imshow("Original Image",image);

    // Split the image into different channels
    vector<Mat> rgbChannels(3);
    split(src, rgbChannels);

    // Show individual channels
    Mat g, fin_img;
    g = Mat::zeros(Size(image.cols, image.rows), CV_8UC1);
     
    // Showing Red Channel
    // G and B channels are kept as zero matrix for visual perception
    {
    vector<Mat> channels;
    channels.push_back(g);
    channels.push_back(g);
    channels.push_back(rgbChannels[2]);

    /// Merge the three channels
    merge(channels, fin_img);
    namedWindow("Red",1);
 imshow("Red", fin_img);
    }

    // Showing Green Channel
    {
    vector<Mat> channels;
    channels.push_back(g);
    channels.push_back(rgbChannels[1]);
    channels.push_back(g);    
    merge(channels, fin_img);
    namedWindow("Green",1);
 imshow("Green", fin_img);
    }

    // Showing Blue Channel
    {
    vector<Mat> channels;
    channels.push_back(rgbChannels[0]);
    channels.push_back(g);
    channels.push_back(g);
    merge(channels, fin_img);
    namedWindow("Blue",1);
    imshow("Blue", fin_img);
    }

    waitKey(0);
    return 0;

}

Input:

Output:
opencv blue channel image merge

opencv green channel image merge

opencv red channel image merge

Here after splitting the image by split(image, rgbChannels)
We get three channels of which
·        Rgbchannel[0] corresponds to that of “Blue” color image.
·        Rgbchannel[1] corresponds to that of “Green” color image
·        Rgbchannel[2] corresponds to that of “Red” color image

Since the split function splits the multi-channel image into single channel ,if we display these channels directly we would get the gray-scale image of RGB channels.
Thus we need to create a matrix of zeros and push that into other channels which are not needed.
Mat::zeros(Size(image.cols, image.rows), CV_8UC1 :
Creates a matrix of Zeros of single channel whose dimension is same as that of the original image.
Then we have initialized channels as the vector and push_back always puts a new element at the end of the vector.
Here the new element is a 8 bit single channel matrix of Zeros.

The BGR color ordering is the default order of OpenCV.
Refer:

Thus for displaying the red channels… we need to make the first two channels as Zeros and create a 3channel image with merge function to get the colored image.
Similar is the case with other channels of image.