使用OpenCV在灰度图像中查找局部最大值
image
image-processing
opencv
5
0

有谁知道如何使用OpenCV在IPL_DEPTH_8U灰度图像中找到局部最大值? HarrisCorner提到了类似的内容,但实际上我对弯角不感兴趣……谢谢!

参考资料:
Stack Overflow
收藏
评论
共 5 个回答
高赞 时间 活跃

您要回答的第一个问题是什么是“本地”。答案很可能是方形窗口(例如3x3或5x5)或一定半径的圆形窗口。然后,您可以扫描整个图像,并且窗口以每个像素为中心,并在窗口中选取最大值。

对OpenCV中如何存取像素值。

收藏
评论

下面的清单是类似于Matlab的“ imregionalmax”的函数。它最多寻找 阈值以上的nLocMax局部最大值,其中找到的局部最大值至少相距minDistBtwLocMax像素。它返回找到的局部最大值的实际数量。请注意,它使用OpenCV的minMaxLoc查找全局最大值。它是“ opencv自包含的”,除了(易于实现的)函数vdist ,该函数计算点(r,c)和(row,col)之间的(欧几里得)距离。

输入是单通道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;
}
收藏
评论

实际上,在我发布上面的代码之后,我写了一个更好,非常非常快的代码。.即使对于640x480的图片,上面的代码也受苦。这是代码:

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;
        }
    }
}
收藏
评论

如果像素等于“局部”邻域中的最大值,则认为该像素为局部最大值。下面的函数用两行代码捕获了此属性。

为了处理“高原”上的像素(值等于其邻域),可以使用局部最小值属性,因为高原像素等于其局部最小值。其余代码将滤除这些像素。

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);
    }
}
收藏
评论

这是一个简单的把戏。这个想法是用一个在中心包含一个孔的内核进行扩张。进行扩张操作后,每个像素都将替换为其最大的邻居(在此示例中使用5 x 5邻域), 而不包括原始像素。

Mat1b kernelLM(Size(5, 5), 1u);
kernelLM.at<uchar>(2, 2) = 0u;
Mat imageLM;
dilate(image, imageLM, kernelLM);
Mat1b localMaxima = (image > imageLM);
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号