Ask Your Question
1

draw cumulative histogram output

asked 2015-09-30 07:09:31 -0600

sarmad gravatar image

updated 2016-01-07 09:04:02 -0600

Hi

I have got the histogram of Y channel of YCrCb

the output after drawing with this code

 int hist_w = 512; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

 normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

// Draw for each channel

for( int i = 1; i < histSize; i++ )

{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) , Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ), Scalar( 255, 0, 0), 2, 8, 0 );

}

is :

Output

I want to draw it like this :

another drawing

edit retag flag offensive close merge delete

Comments

May be this

line( histImage, Point( bin_w*(i-1), hist_h  ) , Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ), Scalar( 255, 0, 0), 2, 8, 0 );
LBerger gravatar imageLBerger ( 2015-09-30 07:15:22 -0600 )edit
1

What you want to draw is a cumulative histogram. The formula is very simple.

Eduardo gravatar imageEduardo ( 2015-09-30 07:48:11 -0600 )edit

How can I draw it ?

sarmad gravatar imagesarmad ( 2015-09-30 08:14:15 -0600 )edit
3

just apply something like cumulativeHistogram[i] = histogram[i] + cumulativeHistogram[i - 1]; in a loop for the size of your already obtained histogram.

theodore gravatar imagetheodore ( 2015-09-30 09:19:58 -0600 )edit

You can find definition here. In discrete you can use previous comment from @theodore

In matlab I think you can calulate using cumsum function

LBerger gravatar imageLBerger ( 2015-10-01 06:19:35 -0600 )edit

I'm confused a little bit about what it is cumulative histogram ?

is that is the same histogram that is calculated with calcHist() function in open cv ?

sarmad gravatar imagesarmad ( 2015-10-01 08:19:33 -0600 )edit

In histogram h(i) is equal to pixel number with gray value i

in cumulative histogram ch(i) is equal to pixel number with gray value less or equal to i.

Hence in 8 bit image ch(255) is equal to image size (in pixels)

LBerger gravatar imageLBerger ( 2015-10-01 08:26:41 -0600 )edit

2 answers

Sort by ยป oldest newest most voted
5

answered 2015-10-01 13:50:10 -0600

theodore gravatar image

updated 2015-10-02 10:35:20 -0600

try this code:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

Mat drawHistogram(Mat &hist, int hist_h = 400, int hist_w = 1012, int hist_size = 256, Scalar color = Scalar(255, 255, 255), int type = 2, string title = "Histogram")
{
    int bin_w = cvRound( (double) hist_w/hist_size );

    Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

    /// Normalize the result to [ 0, histImage.rows ]
    normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

    switch (type) {
    case 1:
        for(int i = 0; i < hist_size; i++)
        {
            const unsigned x = i;
            const unsigned y = hist_h;

            line(histImage, Point(bin_w * x, y),
                 Point(bin_w * x, y - cvRound(hist.at<float>(i))),
                 color);
        }

        break;
    case 2:
        for( int i = 1; i < hist_size; ++i)
        {
            Point pt1 = Point(bin_w * (i-1), hist_h);
            Point pt2 = Point(bin_w * i, hist_h);
            Point pt3 = Point(bin_w * i, hist_h - cvRound(hist.at<float>(i)));
            Point pt4 = Point(bin_w * (i-1), hist_h - cvRound(hist.at<float>(i-1)));
            Point pts[] = {pt1, pt2, pt3, pt4, pt1};

            fillConvexPoly(histImage, pts, 5, color);
        }
        break;
    default:
        for( int i = 1; i < hist_size; ++i)
        {
            line( histImage, Point( bin_w * (i-1), hist_h - cvRound(hist.at<float>(i-1))) ,
                             Point( bin_w * (i), hist_h - cvRound(hist.at<float>(i))),
                             color, 1, 8, 0);
        }

        break;
    }

    imshow(title, histImage);

    return histImage;
}
int main()
{
        /// Load image
        Mat src = imread( "lena.png");
        if( !src.data )
          { return -1; }

        Mat gray;
        cvtColor(src, gray, CV_RGB2GRAY);

        /// Establish the number of bins
        int histSize = 256;

        /// Set the range
        float range[] = { 0, 256 } ;
        const float* histRange = { range };

        bool uniform = true; bool accumulate = false;

        // compute the histogram
        Mat hist;
        calcHist( &gray, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate );

        // calculate cumulative histogram
        Mat c_hist(hist.size(), hist.type());

        c_hist.at<float>(0) = hist.at<float>(0)
        for(size_t k = 1; k < hist.rows; ++k)
            c_hist.at<float>(k) = hist.at<float>(k) + c_hist.at<float>(k-1);

        // draw histogram
        drawHistogram(hist, 400, 1024, hist.rows, Scalar(255, 255, 255), 2);
        // draw cumulative histogram
        drawHistogram(c_hist, 400, 1024, c_hist.rows, Scalar(255, 255, 255), 2, "cumulativeHistogram");

        waitKey(0);

        return 0;
}

input image:

image description

histogram:

image description

cumulative histogram:

image description

edit flag offensive delete link more
0

answered 2015-10-05 10:12:23 -0600

sarmad gravatar image

Thanks @theodore for the perfect answer i have qustion

why in this line the value at (0) is equal to (30) ? is there any reason for choosing 30 ?

c_hist.at<float>(0) = hist.at<float>(30);

edit flag offensive delete link more

Comments

where is this line and I cannot find it? is it at my code?

theodore gravatar imagetheodore ( 2015-10-05 10:55:49 -0600 )edit

Mat c_hist(hist.size(), hist.type()); In this line you passed hist size and type to MAT object , right ?

and my question is that what the difference will be if we write

    c_hist.at<float>(0) = hist.at<float>(30)     ?
sarmad gravatar imagesarmad ( 2015-10-06 04:39:32 -0600 )edit

@sarmad yes in the beginning I am creating a matrix of the same size and type as your original histogram image. As for your second question

    c_hist.at<float>(0) = hist.at<float>(0) // line 1
    for(size_t k = 1; k < hist.rows; ++k)    // line 2
        c_hist.at<float>(k) = hist.at<float>(k) + c_hist.at<float>(k-1); // line 3

in line 1 I am initializing the first value of the cumulative histogram image with the first value of the normal histogram image. Since if you notice in the the last variable in line 3 I need to use the previous value of the cumulative image all the time for that reason I am starting my loop for k = 1 and not 0 since if I start for k = 0 in the first run the c_hist.at<float>(k-1) will contain garbage.

theodore gravatar imagetheodore ( 2015-10-06 06:42:32 -0600 )edit

now if you use c_hist.at<float>(0) = hist.at<float>(30) instead then you will initialize the first value in the cumulative image with the 30st value of you normal histogram image, which is something that it is wrong. Actually, you can replace the below code:

// calculate cumulative histogram
Mat c_hist(hist.size(), hist.type());

c_hist.at<float>(0) = hist.at<float>(0)
for(size_t k = 1; k < hist.rows; ++k)
    c_hist.at<float>(k) = hist.at<float>(k) + c_hist.at<float>(k-1);

with:

// calculate cumulative histogram
Mat c_hist = hist.clone();

for(int k = 1; k < c_hist.rows; ++k)
    c_hist.at<float>(k) += c_hist.at<float>(k-1);

I hope that it is more understandable to you now. Let me know otherwise ;-).

theodore gravatar imagetheodore ( 2015-10-06 06:56:59 -0600 )edit

It is clear thanks , I want to use video file to calculate the cumulative histogram , what changes should be done

Mat frame;

cap >> frame; // get a new frame

imshow( "video", frame );

cvtColor(frame, ycbcr, CV_RGB2GRAY);

I have tried it this error is displayed

1>source.cpp(105): warning C4244: 'initializing' : conversion from 'int' to 'float', possible loss of data 1>source.cpp(113): warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data

sarmad gravatar imagesarmad ( 2015-10-07 05:53:37 -0600 )edit

these are not errors, but warnings. Your code should work though without problem. However, you should be aware of them since they can lead to some strange behavior of your algorithm. This output points you at lines 105 and 113 of your source code in order to see what you are doing there.

theodore gravatar imagetheodore ( 2015-10-07 06:49:46 -0600 )edit

I want to apply cumulative histogram to a video file I have made theses changes

   int main()
  {  
      /// Load image
      VideoCapture cap("eye movements.mp4"); // open video

     if(!cap.isOpened())  // check if we succeeded

      return -1;

   while(1)
  {
   Mat frame;
  cap >> frame; // get a new frame
  imshow( "video", frame );

this is the output , it is not updating the histogram and I think only first frame is displayed

outputoutput

sarmad gravatar imagesarmad ( 2015-10-07 08:10:08 -0600 )edit

please edit the post and add your full while() loop, because with the code snippet that you have added I cannot see if you are doing something wrong later. This code is only the frame capturing part which seems ok.

theodore gravatar imagetheodore ( 2015-10-07 10:34:56 -0600 )edit

I have uploaded it here

code

sarmad gravatar imagesarmad ( 2015-10-07 10:51:34 -0600 )edit

I tested your code and it works perfectly here.

theodore gravatar imagetheodore ( 2015-10-07 11:10:01 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-09-30 07:09:31 -0600

Seen: 3,543 times

Last updated: Oct 05 '15