Ask Your Question
1

count number of peaks in histogram

asked 2015-02-06 22:26:54 -0600

Sandhya gravatar image

updated 2015-02-07 05:29:09 -0600

Guanta gravatar image

I have written a code to plot the histogram and i need to count the number of peaks in the histogram plot. Since i am new to it i was facing problem in finding the peaks, so please help me in solving this problem

#include "stdio.h"
#include "iostream"

#include "opencv\cxcore.h"
#include "opencv\highgui.h"
#include "opencv\cv.h"

#include "opencv2\core\core.hpp"
#include "opencv2\highgui\highgui.hpp"
#include "opencv2\imgproc\imgproc.hpp"


using namespace cv;
using namespace std;


//int main( int argc, char** argv )
//{
//  Mat src,hsv;
  // src=imread("DSC02712.JPG", CV_LOAD_IMAGE_COLOR);

    int main( int argc, char** argv )
{
  Mat src, dst,src1;

  /// Load image
  src = imread( "1.png", CV_LOAD_IMAGE_COLOR );
  cvtColor(src,src1,CV_RGB2GRAY);

  if( !src.data )
    { return -1; }

  /// Separate the image in 3 places ( B, G and R )
  //vector<Mat> bgr_planes;
  //split( src, bgr_planes );

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

  /// Set the ranges ( for B,G,R) )
  float range[] = { 0, 256 } ;
  const float* histRange = { range };

  bool uniform = true; bool accumulate = false;

  Mat b_hist;


  /// Compute the histograms:

  calcHist( &src1, 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );


  // Draw the histograms for B, G and R
  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 the result to [ 0, histImage.rows ]
  normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );

  /// Draw the histogram
  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  );
  }

  /// Display
  namedWindow("Histgram", CV_WINDOW_AUTOSIZE );
  imshow("Histgram", histImage );
waitKey(0);
}
edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
4

answered 2015-02-07 10:33:24 -0600

theodore gravatar image

updated 2015-02-10 20:06:11 -0600

search for finding local maximum in a matrix. With a fast search I found this one. I think that it is what you are looking for.

edit:

Since the code in the above link was a bit outdated, I transformed it a bit including also the drawing functions.

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

using namespace std;
using namespace cv;

int drawPeaks(Mat &histImage, vector<int>& peaks, int hist_size = 256, Scalar color = Scalar(0, 0, 255))
{
    int bin_w = cvRound( (double) histImage.cols / hist_size );
    for(size_t i = 0; i < peaks.size(); i++)
        line(histImage, Point(bin_w * peaks[i], histImage.rows), Point(bin_w * peaks[i], 0), color);

    imshow("Peaks", histImage);
    return EXIT_SUCCESS;
}

Mat drawHistogram(Mat &hist, int hist_h = 400, int hist_w = 1024, int hist_size = 256, Scalar color = Scalar(255, 255, 255), int type = 2)
{
    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 < histImage.cols; 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("Histogram", histImage);

    return histImage;
}

struct Length
{
    int pos1;
    int pos2;
    int size()
    {
        return pos2 - pos1 +1;
    }
};

struct PeakInfo
{
    int pos;
    int left_size;
    int right_size;
    float value;
};

PeakInfo peakInfo(int pos, int left_size, int right_size, float value)
{
    PeakInfo output;
    output.pos = pos;
    output.left_size = left_size;
    output.right_size = right_size;
    output.value = value;
    return output;
}

vector<PeakInfo> findPeaks(InputArray _src, int window_size)
{
    Mat src = _src.getMat();

    Mat slope_mat = src.clone();

    // Transform initial matrix into 1channel, and 1 row matrix
    Mat src2 = src.reshape(1, 1);

    int size = window_size / 2;

    Length up_hill, down_hill;
    vector<PeakInfo> output;

    int pre_state = 0;
    int i = size;

    while(i < src2.cols - size)
    {
        float cur_state = src2.at<float>(i + size) - src2.at<float>(i - size);

        if(cur_state > 0)
            cur_state = 2;
        else if(cur_state < 0)
            cur_state = 1;
        else cur_state = 0;

        // In case you want to check how the slope looks like
        slope_mat.at<float>(i) = cur_state;

        if(pre_state == 0 && cur_state == 2)
            up_hill.pos1 = i;
        else if(pre_state == 2 && cur_state == 1)
        {
            up_hill.pos2 = i - 1;
            down_hill.pos1 = i;
        }

        if((pre_state == 1 && cur_state == 2) || (pre_state == 1 && cur_state == 0))
        {
            down_hill.pos2 = i - 1;
            int max_pos = up_hill.pos2;
            if(src2.at<float>(up_hill.pos2) < src2.at<float>(down_hill.pos1))
                max_pos = down_hill.pos1;

            PeakInfo peak_info = peakInfo(max_pos, up_hill.size(), down_hill.size(), src2.at<float>(max_pos));

            output ...
(more)
edit flag offensive delete link more

Comments

The LocalMaximum() have to be written like the getLocalMaximum()? thanks

zms gravatar imagezms ( 2015-12-07 05:23:22 -0600 )edit

Could you please tell me precisely whats going on in findPeaks function?

tajmaj gravatar imagetajmaj ( 2018-11-16 16:06:00 -0600 )edit
3

answered 2015-02-07 10:54:40 -0600

berak gravatar image

for the fun of it, you could try an analytical solution, like:

 Mat dx;  Sobel(hist,dx,CV_32F,1,0,1); // zeros of the 1st derivative in x are are extremums

but you'd still have to iterate it to check the neighbours for slope, so ...

let's keep it simple: a histogram is a 1d array, and for a a peak value , both neighbour elements have to be <= center.

for (int i=1; i<hist.total()-1; ++i)
{
       float left  = hist.at<float>(i-1);
       float cent  = hist.at<float>(i);
       float right = hist.at<float>(i+1);
       // we have to set a boundary condition for 'plateaus', 
       // so just decide to have the 'cutoff' on the left side
       if ( left < cent  && right <= cent )
       {
               // peak !
       }
       // bonus track, get the valleys, too !
       if ( left > cent  && right >= cent )
       {
               // valley !
       }
 }

you will still have to think of a way to handle the 1st and last element (which are lacking the neighbour).

edit flag offensive delete link more

Comments

in the case of 1st and last element I guess you just consider that the left and right values are zero, respectively.

theodore gravatar imagetheodore ( 2015-02-07 15:24:51 -0600 )edit

not nessecarily, unfortunately,

|            ___              |
|\          /      \       ___|
|  \      /         \__/      |
|    \__/                     |
berak gravatar imageberak ( 2015-02-07 15:38:02 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-02-06 22:26:54 -0600

Seen: 12,964 times

Last updated: Feb 10 '15