Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

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')
    cv::dilate(src, mask, cv::Mat());
    cv::compare(src, mask, mask, cv::CMP_GE);

    // optionally filter out pixels that are equal to the local minimum ('plateaus')
    if (remove_plateaus) {
        cv::Mat non_plateau_mask;
        cv::erode(src, non_plateau_mask, cv::Mat());
        cv::compare(src, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
        cv::bitwise_and(mask, non_plateau_mask, mask);
    }
}

// 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);

    Mat mask;
    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
    cv::findNonZero(mask, maxima);

    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 a 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);

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')
    cv::dilate(src, mask, cv::Mat());
    cv::compare(src, mask, mask, cv::CMP_GE);

    // optionally filter out pixels that are equal to the local minimum ('plateaus')
    if (remove_plateaus) {
        cv::Mat non_plateau_mask;
        cv::erode(src, non_plateau_mask, cv::Mat());
        cv::compare(src, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
        cv::bitwise_and(mask, non_plateau_mask, mask);
    }
}

// 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);

    Mat mask;
    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
    cv::findNonZero(mask, maxima);

    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 a std::vector<point> an std::vector<Point> or a cv::Mat 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);

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')
    cv::dilate(src, mask, cv::Mat());
    cv::compare(src, mask, mask, cv::CMP_GE);

    // optionally filter out pixels that are equal to the local minimum ('plateaus')
    if (remove_plateaus) {
        cv::Mat non_plateau_mask;
        cv::erode(src, non_plateau_mask, cv::Mat());
        cv::compare(src, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
        cv::bitwise_and(mask, non_plateau_mask, mask);
    }
}

// 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);

    Mat mask;
    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
    cv::findNonZero(mask, maxima);

    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);