webentwicklung-frage-antwort-db.com.de

Finden Sie lokale Maximalwerte in Graustufenbild mit OpenCV

Weiß jemand, wie man mit OpenCV die lokalen Maxima in einem Graustufen-IPL_DEPTH_8U-Bild findet? HarrisCorner erwähnt so etwas, aber ich interessiere mich eigentlich nicht für Ecken ... Danke!

17
Durin

Ich denke du willst das benutzen

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

funktion auf Ihrem Bild

1
fabrizioM

Ein Pixel wird als lokales Maximum betrachtet, wenn es dem Maximalwert in einer lokalen Umgebung entspricht. Die Funktion unten erfasst diese Eigenschaft in zwei Codezeilen.

Um Pixel auf "Plateaus" (Wert gleich ihrer Nachbarschaft) zu behandeln, können Sie die lokale Minimum-Eigenschaft verwenden, da die Pixel des Plateaus ihrem lokalen Minimum entsprechen. Der Rest des Codes filtert diese Pixel heraus.

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
killogre

Die folgende Auflistung ist eine Funktion, die Matlabs "imregionalmax" ähnelt. Es sieht höchstens so aus nLocMax lokale Maxima oben schwelle, wo die gefundenen lokalen Maxima mindestens sind minDistBtwLocMax Pixel voneinander entfernt. Es gibt die tatsächliche Anzahl der gefundenen lokalen Maxima zurück. Beachten Sie, dass es OpenCVs verwendet minMaxLoc um globale Maxima zu finden. Abgesehen von der (einfach zu implementierenden) Funktion ist es "opencv-in sich abgeschlossen" vdist, die den (euklidischen) Abstand zwischen den Punkten (r, c) und (Reihe, Spalte) berechnet.

eingang ist eine CV_32F-Matrix mit einem Kanal und standorte ist nLocMax (Zeilen) durch 2 (Spalten) CV_32S-Matrix.

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

3
Marcelo

Nachdem ich oben den Code gepostet hatte, schrieb ich einen besseren und sehr schnelleren Code. Der obige Code leidet sogar für ein 640x480-Bild. Ich habe es optimiert und jetzt ist es auch sehr schnell für 1600x1200 pic. Hier ist der Code:

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;
        }
    }
}
3
Doga Siyli

Die erste zu beantwortende Frage wäre, was Ihrer Meinung nach "lokal" ist. Die Antwort kann ein quadratisches Fenster (beispielsweise 3x3 oder 5x5) oder ein kreisförmiges Fenster mit einem bestimmten Radius sein. Sie können dann das gesamte Bild mit dem Fenster um jedes Pixel scannen und den höchsten Wert im Fenster auswählen.

Unter this erfahren Sie, wie Sie auf Pixelwerte in OpenCV zugreifen können.

2
peakxu

Eine einfache Lösung gefunden.

Wenn Sie in diesem Beispiel versuchen, zwei Ergebnisse einer MatchTemplate-Funktion mit einem Mindestabstand voneinander zu finden.

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

woher

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

Der Prozess ist:

  1. Finden Sie das globale Minimum mit minMaxLoc
  2. Zeichnen Sie einen gefüllten weißen Kreis um das globale Minimum und verwenden Sie den Mindestabstand zwischen den Minima als Radius
  3. Finden Sie ein anderes Minimum

Die Bewertungen können miteinander verglichen werden, um beispielsweise die Sicherheit des Spiels zu bestimmen.

1
Mich

Hier ist ein einfacher Trick. Die Idee ist, sich mit einem Kern zu erweitern, der ein Loch in der Mitte enthält. Nach der Dilatationsoperation wird jedes Pixel durch das Maximum seiner Nachbarn ersetzt (in diesem Beispiel eine 5 x 5-Nachbarschaft), ausschließlich das ursprüngliche Pixel. 

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

Um mehr als nur das globale Minimum und Maximum zu finden, versuchen Sie es mit dieser Funktion von skimage:

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

Sie können auch den Mindestabstand zwischen den Peaks parametrieren. Und mehr. Um Minima zu finden, verwenden Sie negierte Werte (achten Sie jedoch auf den Array-Typ, 255-image könnte den Trick ausführen).

0
DomTomCat

Dies ist eine sehr schnelle Methode. Es wurden die begründeten Maxima in einem Vektor von Punkten gespeichert.

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
Dasdranagon

Sie können jedes Pixel durchgehen und testen, ob es sich um ein lokales Maxima handelt. So würde ich es machen: Als Eingabe wird angenommen, dass der Typ CV_32FC1 ist

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

            }
        }
    }

}

Zum Testen des Codes können Sie Folgendes versuchen:

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

Diese Lösung berücksichtigt keine Plateaus und ist daher nicht genau dasselbe wie der imregionalmax von matlab ().

0
Yonatan Simson