2

I am a beginner in openCV.

I want to plot the intensity profile for R, G and B for the image given below.

I am like to plot R, G and B values w.r.t to pixel location in three different graphs.

So far I have learnt how to read an Image and display. for example using imread();

 Mat img = imread("Apple.bmp");

and then showing it on the screen using imshow(" Window", img);.

Now I would like to put all R , G and B values in 3 separate buffers; buf1, buf2, buf3 and plot these values.

Kindly provide me some hint or a sample code snippet to help me understand this.

enter image description here

user2799508
  • 844
  • 1
  • 15
  • 41
  • do you want a [histogram](http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html#histogram-calculation) ? – berak Jul 01 '14 at 06:27
  • No. I just want to scan and plot variation of R (say) along any axis. – user2799508 Jul 01 '14 at 06:31
  • @berak Can you tell me how to extract R, G and B values and put in three different arrays? I will do rest. Thanks – user2799508 Jul 01 '14 at 06:53
  • possible duplicate of [Accessing certain pixel RGB value in openCV](http://stackoverflow.com/questions/8932893/accessing-certain-pixel-rgb-value-in-opencv) – GPPK Jul 01 '14 at 07:01
  • 1
    @GPPK, how is that a duplicate? – Bull Jul 01 '14 at 08:01

1 Answers1

4

You can separate R, G and B into separate Mats using cv::split()

std::vector<Mat> planes(3);
cv::split(img, planes);
cv::Mat R = planes[2];
cv::Mat G = planes[1];
cv::Mat B = planes[0];

But you only need to separate them like this if you have code that is expecting a Mat with a single color channnel. Don't use at<>() as the supposed duplicate suggest - it is really slow if you are sequentially scanning an image (but it is good for random access).

You can scan the image efficiently like this

for(int i = 0; i < img.rows; ++i)
{
    // get pointers to each row
    cv::Vec3b* row = img.ptr<cv::Vec3b>(i);

    // now scan the row
    for(int j = 0; j < img.cols; ++j)
    {   
        cv::Vec3b pixel = row[j];
        uchar r = pixel[2];
        uchar g = pixel[1];
        uchar b = pixel[0];
        process(r, g, b);
    } 
}

Lastly if you do want to make a histogram, you can use this code. It is fairly old so I suppose it still works.

void show_histogram_image(cv::Mat src, cv::Mat &hist_image)
{ // based on http://docs.opencv.org/2.4.4/modules/imgproc/doc/histograms.html?highlight=histogram#calchist

   int sbins = 256;
   int histSize[] = {sbins};

   float sranges[] = { 0, 256 };
   const float* ranges[] = { sranges };
   cv::MatND hist;
   int channels[] = {0};

   cv::calcHist( &src, 1, channels, cv::Mat(), // do not use mask
       hist, 1, histSize, ranges,
       true, // the histogram is uniform
       false );

   double maxVal=0;
   minMaxLoc(hist, 0, &maxVal, 0, 0);

   int xscale = 10;
   int yscale = 10;
   //hist_image.create(
   hist_image = cv::Mat::zeros(256, sbins*xscale, CV_8UC3);

   for( int s = 0; s < sbins; s++ )
   {
       float binVal = hist.at<float>(s, 0);
       int intensity = cvRound(binVal*255/maxVal);
       rectangle( hist_image, cv::Point(s*xscale, 0),
           cv::Point( (s+1)*xscale - 1, intensity),
           cv::Scalar::all(255),
           CV_FILLED );
   }
}
Bull
  • 11,771
  • 9
  • 42
  • 53
  • Can you tell me where can I get the definition of process() you have used? – user2799508 Jul 01 '14 at 09:10
  • 1
    Oh perhaps you mean I have to write my own function for processing this data. – user2799508 Jul 01 '14 at 09:14
  • B's horn of plenty again .. ;) – berak Jul 01 '14 at 09:29
  • @B... Thanks for the code snippet. However, I would like to collect r, g, b in three different arrays and not as chars which are overwritten in each loop iteration as you have shown. – user2799508 Jul 01 '14 at 09:29
  • @user2799508 that's the 1st solution in the answer above, 1 plane(Mat) for each color channel – berak Jul 01 '14 at 09:31
  • 1
    @berak Sorry for weak english. To clarify further I have asked this question [Saving Mats to int arrays in opencv](http://stackoverflow.com/questions/24507207/converting-mats-to-int-arrays-in-opencv) – user2799508 Jul 01 '14 at 09:50
  • @user2799508 I have answered your other question, just use convertTo() to change the whole color plane from uchar to int. – Bull Jul 01 '14 at 12:31