2015-04-24 13 views
6

Sto cercando di rilevare più di un quadrato (marker) a mia immagine mentre chiedo qui Detect Marker Position in 2D imageOpenCV - C++ a Java - Partita Template

C'è un ragazzo che mi ha mostrato una soluzione in C++, eccolo :

#include <iostream> 

#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 


//See: http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html 
//See: http://answers.opencv.org/question/60382/detect-markers-position-in-2d-images/ 
int main() { 
    cv::Mat img, templateImg, result; 
    cv::VideoCapture capture("http://answers.opencv.org/upfiles/14297307634571599.png"); 
    if(capture.isOpened()) { 
    capture >> img; 
    } else { 
    return -1; 
    } 

    capture = cv::VideoCapture("http://answers.opencv.org/upfiles/14297308125543022.png"); 
    if(capture.isOpened()) { 
    capture >> templateImg; 
    } else { 
    return -1; 
    } 

    /// Reduce the size of the image to display it on my screen 
    cv::resize(img, img, cv::Size(), 0.5, 0.5); 
    /// Reduce the size of the template image 
    /// (first to fit the size used to create the image test, second to fit the size of the reduced image) 
    cv::resize(templateImg, templateImg, cv::Size(), 0.25, 0.25); 

    cv::Mat img_display; 
    img.copyTo(img_display); 

    // Create the result matrix 
    int result_cols = img.cols - templateImg.cols + 1; 
    int result_rows = img.rows - templateImg.rows + 1; 

    result.create(result_rows, result_cols, CV_32FC1); 

    /// Do the Matching and Normalize 
    cv::matchTemplate(img, templateImg, result, CV_TM_CCORR_NORMED); 
    cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 

    /// Localizing the best match with minMaxLoc 
    double minVal; double maxVal; cv::Point minLoc; cv::Point maxLoc; 
    cv::Point matchLoc; 

    for(;;) { 
    cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat()); 
    matchLoc = maxLoc; 
    std::cout << "Max correlation=" << maxVal << std::endl; 
    if(maxVal < 0.8) { 
     break; 
    } 

    /// Show me what you got 
    cv::rectangle(img_display, matchLoc, cv::Point(matchLoc.x + templateImg.cols , matchLoc.y + templateImg.rows), 
     cv::Scalar::all(0), 2, 8, 0); 
    cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2), 
     cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2), cv::Scalar::all(0), 2, 8, 0); 

    cv::imshow("result", result); 
    cv::waitKey(0); 

    /// Fill the detected location with a rectangle of zero 
    cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2), 
     cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2), cv::Scalar::all(0), -1); 
    } while (maxVal > 0.9); 


    cv::imshow("result", result); 
    cv::imshow("img_display", img_display); 
    cv::waitKey(0); 

    return 0; 
} 

Il ciclo for è responsabile di trovare più di un marcatore e rilevarlo, sto cercando di adattarlo al mio codice Java e sto ottenendo un ciclo infinito qui è il mio codice:

public void run(String inFile, String templateFile, String outFile, int match_method) { 
     System.out.println("\nRunning Template Matching"); 


    Mat img = Highgui.imread(inFile); 
    Mat templ = Highgui.imread(templateFile); 

    ///Create the result matrix 
    int result_cols = img.cols() - templ.cols() + 1; 
    int result_rows = img.rows() - templ.rows() + 1; 
    Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1); 

    ///Do the Matching and Normalize 
    Imgproc.matchTemplate(img, templ, result, match_method); 
    Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat()); 

    Point matchLoc; 
    Point maxLoc; 
    Point minLoc; 

    MinMaxLocResult mmr; 

    boolean iterate = true; 
    while(iterate){ 

    ///Localizing the best match with minMaxLoc 
    mmr = Core.minMaxLoc(result); 
    matchLoc = mmr.maxLoc; 


    if(mmr.maxVal < 0.8) 
    { 
     iterate = false; 
    } 



    ///Show me what you got 
    Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(), 
      matchLoc.y + templ.rows()), new Scalar(0, 255, 0)); 

    } 

    // Save the visualized detection. 
    System.out.println("Writing "+ outFile); 
    Highgui.imwrite(outFile, img); 

} 

I n Nota che la funzione minMaxLoc ha più argomenti in C++ che in java, forse questo è il problema? Perché non riesco a ottenere lo stesso comportamento in java qualcuno può aiutarmi?

Grazie mille in anticipo

risposta

3

Come diceva cyriel, Hai dimenticato di riempire gli zeri per la posizione massima e quindi hai ottenuto il ciclo infinito.Può essere ha dimenticato di spiegare che,

for each iteration 
    find the max location 
    check if max value is greater than desired threshold 
    if true 
    show me what is max 
    else 
    break // not found anything that matches 
    make the existing max to be zero and continue to search for other max// you forgot this and hence infinite loop 
    end 

Per un quadro più chiaro del problema, è possibile commentare le seguenti righe nel codice C++ ed eseguirlo, si verificano problemi simili. (Qui cv :: Scalar :: tutti (0), - 1 args dice riempire esistente max/trovato regione con 0 e continuare)

// Fill the detected location with a rectangle of zero 
    cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2, matchLoc.y - templateImg.rows/2), 
     cv::Point(matchLoc.x + templateImg.cols/2, matchLoc.y + templateImg.rows/2), cv::Scalar::all(0), -1); 

Speranza che aiuta.

+0

Ha aiutato molto, ho cambiato il codice che avevo in java e ora funziona, eccolo: http://pastebin.com/HXP9JaMN Grazie mille! ;) – TiagoM

+0

Ho notato che la corrispondenza del modello non funziona per rilevare i miei quadrati neri, avrò bisogno di andare con la soluzione @RobAu ... – TiagoM

+1

Va bene. La tua domanda sembra più volta a risolvere il problema del loop infinito con il titolo Opencv C++ in Java - Template match. Puoi cercare qui in StackOverflow per ulteriori domande relative alla corrispondenza del modello o alla ricerca di quadrati o oggetti nelle immagini. – sriram

1

Hai dimenticato di disegnare il secondo rettangolo. Codice originale:

cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2), 
    cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2), cv::Scalar::all(0), 2, 8, 0); 

... 

/// Fill the detected location with a rectangle of zero 
cv::rectangle(result, cv::Point(matchLoc.x - templateImg.cols/2 , matchLoc.y - templateImg.rows/2), 
    cv::Point(matchLoc.x + templateImg.cols/2 , matchLoc.y + templateImg.rows/2), cv::Scalar::all(0), -1); 

comunque nel codice c'è solo questo:

Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(), 
     matchLoc.y + templ.rows()), new Scalar(0, 255, 0)); 

La seconda parte del codice originale più probabile è cruciale - trae riempito, non solo una forma come prima linea.

Btw questa riga Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(), matchLoc.y + templ.rows()), new Scalar(0, 255, 0)); probabilmente è anche errata - 1) È necessario disegnare il rettangolo su result mat, non su img mat. 2) Nel codice originale c'è Core.rectangle(img, matchLoc, new Point(matchLoc.x + templ.cols(), matchLoc.y + templ.rows()), new Scalar(0, 255, 0)); e nel tuo codice new Point(matchLoc.x + templ.cols(), matchLoc.y + templ.rows()). Sei sicuro che stia bene?

+0

No il problema non è il secondo rettangolo, in realtà non ne ho bisogno. Il problema è nel mentre (iterazione) che non finisce, sto ricevendo un ciclo infinito, credo. Ho provato a copiare il ciclo dal codice C++ ma forse è rimasto qualcosa, sai cosa? – TiagoM

1

Anche se potrebbe essere utile, non è necessario OpenCV/JavaCV per questo compito relativamente facile.

sostanza, si vuole per trovare le regioni in voi immagine che sono:

a: all black 
b: square 
c: a percentage of size of the total image 

In primo luogo, la soglia l'immagine in modo che tutti i pixel sono o bianco o nero.

Il mio approccio sarebbe quello di trovare i componenti connessi mediante la scansione dell'immagine pixel per pixel fino a raggiungere un pixel nero. Quindi riempire di riempimento finché non si raccolgono tutti i pixel neri. Contrassegnali (colorali in modo diverso) e memorizzali in una struttura (elenco di punti) e ripeti fino a raggiungere l'ultimo pixel dell'immagine.

Per ogni componente:

  • determinare il riquadro di delimitazione (min e max valori xey).
  • Calcolare la dimensione della casella e determinare se è piccola/grande abbastanza
  • Calcolare la percentuale di pixel corrispondenti in quella casella. Se è vicino al 100%, hai una forma quadrata.

È possibile riportare le caselle di delimitazione corrispondenti nell'immagine originale.

+0

Ho notato che la corrispondenza del modello non può rilevare i miei quadrati neri, ho bisogno di usare questa soluzione, ma non l'ho capita molto bene ... intendi controllare ogni pixel dell'immagine? non ci vorrà molto tempo? Puoi darmi un po 'di codice? Grazie mille. Ho già la soglia immagine, tutti i pixel sono neri o bianchi – TiagoM

+0

Non ho intenzione di codificare la tua soluzione, usare google per trovare gli algoritmi. Una volta ho scritto qualcosa del genere su un Pentium III e sono ancora in grado di fare 30fps. Dipende principalmente dalla risoluzione dell'immagine. – RobAu

+0

Okay, spiegami una cosa: quando comincio a riempire il primo pixel nero, il riempimento funzionerà solo con i pixel neri collegati, giusto? stesso componente? quindi posso dividere tutte le componenti nere sull'immagine in una lista? – TiagoM