Find local maxima in grayscale image using OpenCV

前端 未结 10 2253
暗喜
暗喜 2020-11-30 04:44

Does anybody know how to find the local maxima in a grayscale IPL_DEPTH_8U image using OpenCV? HarrisCorner mentions something like that but I\'m actually not i

相关标签:
10条回答
  • 2020-11-30 05:25

    The first question to answer would be what is "local" in your opinion. The answer may well be a square window (say 3x3 or 5x5) or circular window of a certain radius. You can then scan over the entire image with the window centered at each pixel and pick the highest value in the window.

    See this for how to access pixel values in OpenCV.

    0 讨论(0)
  • 2020-11-30 05:26

    You can go over each pixel and test if it is a local maxima. Here is how I would do it. The input is assumed to be type CV_32FC1

    #include <vector>//std::vector
    #include <algorithm>//std::sort
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/core/core.hpp"
    
    //structure for maximal values including position
    struct SRegionalMaxPoint
    {
        SRegionalMaxPoint():
            values(-FLT_MAX),
            row(-1),
            col(-1)
        {}
        float values;
        int row;
        int col;
        //ascending order
        bool operator()(const SRegionalMaxPoint& a, const SRegionalMaxPoint& b)
        {   
            return a.values < b.values;
        }   
    };
    
    //checks if pixel is local max
    bool isRegionalMax(const float* im_ptr, const int& cols )
    {
        float center = *im_ptr;
        bool is_regional_max = true;
        im_ptr -= (cols + 1);
        for (int ii = 0; ii < 3; ++ii, im_ptr+= (cols-3))
        {
            for (int jj = 0; jj < 3; ++jj, im_ptr++)
            {
                if (ii != 1 || jj != 1)
                {
                    is_regional_max &= (center > *im_ptr);
                }
            }
        }
        return is_regional_max;
    }
    
    void imregionalmax(
        const cv::Mat& input, 
        std::vector<SRegionalMaxPoint>& buffer)
    {
        //find local max - top maxima
        static const int margin = 1;
        const int rows = input.rows;
        const int cols = input.cols;
        for (int i = margin; i < rows - margin; ++i)
        {
            const float* im_ptr = input.ptr<float>(i, margin);
            for (int j = margin; j < cols - margin; ++j, im_ptr++)
            {
                //Check if pixel is local maximum
                if ( isRegionalMax(im_ptr, cols ) )
                {
                    cv::Rect roi = cv::Rect(j - margin, i - margin, 3, 3);
                    cv::Mat subMat = input(roi);
    
                    float val = *im_ptr;
                    //replace smallest value in buffer
                    if ( val > buffer[0].values )
                    {
                        buffer[0].values = val;
                        buffer[0].row    = i;
                        buffer[0].col    = j;
                        std::sort(buffer.begin(), buffer.end(), SRegionalMaxPoint());
                    }
    
                }
            }
        }
    
    }
    

    For testing the code you can try this:

    cv::Mat temp = cv::Mat::zeros(15, 15, CV_32FC1);
    temp.at<float>(7, 7) = 1;
    temp.at<float>(3, 5) = 6;
    temp.at<float>(8, 10) = 4;
    temp.at<float>(11, 13) = 7;
    temp.at<float>(10, 3) = 8;
    temp.at<float>(7, 13) = 3;
    
    vector<SRegionalMaxPoint> buffer_(5);
    imregionalmax(temp, buffer_);
    
    cv::Mat debug;
    cv::cvtColor(temp, debug, cv::COLOR_GRAY2BGR);
    for (auto it = buffer_.begin(); it != buffer_.end(); ++it)
    {
        circle(debug, cv::Point(it->col, it->row), 1, cv::Scalar(0, 255, 0));
    }
    

    This solution does not take plateaus into account so it is not exactly the same as matlab's imregionalmax()

    0 讨论(0)
  • 2020-11-30 05:27

    To find more than just the global minimum and maximum try using this function from skimage:

    http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.peak_local_max

    You can parameterize the minimum distance between peaks, too. And more. To find minima, use negated values (take care of the array type though, 255-image could do the trick).

    0 讨论(0)
  • 2020-11-30 05:33

    Found a simple solution.

    In this example, if you are trying to find 2 results of a matchTemplate function with a minimum distance from each other.

        cv::Mat result;
        matchTemplate(search, target, result, CV_TM_SQDIFF_NORMED);
        float score1;
        cv::Point displacement1 = MinMax(result, score1);
        cv::circle(result, cv::Point(displacement1.x+result.cols/2 , displacement1.y+result.rows/2), 10, cv::Scalar(0), CV_FILLED, 8, 0);
        float score2;
        cv::Point displacement2 = MinMax(result, score2);
    

    where

    cv::Point MinMax(cv::Mat &result, float &score)
    {
        double minVal, maxVal;
        cv::Point  minLoc, maxLoc, matchLoc;
    
        minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
        matchLoc.x = minLoc.x - result.cols/2;
        matchLoc.y = minLoc.y - result.rows/2;
        return minVal;
    }
    

    The process is:

    1. Find global Minimum using minMaxLoc
    2. Draw a filled white circle around global minimum using min distance between minima as radius
    3. Find another minimum

    The the scores can be compared to each other to determine, for example, the certainty of the match,

    0 讨论(0)
  • 2020-11-30 05:37

    This is very fast method. It stored founded maxima in a vector of Points.

    vector <Point> GetLocalMaxima(const cv::Mat Src,int MatchingSize, int Threshold, int GaussKernel  )
    {  
      vector <Point> vMaxLoc(0); 
    
      if ((MatchingSize % 2 == 0) || (GaussKernel % 2 == 0)) // MatchingSize and GaussKernel have to be "odd" and > 0
      {
        return vMaxLoc;
      }
    
      vMaxLoc.reserve(100); // Reserve place for fast access 
      Mat ProcessImg = Src.clone();
      int W = Src.cols;
      int H = Src.rows;
      int SearchWidth  = W - MatchingSize;
      int SearchHeight = H - MatchingSize;
      int MatchingSquareCenter = MatchingSize/2;
    
      if(GaussKernel > 1) // If You need a smoothing
      {
        GaussianBlur(ProcessImg,ProcessImg,Size(GaussKernel,GaussKernel),0,0,4);
      }
      uchar* pProcess = (uchar *) ProcessImg.data; // The pointer to image Data 
    
      int Shift = MatchingSquareCenter * ( W + 1);
      int k = 0;
    
      for(int y=0; y < SearchHeight; ++y)
      { 
        int m = k + Shift;
        for(int x=0;x < SearchWidth ; ++x)
        {
          if (pProcess[m++] >= Threshold)
          {
            Point LocMax;
            Mat mROI(ProcessImg, Rect(x,y,MatchingSize,MatchingSize));
            minMaxLoc(mROI,NULL,NULL,NULL,&LocMax);
            if (LocMax.x == MatchingSquareCenter && LocMax.y == MatchingSquareCenter)
            { 
              vMaxLoc.push_back(Point( x+LocMax.x,y + LocMax.y )); 
              // imshow("W1",mROI);cvWaitKey(0); //For gebug              
            }
          }
        }
        k += W;
      }
      return vMaxLoc; 
    }
    
    0 讨论(0)
  • 2020-11-30 05:45

    A pixel is considered a local maximum if it is equal to the maximum value in a 'local' neighborhood. The function below captures this property in two lines of code.

    To deal with pixels on 'plateaus' (value equal to their neighborhood) one can use the local minimum property, since plateaus pixels are equal to their local minimum. The rest of the code filters out those pixels.

    void non_maxima_suppression(const cv::Mat& image, cv::Mat& mask, bool remove_plateaus) {
        // find pixels that are equal to the local neighborhood not maximum (including 'plateaus')
        cv::dilate(image, mask, cv::Mat());
        cv::compare(image, 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(image, non_plateau_mask, cv::Mat());
            cv::compare(image, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
            cv::bitwise_and(mask, non_plateau_mask, mask);
        }
    }
    
    0 讨论(0)
提交回复
热议问题