Merl
Merl

Reputation: 131

Function to determine all local maxima of a histogram

Is there an OpenCV function that can give me a list of all the local maxima for a histogram? Maybe there is a function that lets me specify a minimum peak/threshold and will tell me the bins of all those local maxima above that threshold.

If not, is there a function that can sort the bins from highest(most frequent) to lowest (least frequent). I can then grab all the first 20 or so bins and I have my 20 biggest local maxima.

Upvotes: 2

Views: 2334

Answers (2)

ACCurrent
ACCurrent

Reputation: 385

Opencv minMaxLoc can be used in this context with a sliding window. If the location of the maxima is on an edge then ignore the maxima, otherwise record as maxima. You can use something like the function below (Note: this code is more like psuedocode it has not been tested)

/**
* Assumes a 1 channel histogram
*/
vector<int> findMaxima(Mat histogram, int windowsize, int histbins){
   vector<int> maximas;
   int lastmaxima;
   for(int i = 0; i < histbins - windowsize; i++){
       //Just some Local variables, only maxloc and maxval are used.
       int maxval,minval;
       Point* maxloc, maxloc;
       //Crop the windows
       Rect window(i,0,windowsize,1);
       //Get the maxima
       minMaxLoc(histogram(window), minval,maxval,maxloc,minloc);
       //Check if its not on the side
       if(maxloc.x != 0&&maxloc.x != windowsize-1){
            //Translate from cropped window into real position
            int originalposition = maxloc.x+i;
            //Check that this is a new maxima and not already recorded
            if(lastmaxima != originalposition){
               maximas.push(originalposition);
               lastmaxima = originalposition;
            }
       }
   }
   return maximas;
}

Of course this is a very simplistic system. You might want to use a multiscale approach with different sliding window sizes. You may also need to apply gaussian smoothing depending on your data. Another approach could be to run this for a small window size like 3 or 4 (you need a mimimum of 3). Then you could use something else for non maxima-suppression.

For your approach in which you suggested

Maybe there is a function that lets me specify a minimum peak/threshold and will tell me the bins of all those local maxima above that threshold.

You could simply perform a threshold before finding the maxima with the above function.

threshold(hist,res ...aditional parameters...);
vector<int> maximas = findMaximas(hist, ...other parameters...);

Upvotes: 1

alexisrozhkov
alexisrozhkov

Reputation: 1632

AFAIK OpenCV doesn't have such functionality, but it is possible do implement something similar yourself.

In order to sort histogram bins you can possibly use sortIdx, but as a result you will obtain list of largest bins, which is different than local maxima (those should be "surrounded" by smaller values).

To obtain local maxima you can compare each bin with its neighbors (2 in 1D case). A bin should be larger than neighbors with some margin to be considered a local maximum.

Depending on the size of the bins, you may want to filter the histogram before this step (for example convolve it with Gaussian kernel), since otherwise you'd obtain too much of these maxima, especially for small bin sizes. If you've used Gaussian kernel - it's sigma would be related to the size of the neighborhood in which detected local maxima are "global".

Once you detect those points - you may want to perform non-maximal suppression, to replace groups of points that lie very close together with a single point. A simple strategy for that would be to sort those maxima according to some criteria (for example difference with neighbors), then take one maximum and remove all the points in its neighborhood (its size can be related the the Gaussian kernel sigma), take next remaining maximum and again remove points in its neighborhood and so on until you run out of points or go below some meaningful difference values.

Finally, you may want to sort remaining candidate points by their absolute values (to get "largest" local maxima), or by their differences with neighbors (to get "sharpest" ones).

You may try another approach. We can use this definition of local maximum to implement a simpler algorithm: just move a sliding window of size S along the histogram and pick maximum in each position. This will have some problems:

  • in locations with prominent maximum multiple window positions will generate points that correspond to the same maximum (can be fixed with non maximum suppression),
  • in locations with no or small variation it will return semi-random maxima (can be fixed with threshold on variance in window or difference between maximum and neighborhood),
  • in regions with monotonic histogram it will return a largest value (which is not necessarily a maximum).

Once you perform all the "special case" handling - those 2 approaches would be quite similar I believe.

Another thing to implement may be "multi scale" approach, which can be considered as an extension if those 2. Basically it boils down to detecting local maxima for different neighborhood sizes, and then storing them all along with corresponding neighborhood size, which can be helpful for some purposes.

As you can see, this is a quite vague guide, and there's a reason for that: the type and amount of local maximas you want to get will most likely depend on the problem you have in mind. There's no hard and easy rule to decide if the point should be considered a local maxima, so you should probably start with some simple approach and then refine it for your specific case.

Upvotes: 0

Related Questions