# Find all peaks for Mat() in OpenCV C++

I want to find all peaks for my image. I need it to divide my picture such way:

So, i already asked question, how to project all image to one of the axis, and now i need to find all maximums on this one-row image. Here's my part of the code:

void segment_plate (Mat input_image) {
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
Mat work_image = input_image;
Mat output;
//binarize image
//project it to one axis
reduce(work_image,output,0,CV_REDUCE_SUM,CV_32S);

//find minimum and maximum falue for ALL image
minMaxLoc(output, &minVal,&maxVal,&minLoc,&maxLoc);
cout << "min val : " << minVal << endl;
cout << "max val: " << maxVal << endl;


As you can see, i could find one maximum and one minimum for all picture, but i need to find local maximums. Thanks for any help!

EDIT Ok, so i made a mistake, i need to find peaks for this vector. I've used this code to find first peak:

int findPeakUtil(Mat arr, int low, int high, int n) {
// Find index of middle element
int mid = low + (high - low)/2;  /* (low + high)/2 */

// Compare middle element with its neighbours (if neighbours exist)
if ((mid == 0 || arr.at<int>(0,mid-1) <= arr.at<int>(0,mid)) &&
(mid == n-1 || arr.at<int>(0,mid+1) <= arr.at<int>(0,mid)))
return mid;

// If middle element is not peak and its left neighbor is greater than it
// then left half must have a peak element
else if (mid > 0 && arr.at<int>(0,mid-1) > arr.at<int>(0,mid))
return findPeakUtil(arr, low, (mid - 1), n);

// If middle element is not peak and its right neighbor is greater than it
// then right half must have a peak element
else return findPeakUtil(arr, (mid + 1), high, n);
}

// A wrapper over recursive function findPeakUtil()
int findPeak(Mat arr, int n) {
return findPeakUtil(arr, 0, n-1, n);
}


So now my code looks like:

void segment_plate (Mat input_image) {
Mat work_image = input_image;
Mat output;
//binarize image
//project it to one axis
reduce(work_image,output,0,CV_REDUCE_SUM,CV_32S);
int n = output.cols;
printf("Index of a peak point is %d", findPeak(output, n));


But how can i find another peaks? The algorithm of peak finding i took from here.

edit retag close merge delete

Sort by ยป oldest newest most voted

you can have a look here I guess this is what you are looking for. Plus look, to a newer implementation of mine below:

void non_maxima_suppression(const cv::Mat& src, cv::Mat& mask, const bool remove_plateaus)
{
// find pixels that are equal to the local neighborhood not maximum (including 'plateaus')

// optionally filter out pixels that are equal to the local minimum ('plateaus')
if (remove_plateaus) {
}
}

// function that finds the peaks of a given hist image
void findHistPeaks(InputArray _src, OutputArray _idx, const float scale = 0.2, const Size& ksize = Size(9, 9), const bool remove_plateus = true)
{
Mat hist = _src.getMat();
// die if histogram image is not the correct type
CV_Assert(hist.type() == CV_32F);

// find the min and max values of the hist image
double min_val, max_val;
minMaxLoc(hist, &min_val, &max_val);

GaussianBlur(hist, hist, ksize, 0); // smooth a bit in order to obtain better result
non_maxima_suppression(hist, mask, remove_plateus); // extract local maxima

vector<Point> maxima;   // output, locations of non-zero pixels

for(vector<Point>::iterator it = maxima.begin(); it != maxima.end();)
{
Point pnt = *it;
float pVal = hist.at<float>(/*pnt.x, */pnt.y - 1);
float val = hist.at<float>(/*pnt.x, */pnt.y);
float nVal = hist.at<float>(/*pnt.x, */pnt.y+1);
// filter peaks
if((val > max_val * scale))
++it;
else
it = maxima.erase(it);
}

Mat(maxima).copyTo(_idx);
}


Then you can call the function by either passing an std::vector<Point> or a cv::Mat as an output array. If you pass the scale attribute as 0 you will get every peak in the matrix, but if you don't want the small peaks then just leave it as it is or raise it to a higher value.

// vector<Point> peaks; or
Mat peaks;
findHistPeaks(b_hist, peaks);

more

Thanks a lot!

( 2015-03-04 19:44:31 -0600 )edit

@theodore, could you take a look at my try at your code

I got the mask of the histogram

But when I calculate and visualize the peaks, I get this result

Any idea why I would get this odd locations as peaks?

Code I am using for it

Mat mask;
hist_copy.convertTo(hist_copy, CV_32FC1);

double min_val, max_val;
minMaxLoc(hist_copy, &min_val, &max_val);

non_maxima_suppression(hist_copy, mask, true); // extract local maxima

vector<Point> maxima;   // output, locations of non-zero pixels

for(vector<Point>::iterator it = maxima.begin(); it != maxima.end();)
{
Point pnt = *it;
float pVal = hist_copy.at<float>(pnt.y - 1);
float val = hist_copy.at<float>(pnt.y);
float nVal = hist_copy.at<float>(pnt.y+1);
// filter peaks
if((val > max_val*0.2))
++it;
else
it = maxima.erase(it);
}

// Make a color hist
Mat hist_color(hist_copy.rows, hist_copy.cols, CV_32FC3);
Mat in_h[] = { hist_copy.clone(), hist_copy.clone(), hist_copy.clone() };
int from_to_h[] = { 0,0, 1,1, 2,2 };
mixChannels( in_h, 3, &hist_color, 1, from_to_h, 3 );
for(int i=0; i < maxima.size(); i++){
drawMarker(hist_color, maxima[i], Scalar(0,0,255), MARKER_STAR, 10, 1);
}

imshow("peaks", hist_color); waitKey(0);

more

@StevenPuttemans I will check it later when I find some time ;-)

( 2016-01-12 04:33:18 -0600 )edit

Aha no instant idea? I am kind of running against a deadline here and stuck in the middle of it :D

( 2016-01-12 04:34:24 -0600 )edit

A small explanation of that sketchy scale parameter could already give me some insight :D

( 2016-01-12 04:35:38 -0600 )edit

did you try to use the findHistPeak() as it is? also I think a bit of smoothing would help, try different kernels. Try also to play a bit with the scale ;-).

( 2016-01-12 04:48:44 -0600 )edit

Hmm I am running a different approach now first :D will keep you posted on the result.

( 2016-01-12 04:52:41 -0600 )edit

I think that GaussianBlur smooths peaks values. Despite of InputArray is defined to be const calling hist = _src.getMat();constructs a matrix header for the array (without copying data).... than 'GaussianBlur(hist, hist, ' will change (reduce) your source hist values.

( 2016-01-13 12:15:17 -0600 )edit

Ok I'm OT because you are looking a reason for odd peaks. BTW your markers are all at same height ... should marker point to be Point(maxima[i].y, hist_not_smoothed.at<float>(maxima[i].y)) ?

( 2016-01-13 13:41:51 -0600 )edit

@StevenPuttemans I am sorry but I did not have the time to check on your example. I am quite busy this period. In any case did you have any update.

( 2016-01-15 05:00:31 -0600 )edit

We took another approach at solving my situation, will edit it once I have the time :)

( 2016-01-15 05:55:46 -0600 )edit

@StevenPuttemans do you have maybe in the meantime your solution for the peak finder problem? :)

( 2016-08-10 09:43:14 -0600 )edit

Official site

GitHub

Wiki

Documentation