2014-11-11 5 views
6

Próbuję dopasować 2 przeciwległe obrazy za pomocą deskryptora OpenCV bez powodzenia. Obrazy są następujące: http://i61.tinypic.com/28whu0g.jpg (od lewej do prawej) i http://i61.tinypic.com/x35vte.jpg (od prawej do lewej).OpenCV - Java - brak zgodności z 2 przeciwnymi obrazami za pomocą DescriptorMatcher

Mój kod jest podobny do wielu przykładów, które widziałem w StackOverflow i Internecie, ale wciąż nie dorówna mi.

 String firstImageSourcePath = "RTL_IMAGE_PATH"; 
     String secondImageSourcePath = "LTR_IMAGE_PATH"; 

     Mat firstImageSrcImgMat = Highgui.imread(firstImageSourcePath); 
     Mat secondImageSrcImgMat = Highgui.imread(firstImageSourcePath); 

     if (firstImageSrcImgMat.empty() || secondImageSrcImgMat.empty()) { 
      System.out.println("Failed to load images"); 
      return; 
     } 

     System.out.println("Loaded image at " + firstImageSourcePath + " and " + secondImageSourcePath); 

     FeatureDetector featureDetector = FeatureDetector.create(FeatureDetector.BRISK); 

     MatOfKeyPoint firstImgMatOfKeyPoints = new MatOfKeyPoint(); 
     MatOfKeyPoint secondImgMatOfKeyPoints = new MatOfKeyPoint(); 

     featureDetector.detect(firstImageSrcImgMat, firstImgMatOfKeyPoints); 
     featureDetector.detect(secondImageSrcImgMat, secondImgMatOfKeyPoints); 

     System.out.println("Detected " + firstImgMatOfKeyPoints.size() + " and " + secondImgMatOfKeyPoints + " blobs in the images"); 

     List<KeyPoint> firstImgKeyPoints = firstImgMatOfKeyPoints.toList(); 
     List<KeyPoint> secondImgKeyPoints = secondImgMatOfKeyPoints.toList(); 

     System.out.println("First Image key points: " + firstImgKeyPoints); 
     System.out.println("Second Image key points: " + secondImgKeyPoints); 

     Mat firstImgDescriptors = new Mat(); 
     Mat secondImgDescriptors = new Mat(); 

     DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRISK); 
     extractor.compute(firstImageSrcImgMat, firstImgMatOfKeyPoints, firstImgDescriptors); 
     extractor.compute(secondImageSrcImgMat, secondImgMatOfKeyPoints, secondImgDescriptors); 

     System.out.println("descriptorsA.size() : " + firstImgDescriptors.size()); 
     System.out.println("descriptorsB.size() : " + secondImgDescriptors.size()); 

     MatOfDMatch matches = new MatOfDMatch(); 

     DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMINGLUT); // BRUTEFORCE_HAMMINGLUT 
     matcher.match(firstImgDescriptors, secondImgDescriptors, matches); 

     System.out.println("matches.size() : " + matches.size()); 
     System.out.println("matches : " + matches); 

     MatOfDMatch matchesFiltered = new MatOfDMatch(); 

     List<DMatch> matchesList = matches.toList(); 
     List<DMatch> bestMatches = new ArrayList<DMatch>(); 

     Double max_dist = 0.0; 
     Double min_dist = 100.0; 

     for (int i = 0; i < matchesList.size(); i++) { 
      Double dist = (double) matchesList.get(i).distance; 

      if (dist > 0) 
       System.out.println("dist : " + dist); 

      if (dist < min_dist && dist != 0) { 
       min_dist = dist; 
      } 

      if (dist > max_dist) { 
       max_dist = dist; 
      } 

     } 

     System.out.println("max_dist : " + max_dist); 
     System.out.println("min_dist : " + min_dist); 

     if (min_dist > 50) { 
      System.out.println("No match found, min_dist under minimum value"); 
      return; 
     } 

     double threshold = 3 * min_dist; 
     double threshold2 = 2 * min_dist; 

     if (threshold > 75) { 
      threshold = 75; 
     } else if (threshold2 >= max_dist) { 
      threshold = min_dist * 1.1; 
     } else if (threshold >= max_dist) { 
      threshold = threshold2 * 1.4; 
     } 

     System.out.println("Threshold : " + threshold); 

     for (int i = 0; i < matchesList.size(); i++) { 
      Double dist = (double) matchesList.get(i).distance; 

      if (dist < threshold) { 
       bestMatches.add(matches.toList().get(i)); 
       System.out.println(String.format(i + " best match added : %s", dist)); 
      } 
     } 

     matchesFiltered.fromList(bestMatches); 

     System.out.println("matchesFiltered.size() : " + matchesFiltered.size()); 

     if (matchesFiltered.rows() >= 1) { 
      System.out.println("match found"); 
     } else { 
      System.out.println("match not found"); 
     } 

jakaś wskazówka co robię źle?

+0

Ile keypoints masz i ile deskryptory? Czy potrafisz je sobie wyobrazić? Czy jesteś pewien, że twój schemat progowania nie jest zbyt agresywnym wybijaniem meczów? I uważam, że w idealnym świecie nie powinno być żadnych dopasowań z prostego powodu, że istnieje różnica w parze (LTR vs. RTL), a deskryptory mają na celu odróżnienie takich różnic. Czy możesz spróbować dopasować między LTR a poziomą klapą RTL? –

+0

Muszę powiedzieć, że tak naprawdę nie rozumiałem, o co prosiłeś :(ALE, próbowałem dopasować pomiędzy 2 identycznymi obrazami (ten sam plik) i nadal mam "brak dopasowania" – Avisho

Odpowiedz

5

Jako że @ Iwillnotexist - Idonotexist stwierdził, że pierwszym problemem jest próg, który stosujesz. Spróbuj użyć progu, który nie zależy od odległości między deskryptorami, która nie działa dobrze, ponieważ niektóre deskryptory są znacznie bardziej dyskryminujące niż inne. Myślę, że da ci to lepsze wyniki. Radzę zastosować Test Ratio zaproponowany przez D. Lowe w pracy SIFT. Proszę spojrzeć na sekcję 7.1: http://cs.ubc.ca/~lowe/papers/ijcv04.pdf

Drugi problem polega na tym, że używasz BRISK do wykrywania funkcji na obrazach. Ta implementacja OpenCV zawiera błędy (można sprawdzić tutaj: http://code.opencv.org/issues/3976), więc spróbuj użyć innego FeatureDetector jak szybko, ORB, etc ... (deskryptor jest w porządku, dzięki czemu można nadal używać go)

skończyło się na badania w swoich zdjęć i udało mi aby uzyskać pewne wyniki z różnych czujki/deskryptorów: (keypoints z żadnym meczu -> żółty)

BRISK detektora i Eurovoc: BRISK/BRISK

  • lewo keypoints obrazu: 74
  • prawo keypoints obrazu: 86
  • mecze: 3 (Nawet zepsuty detektor mam tenis)

detektor ORB z BRISK jak Eurovoc: ORB/BRISK

  • lewe keypoints obrazu: 499
  • prawy kluczowe punkty obrazu: 500
  • dopasowania: 26

detektor ORB i deskryptora using ORB

  • lewe keypoints obrazu: 841
  • prawo keypoints obrazu: 907
  • mecze: 43

Wszystkie wyniki zostały uzyskane przy użyciu test współczynnika, aby usunąć fałszywe dopasowania. Mam nadzieję, że to pomoże!

EDIT:

BruteForceMatcher<Hamming> matcher; 
vector< vector<DMatch> > matches; 
vector <DMatch> goodMatches; 
matcher.knnMatch(imgDescriptors1, imgDescriptors2, matches, 2); 
// Ratio Test 
for (unsigned int matchIdx = 0; matchIdx < matches.size(); ++matchIdx) 
{ 
    const float ratio = 0.8; // As in Lowe's paper (can be tuned) 
    if (matches[matchIdx][0].distance < ratio * matches[matchIdx][1].distance) 
    { 
     goodMatches.push_back(matches[matchIdx][0]); 
    } 
} 
+0

Dzięki Zedv! Próbowałem wyszukać przykład kodu dla dopasowania proporcji, ale bez powodzenia ... czy możesz skierować mnie do jednego? – Avisho

+0

Czy możesz umieścić tutaj swój kod C++ ?, ale nie wiem nawet, które klasy użyć ... – Avisho

+0

Nie wstawiłem żadnego kodu ponieważ nie używam java. Tak czy inaczej, myślę, że łatwo będzie dokonać konwersji mojego kodu C++ Zaktualizowałem swoją odpowiedź za pomocą kodu. – zedv

2

wersja Java jest:

DescriptorMatcher descriptorMatcher; 
descriptorMatcher=DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING); 
MatOfDMatch good_matches; 
good_matches = new MatOfDMatch(); 

LinkedList<MatOfDMatch> dmatchesListOfMat = new LinkedList<>(); 
descriptorMatcher.knnMatch(imgDescriptors1, imgDescriptors2, dmatchesListOfMat, 2); 

LinkedList<DMatch> good_matchesList = new LinkedList<>(); 
for (int matchIndx = 0; matchIndx < dmatchesListOfMat.size() ; matchIndx++) { 
    double ratio = 0.8; 
    if (dmatchesListOfMat.get(matchIndx).toArray()[0].distance < ratio * dmatchesListOfMat.get(matchIndx).toArray()[1].distance) { 
     good_matchesList.addLast(dmatchesListOfMat.get(matchIndx).toArray()[0]); 
    } 
} 
good_matches.fromList(good_matchesList); 
Powiązane problemy