使用OpenCV在灰度图像中找到局部极大值。

时间:2022-08-22 13:21:20

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 interested in corners ... Thanks!

是否有人知道如何使用OpenCV在灰度IPL_DEPTH_8U图像中找到本地最大值?HarrisCorner提到过类似的事情,但我实际上对角落不感兴趣……谢谢!

9 个解决方案

#1


2  

I think you want to use the

我认为你想用。

MinMaxLoc(arr, mask=NULL)-> (minVal, maxVal, minLoc, maxLoc)
Finds global minimum and maximum in array or subarray

function on you image

函数在图像

#2


5  

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.

要处理“plateaus”(相当于其邻近区域的值)上的像素,可以使用本地最小属性,因为plateaus像素等于它们的本地最小值。其余的代码过滤掉这些像素。

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

#3


3  

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.

第一个要回答的问题是,你认为什么是“地方”。答案很可能是一个正方形的窗口(比如3x3或5x5)或某个半径的圆形窗口。然后,您可以通过以每个像素为中心的窗口来扫描整个图像,并在窗口中选择最高的值。

See this for how to access pixel values in OpenCV.

在OpenCV中查看如何访问像素值。

#4


3  

Actually after I posted the code above I wrote a better and very very faster one .. The code above suffers even for a 640x480 picture.. I optimized it and now it is very very fast even for 1600x1200 pic. Here is the code :

实际上,在我发布了上面的代码之后,我写了一个更好更快的代码。上面的代码甚至有640x480的图片。我对它进行了优化,现在它的速度非常快,甚至是1600x1200像素。下面是代码:

void localMaxima(cv::Mat src,cv::Mat &dst,int squareSize)
{
if (squareSize==0)
{
    dst = src.clone();
    return;
}

Mat m0;
dst = src.clone();
Point maxLoc(0,0);

//1.Be sure to have at least 3x3 for at least looking at 1 pixel close neighbours
//  Also the window must be <odd>x<odd>
SANITYCHECK(squareSize,3,1);
int sqrCenter = (squareSize-1)/2;

//2.Create the localWindow mask to get things done faster
//  When we find a local maxima we will multiply the subwindow with this MASK
//  So that we will not search for those 0 values again and again
Mat localWindowMask = Mat::zeros(Size(squareSize,squareSize),CV_8U);//boolean
localWindowMask.at<unsigned char>(sqrCenter,sqrCenter)=1;

//3.Find the threshold value to threshold the image
    //this function here returns the peak of histogram of picture
    //the picture is a thresholded picture it will have a lot of zero values in it
    //so that the second boolean variable says :
    //  (boolean) ? "return peak even if it is at 0" : "return peak discarding 0"
int thrshld =  maxUsedValInHistogramData(dst,false);
threshold(dst,m0,thrshld,1,THRESH_BINARY);

//4.Now delete all thresholded values from picture
dst = dst.mul(m0);

//put the src in the middle of the big array
for (int row=sqrCenter;row<dst.size().height-sqrCenter;row++)
    for (int col=sqrCenter;col<dst.size().width-sqrCenter;col++)
    {
        //1.if the value is zero it can not be a local maxima
        if (dst.at<unsigned char>(row,col)==0)
            continue;
        //2.the value at (row,col) is not 0 so it can be a local maxima point
        m0 =  dst.colRange(col-sqrCenter,col+sqrCenter+1).rowRange(row-sqrCenter,row+sqrCenter+1);
        minMaxLoc(m0,NULL,NULL,NULL,&maxLoc);
        //if the maximum location of this subWindow is at center
        //it means we found the local maxima
        //so we should delete the surrounding values which lies in the subWindow area
        //hence we will not try to find if a point is at localMaxima when already found a neighbour was
        if ((maxLoc.x==sqrCenter)&&(maxLoc.y==sqrCenter))
        {
            m0 = m0.mul(localWindowMask);
                            //we can skip the values that we already made 0 by the above function
            col+=sqrCenter;
        }
    }
}

#5


2  

The following listing is a function similar to Matlab's "imregionalmax". It looks for at most nLocMax local maxima above threshold, where the found local maxima are at least minDistBtwLocMax pixels apart. It returns the actual number of local maxima found. Notice that it uses OpenCV's minMaxLoc to find global maxima. It is "opencv-self-contained" except for the (easy to implement) function vdist, which computes the (euclidian) distance between points (r,c) and (row,col).

下面的清单是一个类似于Matlab的“imalmax”的函数。它在大多数nLocMax局部最大值的阈值上寻找,在这里,发现的局部极大值至少是最小的。它返回找到的本地maxima的实际数量。注意,它使用OpenCV的minMaxLoc找到全局最大值。它是“opencv-自足”的,除了(易于实现)函数vdist,它计算点(r,c)和(行,col)之间的(euclidian)距离。

input is one-channel CV_32F matrix, and locations is nLocMax (rows) by 2 (columns) CV_32S matrix.

输入是一个通道CV_32F矩阵,位置是nLocMax(行)2(列)CV_32S矩阵。

int imregionalmax(Mat input, int nLocMax, float threshold, float minDistBtwLocMax, Mat locations)
{
    Mat scratch = input.clone();
    int nFoundLocMax = 0;
    for (int i = 0; i < nLocMax; i++) {
        Point location;
        double maxVal;
        minMaxLoc(scratch, NULL, &maxVal, NULL, &location);
        if (maxVal > threshold) {
            nFoundLocMax += 1;
            int row = location.y;
            int col = location.x;
            locations.at<int>(i,0) = row;
            locations.at<int>(i,1) = col;
            int r0 = (row-minDistBtwLocMax > -1 ? row-minDistBtwLocMax : 0);
            int r1 = (row+minDistBtwLocMax < scratch.rows ? row+minDistBtwLocMax : scratch.rows-1);
            int c0 = (col-minDistBtwLocMax > -1 ? col-minDistBtwLocMax : 0);
            int c1 = (col+minDistBtwLocMax < scratch.cols ? col+minDistBtwLocMax : scratch.cols-1);
            for (int r = r0; r <= r1; r++) {
                for (int c = c0; c <= c1; c++) {
                    if (vdist(Point2DMake(r, c),Point2DMake(row, col)) <= minDistBtwLocMax) {
                        scratch.at<float>(r,c) = 0.0;
                    }
                }
            }
        } else {
            break;
        }
    }
    return nFoundLocMax;
}

#6


1  

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.

在本例中,如果您试图找到一个匹配模板函数的2个结果,那么它们之间的距离最小。

    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. 使用minMaxLoc查找全局最小值。
  3. Draw a filled white circle around global minimum using min distance between minima as radius
  4. 在最小值与最小值之间绘制一个填充的白色圆。
  5. Find another minimum
  6. 找到另一个最低

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

分数可以相互比较来决定,例如,比赛的确定性,

#7


1  

Here's a simple trick. The idea is to dilate with a kernel that contains a hole in the center. After the dilate operation, each pixel is replaced with the maximum of it's neighbors (using a 5 by 5 neighborhood in this example), excluding the original pixel.

这是一个简单的技巧。这个想法是用一个包含一个中心孔的核来扩张。在dilate操作之后,每个像素被替换为它的最大邻居(在本例中使用一个5×5的邻域),不包括原来的像素。

Mat1b kernelLM(Size(5, 5), 1u);
kernelLM.at<uchar>(2, 2) = 0u;
Mat imageLM;
dilate(image, imageLM, kernelLM);
Mat1b localMaxima = (image > imageLM);

#8


0  

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

#9


0  

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

您可以检查每个像素并测试它是否是本地maxima。下面是我的做法。输入被假定为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()

这个解决方案没有考虑到plateaus,所以它和matlab的imalmax()不完全一样

#1


2  

I think you want to use the

我认为你想用。

MinMaxLoc(arr, mask=NULL)-> (minVal, maxVal, minLoc, maxLoc)
Finds global minimum and maximum in array or subarray

function on you image

函数在图像

#2


5  

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.

要处理“plateaus”(相当于其邻近区域的值)上的像素,可以使用本地最小属性,因为plateaus像素等于它们的本地最小值。其余的代码过滤掉这些像素。

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

#3


3  

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.

第一个要回答的问题是,你认为什么是“地方”。答案很可能是一个正方形的窗口(比如3x3或5x5)或某个半径的圆形窗口。然后,您可以通过以每个像素为中心的窗口来扫描整个图像,并在窗口中选择最高的值。

See this for how to access pixel values in OpenCV.

在OpenCV中查看如何访问像素值。

#4


3  

Actually after I posted the code above I wrote a better and very very faster one .. The code above suffers even for a 640x480 picture.. I optimized it and now it is very very fast even for 1600x1200 pic. Here is the code :

实际上,在我发布了上面的代码之后,我写了一个更好更快的代码。上面的代码甚至有640x480的图片。我对它进行了优化,现在它的速度非常快,甚至是1600x1200像素。下面是代码:

void localMaxima(cv::Mat src,cv::Mat &dst,int squareSize)
{
if (squareSize==0)
{
    dst = src.clone();
    return;
}

Mat m0;
dst = src.clone();
Point maxLoc(0,0);

//1.Be sure to have at least 3x3 for at least looking at 1 pixel close neighbours
//  Also the window must be <odd>x<odd>
SANITYCHECK(squareSize,3,1);
int sqrCenter = (squareSize-1)/2;

//2.Create the localWindow mask to get things done faster
//  When we find a local maxima we will multiply the subwindow with this MASK
//  So that we will not search for those 0 values again and again
Mat localWindowMask = Mat::zeros(Size(squareSize,squareSize),CV_8U);//boolean
localWindowMask.at<unsigned char>(sqrCenter,sqrCenter)=1;

//3.Find the threshold value to threshold the image
    //this function here returns the peak of histogram of picture
    //the picture is a thresholded picture it will have a lot of zero values in it
    //so that the second boolean variable says :
    //  (boolean) ? "return peak even if it is at 0" : "return peak discarding 0"
int thrshld =  maxUsedValInHistogramData(dst,false);
threshold(dst,m0,thrshld,1,THRESH_BINARY);

//4.Now delete all thresholded values from picture
dst = dst.mul(m0);

//put the src in the middle of the big array
for (int row=sqrCenter;row<dst.size().height-sqrCenter;row++)
    for (int col=sqrCenter;col<dst.size().width-sqrCenter;col++)
    {
        //1.if the value is zero it can not be a local maxima
        if (dst.at<unsigned char>(row,col)==0)
            continue;
        //2.the value at (row,col) is not 0 so it can be a local maxima point
        m0 =  dst.colRange(col-sqrCenter,col+sqrCenter+1).rowRange(row-sqrCenter,row+sqrCenter+1);
        minMaxLoc(m0,NULL,NULL,NULL,&maxLoc);
        //if the maximum location of this subWindow is at center
        //it means we found the local maxima
        //so we should delete the surrounding values which lies in the subWindow area
        //hence we will not try to find if a point is at localMaxima when already found a neighbour was
        if ((maxLoc.x==sqrCenter)&&(maxLoc.y==sqrCenter))
        {
            m0 = m0.mul(localWindowMask);
                            //we can skip the values that we already made 0 by the above function
            col+=sqrCenter;
        }
    }
}

#5


2  

The following listing is a function similar to Matlab's "imregionalmax". It looks for at most nLocMax local maxima above threshold, where the found local maxima are at least minDistBtwLocMax pixels apart. It returns the actual number of local maxima found. Notice that it uses OpenCV's minMaxLoc to find global maxima. It is "opencv-self-contained" except for the (easy to implement) function vdist, which computes the (euclidian) distance between points (r,c) and (row,col).

下面的清单是一个类似于Matlab的“imalmax”的函数。它在大多数nLocMax局部最大值的阈值上寻找,在这里,发现的局部极大值至少是最小的。它返回找到的本地maxima的实际数量。注意,它使用OpenCV的minMaxLoc找到全局最大值。它是“opencv-自足”的,除了(易于实现)函数vdist,它计算点(r,c)和(行,col)之间的(euclidian)距离。

input is one-channel CV_32F matrix, and locations is nLocMax (rows) by 2 (columns) CV_32S matrix.

输入是一个通道CV_32F矩阵,位置是nLocMax(行)2(列)CV_32S矩阵。

int imregionalmax(Mat input, int nLocMax, float threshold, float minDistBtwLocMax, Mat locations)
{
    Mat scratch = input.clone();
    int nFoundLocMax = 0;
    for (int i = 0; i < nLocMax; i++) {
        Point location;
        double maxVal;
        minMaxLoc(scratch, NULL, &maxVal, NULL, &location);
        if (maxVal > threshold) {
            nFoundLocMax += 1;
            int row = location.y;
            int col = location.x;
            locations.at<int>(i,0) = row;
            locations.at<int>(i,1) = col;
            int r0 = (row-minDistBtwLocMax > -1 ? row-minDistBtwLocMax : 0);
            int r1 = (row+minDistBtwLocMax < scratch.rows ? row+minDistBtwLocMax : scratch.rows-1);
            int c0 = (col-minDistBtwLocMax > -1 ? col-minDistBtwLocMax : 0);
            int c1 = (col+minDistBtwLocMax < scratch.cols ? col+minDistBtwLocMax : scratch.cols-1);
            for (int r = r0; r <= r1; r++) {
                for (int c = c0; c <= c1; c++) {
                    if (vdist(Point2DMake(r, c),Point2DMake(row, col)) <= minDistBtwLocMax) {
                        scratch.at<float>(r,c) = 0.0;
                    }
                }
            }
        } else {
            break;
        }
    }
    return nFoundLocMax;
}

#6


1  

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.

在本例中,如果您试图找到一个匹配模板函数的2个结果,那么它们之间的距离最小。

    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. 使用minMaxLoc查找全局最小值。
  3. Draw a filled white circle around global minimum using min distance between minima as radius
  4. 在最小值与最小值之间绘制一个填充的白色圆。
  5. Find another minimum
  6. 找到另一个最低

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

分数可以相互比较来决定,例如,比赛的确定性,

#7


1  

Here's a simple trick. The idea is to dilate with a kernel that contains a hole in the center. After the dilate operation, each pixel is replaced with the maximum of it's neighbors (using a 5 by 5 neighborhood in this example), excluding the original pixel.

这是一个简单的技巧。这个想法是用一个包含一个中心孔的核来扩张。在dilate操作之后,每个像素被替换为它的最大邻居(在本例中使用一个5×5的邻域),不包括原来的像素。

Mat1b kernelLM(Size(5, 5), 1u);
kernelLM.at<uchar>(2, 2) = 0u;
Mat imageLM;
dilate(image, imageLM, kernelLM);
Mat1b localMaxima = (image > imageLM);

#8


0  

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

#9


0  

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

您可以检查每个像素并测试它是否是本地maxima。下面是我的做法。输入被假定为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()

这个解决方案没有考虑到plateaus,所以它和matlab的imalmax()不完全一样