¿Alguien sabe cómo encontrar el máximo local en una escala de grises IPL_DEPTH_8U imagen usando OpenCV? HarrisCorner menciona algo como eso, pero realmente no soy interesado en las esquinas …
Gracias!

  • No la morfología de la Dilatación de la operación en OpenCV averiguar el máximo local en un 3×3 o definido por el usuario núcleo y el conjunto de los píxeles a este valor máximo? Por lo que este podría ser modificados a su propósito.
InformationsquelleAutor Durin | 2011-04-05

10 Comentarios

  1. -1

    Creo desea utilizar el

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

    función de la imagen

    • en realidad, en la que se busca el global. Prefiero local (regional) como de Matlab imregionmax() función.
    • Usted puede utilizar cvSetImageROI y cvResetImageROI llamadas a definir la subregión más de lo que usted está buscando. Entonces, fabrizio sugerencia funcionaría muy bien.
    • Antes de ejecutar esta función, considerar el desenfoque de la imagen si desea obtener picos locales.
    • En realidad no es tan fácil utilizar el global MinMaxLoc función para encontrar extremos locales en combinación con algunos retorno de la inversión. ¿Cómo se establece la subregión? En una ventana deslizante manera? MinMaxLoc siempre devolverá un mínimo y un máximo. Una frontera de píxeles en el retorno de la inversión podría ser un máximo global en el ROI, pero el siguiente píxel fuera el retorno de la inversión puede tener un valor mayor.
  2. 5

    Un píxel se considera un máximo local si es igual al valor máximo en un local de barrio. La función se muestra a continuación presenta esta propiedad en dos líneas de código.

    Para lidiar con los píxeles de ‘mesetas’ (valor igual a su barrio), se puede utilizar el mínimo local de la propiedad, desde las mesetas de píxeles es igual a su mínimo local. El resto del código en los filtros de los píxeles.

    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);
        }
    }
    
    • Este código da «conectado» de los resultados, lo cual es raro ya que estamos buscando los máximos locales; dos maxima no puede ser conectado, si usted me pregunta. Incluso si puedo aumentar el tamaño del núcleo.
    • Pensar en un ‘cresta’ de los máximos locales…
  3. 3

    Realidad, después de que he publicado el código anterior escribí un mejor y mucho más rápido ..
    El código anterior sufre incluso para una resolución de 640×480 imagen..
    Yo optimizado y ahora es muy muy rápido, incluso para 1600×1200 pic.
    Aquí está el código :

    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;
            }
        }
    }
    
    • siempre puedes editar tu post y aun si dos respuestas, usted puede publicar por separado.
    • Me acabo de dar cuenta de que 🙂 gracias por el dato.. pero, ¿es posible eliminar la anterior?
    • Un moderador puede eliminar. Usted puede marcarlo para que un moderador lo considere.
    • impresionante.. un millón de gracias..pero a pesar de que puede bandera de este uno de los otros post no tiene una opción de marca a continuación 🙁
    • ¿qué es SANITYCHECK?
  4. 3

    El siguiente listado es una función similar a la de Matlab «imregionalmax». Busca en la mayoría de los nLocMax los máximos locales por encima de umbral, donde la encontraron los máximos locales son, al menos, minDistBtwLocMax píxeles aparte. Devuelve el número real de los máximos locales encontrado. Observe que se utiliza OpenCV del minMaxLoc para encontrar máximos globales. Es «opencv-auto-contenida», excepto para el (fácil de implementar), la función de vdist, que calcula la (euclidiana) la distancia entre los puntos (r,c) y (fila,col).

    la entrada es un canal CV_32F de la matriz, y lugares es nLocMax (filas) por 2 (columnas) CV_32S de la matriz.

    HTML:

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

    • +1 por hacer una función con todas las opciones posibles, como la distancia entre max, no. de max, los valores de umbral etc. No he mirado en los cálculos de eficiencia aún. Va a dejar u saber si hay algún problema relacionado con esto.
    • Donde están «vdist» y «Point2DMake» de?
  5. 2

    La primera pregunta a responder sería lo «local» en su opinión. La respuesta bien puede ser una ventana cuadrada de (decir 3×3 o 5×5) o ventana circular de un radio determinado. Luego, puede escanear a través de toda la imagen con la ventana centrada en cada píxel, y escoger el valor más alto de la ventana.

    Ver este de cómo acceder a los valores de los píxeles en OpenCV.

    • +1: Gracias por el enlace.
    • ver mi comentario en respuesta. Este método no está funcionando. Considere la posibilidad de una imagen de 100×100 con greyvalue(x,y) = x+y. Sólo hay una máxima en [99,99]. Una ventana corrediza siempre encuentro un máximo local en la esquina inferior derecha. Su método es básicamente volver casi todos los píxeles como máximo local.
  6. 2

    Aquí es un simple truco. La idea es dilatar con un núcleo que contiene un agujero en el centro. Después de la dilatar la operación, cada píxel es reemplazado con el máximo de los vecinos (con un 5 por 5 barrios en este ejemplo), excluyendo del píxel original.

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

    Esto es muy rápido método. Se almacenan fundada maxima en un vector de
    Puntos.

    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; 
    }
    
    • sólo da negativo X y y
    • Aunque la idea es buena y rápida, el código no funciona para los elementos situados en los bordes inferior y derecho de la imagen. Esto es posiblemente debido a su pProcess[m++] no llegar a los bordes inferior y derecho, y si el umbral no ha sido activado, no va a dar un resultado, mientras que cerca de los bordes del umbral de hecho podría ser mayor, pero nunca va a desencadenar. Aquí la solución es aumentar la SearchWidth y searchHeight y, a continuación, a algunos de saneamiento en el rectángulo de recorte.
  8. 1

    Encontrado una solución simple.

    En este ejemplo, si usted está tratando de encontrar 2 resultados de un matchTemplate función con un mínimo de distancia el uno del otro.

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

    donde

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

    El proceso es el siguiente:

    1. Encontrar el Mínimo global utilizando minMaxLoc
    2. Dibujar un relleno con un círculo blanco alrededor mínimo global utilizando min distancia entre los mínimos como radio
    3. Encontrar otro mínimo

    El, las puntuaciones pueden ser comparados entre sí para determinar, por ejemplo, la certeza de que el partido,

  9. 0

    Usted puede ir a través de cada píxel y prueba si es un máximo local. Aquí es cómo iba a hacerlo.
    La entrada se asume que el tipo de 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());
                    }
    
                }
            }
        }
    
    }
    

    Para probar el código que usted puede probar esto:

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

    Esta solución no tomar las mesetas en cuenta por lo que no es exactamente el mismo que el de matlab imregionalmax()

Dejar respuesta

Please enter your comment!
Please enter your name here