Voglio identificare i mattoncini lego per la costruzione di un lego smistatore (io uso C++ con opencv). Ciò significa che devo distinguere tra oggetti che sembrano molto simili.distingue gli oggetti con opencv
I mattoni arrivano alla mia fotocamera individualmente su un trasportatore piatto. Ma potrebbero trovarsi in ogni modo possibile: a testa in giù, di lato o "normale".
Il mio approccio è quello di insegnare alla macchina di smistamento i mattoni fissandoli con la fotocamera in molte posizioni e rotazioni diverse. Le caratteristiche di ciascuna vista sono calcolate dal surf-algorythm.
void calculateFeatures(const cv::Mat& image,
std::vector<cv::KeyPoint>& keypoints,
cv::Mat& descriptors)
{
// detector == cv::SurfFeatureDetector(10)
detector->detect(image,keypoints);
// extractor == cv::SurfDescriptorExtractor()
extractor->compute(image,keypoints,descriptors);
}
Se c'è un mattone sconosciuta (il mattone che voglio ordinare) le sue caratteristiche anche ottenere calcolati e combinati con quelli noti. Per informazioni sulle funzionalità erroneamente abbinate ho procedere come descritto nel libro OpenCV 2 Cookbook:
con il matcher (= cv :: BFMatcher (cv :: NORM_L2)) i due vicini più prossimi in entrambe le direzioni vengono ricercati
matcher.knnMatch(descriptorsImage1, descriptorsImage2, matches1, 2); matcher.knnMatch(descriptorsImage2, descriptorsImage1, matches2, 2);
ho controllare il rapporto tra le distanze dei vicini più vicini trovati. Se le due distanze sono molto simili, è probabile che venga utilizzato un valore falso.
// loop for matches1 and matches2 for(iterator matchIterator over all matches) if(((*matchIterator)[0].distance/(*matchIterator)[1].distance) > 0.65) throw away
Infine sono accettate solo coppie di combinazioni simmetriche. Si tratta di corrispondenze in cui non solo n1 è il vicino più vicino a feature f1, ma anche f1 è il prossimo più vicino a n1.
for(iterator matchIterator1 over all matches) for(iterator matchIterator2 over all matches) if ((*matchIterator1)[0].queryIdx == (*matchIterator2)[0].trainIdx && (*matchIterator2)[0].queryIdx == (*matchIterator1)[0].trainIdx) // good Match
Ora solo le partite abbastanza buone rimangono. Per filtrare alcune partite più cattive, controlla quali corrispondenze corrispondono alla proiezione di img1 su img2 usando la matrice fondamentale.
std::vector<uchar> inliers(points1.size(),0);
cv::findFundamentalMat(
cv::Mat(points1),cv::Mat(points2), // matching points
inliers,
CV_FM_RANSAC,
3,
0.99);
std::vector<cv::DMatch> goodMatches
// extract the surviving (inliers) matches
std::vector<uchar>::const_iterator itIn= inliers.begin();
std::vector<cv::DMatch>::const_iterator itM= allMatches.begin();
// for all matches
for (;itIn!= inliers.end(); ++itIn, ++itM)
if (*itIn)
// it is a valid match
Il risultato è abbastanza buono. Ma in casi di estrema somiglianza si verificano ancora errori.
Nella figura sopra si vede che un mattone simile è riconosciuto bene.
Tuttavia nella seconda foto un mattone sbagliata è riconosciuto altrettanto bene.
Ora la domanda è come migliorare l'abbinamento.
ho avuto due idee diverse:
Le partite della seconda traccia immagine indietro alle caratteristiche davvero di montaggio, ma solo se il campo visivo è intensamente cambiato. Per riconoscere un mattone devo comunque confrontarlo in molte posizioni diverse (almeno come mostrato nella figura 3). Ciò significa che so che mi è consentito solo di cambiare minimamente il campo visivo. Le informazioni su come viene modificato intensamente il campo visivo dovrebbero essere nascoste nella matrice fondamentale. Come posso leggere da questa matrice fino a che punto è cambiata la posizione nella stanza?Soprattutto la rotazione e il forte ridimensionamento dovrebbero essere di interesse; se il mattone è annegato una volta più lontano sul lato sinistro, ciò non dovrebbe avere importanza.
seconda idea:
ho calcolato la matrice fondamentale su 2 immagini e filtrati caratteristiche che non si adattano le proiezioni - non ci dovrebbe essere un modo per fare la stessa cosa con tre o più immagini? (parola chiave Tensore trifocale). In questo modo la corrispondenza dovrebbe diventare più stabile. Ma non so nemmeno come farlo usando OpenCV né potrei trovare alcuna informazione su questo su google.