Domanda

Ho una serie di immagini e desidero effettuare una corrispondenza incrociata tra tutte e visualizzare i risultati utilizzando le trackbar utilizzando OpenCV 2.4.6 (pacchetto ROS Hydro).La parte di corrispondenza viene eseguita utilizzando un vettore di vettori di vettori di cv::DMatch-objects:

image[0] --- image[3] -------- image[8] ------ ...
   |             |                 |
   |         cv::DMatch-vect   cv::DMatch-vect
   |
image[1] --- ...
   |
image[2] --- ...
   |
  ...
   |
image[N] --- ...

Poiché omettiamo di abbinare un'immagine a se stessa (non ha senso farlo) e poiché un'immagine di query potrebbe non essere abbinata a tutto il resto, ogni set di immagini di treno abbinate per un'immagine di query potrebbe avere una dimensione diversa dal resto.Tieni presente che nel modo corretto in cui è implementato, in realtà abbino una coppia di immagini due volte, il che ovviamente non è ottimale (soprattutto perché ho utilizzato un matcher BruteForce con il controllo incrociato attivato, il che in pratica significa che abbino una coppia di immagini 4 volte! ) ma per ora è tutto.Per evitare di disegnare al volo coppie di immagini abbinate ho popolato un vettore di vettori di oggetti cv::Mat.Ogni cv::Mat rappresenta l'immagine della query corrente e alcune abbinato immagine del treno (la popola utilizzando cv::drawMatches()):

image[0] --- cv::Mat[0,3] ---- cv::Mat[0,8] ---- ...
   |
image[1] --- ...
   |
image[2] --- ...
   |
  ...
   |
image[N] --- ...

Nota:Nell'esempio sopra cv::Mat[0,3] sta per cv::Mat che memorizza il prodotto di cv::drawMatches() utilizzando image[0] e image[3].

Ecco le impostazioni della GUI:

  • Finestra principale:qui visualizzo l'immagine della query corrente.Usando una trackbar, chiamiamola TRACK_QUERY, scorro ogni immagine del mio set.
  • Finestra secondaria:qui visualizzo la coppia abbinata (query,train), dove la combinazione tra la posizione dello slider di TRACK_QUERY e la posizione dello slider di un'altra trackbar in questa finestra - chiamiamola TRACK_TRAIN - mi permette di scorrere tutto il cv::Mat -match-images per l'immagine della query corrente.

Il problema qui deriva dal fatto che ogni query può avere un numero variabile di immagini di treni corrispondenti.Il mio TRACK_TRAIN dovrebbe essere in grado di adattarsi al numero di immagini del treno corrispondenti, ovvero al numero di elementi in ciascun cv::Mat-vettore per l'immagine della query corrente.Purtroppo finora non sono riuscito a trovare un modo per farlo.cv::createTrackbar() richiede un parametro di conteggio, che da quello che vedo imposta il limite del cursore della trackbar e non può essere modificato in seguito.Correggimi se sbaglio perché è proprio questo che mi dà fastidio.Una possibile soluzione (meno elegante e che coinvolge vari controlli per evitare errori fuori intervallo) è quella di prendere la dimensione del set più grande di immagini di treni abbinate e usarla come limite per il mio TRACK_TRAIN.Vorrei evitare di farlo se possibile.Un'altra possibile soluzione prevede la creazione di una trackbar per immagine di query con l'intervallo di valori appropriato e lo scambio di ciascuna nelle mie finestre secondarie in base all'immagine di query selezionata.Per ora questo sembra essere il modo più semplice da percorrere, ma comporta un notevole sovraccarico delle trackbar, per non parlare del fatto che non ho sentito parlare di OpenCV che ti consente di nascondere i controlli della GUI.Ecco due esempi che potrebbero chiarire un po’ di più le cose:

Esempio 1:Nella finestra principale seleziono l'immagine 2 utilizzando TRACK_QUERY.Per questa immagine sono riuscito ad abbinare altre 5 immagini dal mio set.Diciamo che quelle sono le immagini 4, 10, 17, 18 e 20.La finestra secondaria si aggiorna automaticamente e mi mostra la corrispondenza tra l'immagine 2 e l'immagine 4 (la prima nel sottoinsieme delle immagini del treno abbinate).TRACK_TRAIN deve andare da 0 a 4.Muovendo lo slider in entrambe le direzioni mi permette di scorrere le immagini 4, 10, 17, 18 e 20 aggiornando ogni volta la finestra secondaria.

Esempio 2:Nella finestra principale seleziono l'immagine 7 utilizzando TRACK_QUERY.Per questa immagine sono riuscito ad abbinare altre 3 immagini dal mio set.Diciamo che quelle sono le immagini 0, 1, 11 e 19.La finestra secondaria si aggiorna automaticamente e mi mostra la corrispondenza tra l'immagine 2 e l'immagine 0 (la prima nel sottoinsieme delle immagini del treno abbinate).TRACK_TRAIN deve andare da 0 a 2.Muovendo lo slider in entrambe le direzioni mi permette di scorrere le immagini 0, 1, 1 e 19 aggiornando ogni volta la finestra secondaria.

Se avete domande non esitate a chiedere e cercherò di rispondere nel miglior modo possibile.Grazie in anticipo!

PS:Purtroppo il pacchetto ROS ha il minimo indispensabile di ciò che OpenCV può offrire.Nessuna integrazione Qt, nessun OpenMP, nessun OpenGL ecc.

È stato utile?

Soluzione

Dopo aver fatto qualche ulteriore ricerca sono abbastanza sicuro che al momento ciò non sia possibile.Ecco perché ho implementato la prima proposta che ho fornito nella mia domanda: utilizzare il vettore di corrispondenza con il maggior numero di corrispondenze per determinare una dimensione massima per la trackbar e quindi utilizzare alcuni controlli per evitare eccezioni fuori intervallo.Di seguito c'è una descrizione più o meno dettagliata di come funziona il tutto.Poiché la procedura di corrispondenza nel mio codice prevede alcuni controlli aggiuntivi che non riguardano il problema in questione, la salterò qui.Tieni presente che in un dato insieme di immagini che vogliamo abbinare, mi riferisco a un'immagine come immagine-oggetto quando quell'immagine (esempio:card) è attualmente abbinata a un'immagine di scena (esempio:un set di carte) - livello superiore del vettore di corrispondenze (vedi sotto) e uguale all'indice in immagini elaborate (vedi sotto).Trovo che la notazione treno/query in OpenCV sia alquanto confusa.Questa notazione di scena/oggetto è tratta da http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html.Puoi modificare o scambiare la notazione a tuo piacimento, ma assicurati di cambiarla ovunque di conseguenza, altrimenti potresti ottenere risultati strani.

// stores all the images that we want to cross-match
std::vector<cv::Mat> processedImages;
// stores keypoints for each image in processedImages
std::vector<std::vector<cv::Keypoint> > keypoints;
// stores descriptors for each image in processedImages 
std::vector<cv::Mat> descriptors;

// fill processedImages here (read images from files, convert to grayscale, undistort, resize etc.), extract keypoints, compute descriptors
// ...

// I use brute force matching since I also used ORB, which has binary descriptors and HAMMING_NORM is the way to go
cv::BFmatcher matcher;
// matches contains the match-vectors for each image matched to all other images in our set
// top level index matches.at(X) is equal to the image index in processedImages
// middle level index matches.at(X).at(Y) gives the match-vector for the Xth image and some other Yth from the set that is successfully matched to X
std::vector<std::vector<std::vector<cv::DMatch> > > matches;
// contains images that store visually all matched pairs
std::vector<std::vector<cv::Mat> > matchesDraw;

// fill all the vectors above with data here, don't forget about matchesDraw
// stores the highest count of matches for all pairs - I used simple exclusion by simply comparing the size() of the current std::vector<cv::DMatch> vector with the previous value of this variable
long int sceneWithMaxMatches = 0;
// ...

// after all is ready do some additional checking here in order to make sure the data is usable in our GUI. A trackbar for example requires AT LEAST 2 for its range since a range (0;0) doesn't make any sense
if(sceneWithMaxMatches < 2)
  return -1;

// in this window show the image gallery (scene-images); the user can scroll through all image using a trackbar
cv::namedWindow("Images", CV_GUI_EXPANDED | CV_WINDOW_AUTOSIZE);
// just a dummy to store the state of the trackbar 
int imagesTrackbarState = 0;
// create the first trackbar that the user uses to scroll through the scene-images
// IMPORTANT: use processedImages.size() - 1 since indexing in vectors is the same as in arrays - it starts from 0 and not reducing it by 1 will throw an out-of-range exception
cv::createTrackbar("Images:", "Images", &imagesTrackbarState, processedImages.size() - 1, on_imagesTrackbarCallback, NULL);
// in this window we show the matched object-images relative to the selected image in the "Images" window
cv::namedWindow("Matches for current image", CV_WINDOW_AUTOSIZE);
// yet another dummy to store the state of the trackbar in this new window
int imageMatchesTrackbarState = 0;
// IMPORTANT: again since sceneWithMaxMatches stores the SIZE of a vector we need to reduce it by 1 in order to be able to use it for the indexing later on
cv::createTrackbar("Matches:", "Matches for current image", &imageMatchesTrackbarState, sceneWithMaxMatches - 1, on_imageMatchesTrackbarCallback, NULL);

while(true)
{
  char key = cv::waitKey(20);
  if(key == 27)
    break;

  // from here on the magic begins
  // show the image gallery; use the position of the "Images:" trackbar to call the image at that position
  cv::imshow("Images", processedImages.at(cv::getTrackbarPos("Images:", "Images")));

  // store the index of the current scene-image by calling the position of the trackbar in the "Images:" window
  int currentSceneIndex = cv::getTrackbarPos("Images:", "Images");
  // we have to make sure that the match of the currently selected scene-image actually has something in it
  if(matches.at(currentSceneIndex).size())
  {
    // store the index of the current object-image that we have matched to the current scene-image in the "Images:" window
    int currentObjectIndex = cv::getTrackbarPos("Matches:", "Matches for current image");
    cv::imshow(
            "Matches for current image",
            matchesDraw.at(currentSceneIndex).at(currentObjectIndex < matchesDraw.at(currentSceneIndex).size() ? // is the current object index within the range of the matches for the current object and current scene
            currentObjectIndex : // yes, return the correct index
            matchesDraw.at(currentSceneIndex).size() - 1));  // if outside the range show the last matched pair!
  }
}

// do something else
// ...

La parte difficile è la trackbar nella seconda finestra responsabile dell'accesso alle immagini abbinate alla nostra immagine attualmente selezionata nella finestra "Immagini".Come ho spiegato sopra, ho impostato la trackbar "Corrispondenze:" nella finestra "Corrispondenze per l'immagine corrente" in modo che abbia un intervallo compreso tra 0 e (sceneWithMaxMatches-1).Tuttavia, non tutte le immagini hanno lo stesso numero di corrispondenze con il resto del set di immagini (si applica dieci volte se sono stati applicati filtri aggiuntivi per garantire corrispondenze affidabili, ad esempio sfruttando le proprietà dell'omografia, test del rapporto, controllo della distanza minima/massima, ecc.) .).Poiché non sono riuscito a trovare un modo per regolare dinamicamente l'intervallo della trackbar, avevo bisogno di una convalida dell'indice.Altrimenti per alcune immagini e le relative corrispondenze l'applicazione genererà un'eccezione fuori intervallo.Ciò è dovuto al semplice fatto che per alcune corrispondenze proviamo ad accedere a un vettore di corrispondenza con un indice maggiore della sua dimensione meno 1 perché cv::getTrackbarPos() arriva fino a (sceneWithMaxMatches - 1).Se la posizione della trackbar esce dall'intervallo per il vettore attualmente selezionato con corrispondenze, imposto semplicemente l'immagine matchDraw in "Corrispondenze per l'immagine corrente" all'ultima nel vettore.Qui sfrutto il fatto che l'indicizzazione non può scendere sotto lo zero così come la posizione della trackbar quindi non c'è bisogno di controllare questo ma solo quello che viene dopo la posizione iniziale 0.Se questo non è il tuo caso assicurati di controllare anche il limite inferiore e non solo quello superiore.

Spero che questo ti aiuti!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top