9

My code is working good but when it extracts keypoints, it matches poorly the two images. Here you can find my code, but I don't know how to draw good matched in JAVA Android

 descriptors = new Mat();
        keypoints = new MatOfKeyPoint();
        detector = FeatureDetector.create(FeatureDetector.ORB);
        detector.detect(img1, keypoints);
        descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
        descriptor.compute(img1, keypoints, descriptors);
        matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
     ColorDetection.cvt_YUVtoRGBtoHSV(mYuv,mGraySubmat);
          MatOfKeyPoint mKeyPoints = new MatOfKeyPoint();
        MatOfDMatch  matches = new MatOfDMatch();

          detector.detect(mGraySubmat, mKeyPoints);
          descriptor.compute(mGraySubmat, mKeyPoints, mIntermediateMat);

        matcher.match(mIntermediateMat,descriptors,matches);
        mIntermediateMat2.create(resultSize, CvType.CV_8UC1);
        Features2d.drawMatches(img1, keypoints, mGraySubmat, mKeyPoints, matches, 
                mIntermediateMat2,GREEN, RED,  MATCH_MASK, Features2d.NOT_DRAW_SINGLE_POINTS);

          Imgproc.resize(mIntermediateMat2, mIntermediateMat2, mRgba.size());
          Imgproc.cvtColor(mIntermediateMat2, mRgba, Imgproc.COLOR_RGBA2BGRA, 4);
     Utils.matToBitmap(mRgba, bmp);

      DMatch dm[] = matches.toArray();
          List<Point> lp1 = new ArrayList<Point>(dm.length);
          List<Point> lp2 = new ArrayList<Point>(dm.length);
          KeyPoint tkp[] = keypoints.toArray();
          KeyPoint qkp[] = mKeyPoints.toArray();
          for (int i = 0; i < dm.length; i++) {
              DMatch dma = dm[i];
              lp1.add(tkp[dma.trainIdx].pt);
              lp2.add(qkp[dma.queryIdx].pt);
          }
          MatOfPoint2f pointsPrev = new MatOfPoint2f(lp1.toArray(new Point[0]));
          MatOfPoint2f pointsAct  = new MatOfPoint2f(lp2.toArray(new Point[0]));
        Log.i("pointsPrev", pointsPrev.size().toString());
        Log.i("pointsAct", pointsAct.size().toString());
          fundamental_matrix.create(resultSize, CvType.CV_8UC1);
        fundamental_matrix = Calib3d.findFundamentalMat(
                  pointsAct, pointsPrev, Calib3d.FM_RANSAC, 3, 0.99);

any suggestion?

EDIT :

i can't convert matches to list ! because Feature2d.drawMatches() need a MatOfDmatch and not a List<Dmatch>

MatOfDMatch matches, matches12, matches21;
matcher.match( descriptors1, descriptors2, matches12 );
matcher.match( descriptors2, descriptors1, matches21 );

iterate matches12
    DMatch forward = matches12[i];  
    DMatch backward = matches21[forward.trainIdx]; 
    if( backward.trainIdx == forward.queryIdx ) 
 //add forward to matches 
Features2d.drawMatches(img1, keypoints, mGraySubmat, mKeyPoints, matches,mIntermediateMat2);
Girish Nair
  • 5,148
  • 5
  • 40
  • 61
Mirlo
  • 625
  • 9
  • 26

2 Answers2

15

Your code should be like this:

 FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
 DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);;
 DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

 //first image
 Mat img1 = Highgui.imread("<image1 path>");
 Mat descriptors1 = new Mat();
 MatOfKeyPoint keypoints1 = new MatOfKeyPoint();

 detector.detect(img1, keypoints1);
 descriptor.compute(img1, keypoints1, descriptors1);

 //second image
 Mat img2 = Highgui.imread("<image2 path>");
 Mat descriptors2 = new Mat();
 MatOfKeyPoint keypoints2 = new MatOfKeyPoint();

 detector.detect(img2, keypoints2);
 descriptor.compute(img2, keypoints2, descriptors2);

 //matcher should include 2 different image's descriptors
 MatOfDMatch  matches = new MatOfDMatch();             
 matcher.match(descriptors1,descriptors2,matches);
 //feature and connection colors
 Scalar RED = new Scalar(255,0,0);
 Scalar GREEN = new Scalar(0,255,0);
 //output image
 Mat outputImg = new Mat();
 MatOfByte drawnMatches = new MatOfByte();
 //this will draw all matches, works fine
 Features2d.drawMatches(img1, keypoints1, img2, keypoints2, matches, 
 outputImg, GREEN, RED,  drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);

Also if you want to display just features, you can add this code:

 Mat featuredImg = new Mat();
 Scalar kpColor = new Scalar(255,159,10);//this will be color of keypoints
 //featuredImg will be the output of first image
 Features2d.drawKeypoints(img1, keypoints1, featuredImg , kpColor, 0);
 //featuredImg will be the output of first image
 Features2d.drawKeypoints(img1, keypoints1, featuredImg , kpColor, 0);

Then you can show matched points like this:

  Bitmap imageMatched = Bitmap.createBitmap(outputImg.cols(), outputImg.rows(), Bitmap.Config.RGB_565);//need to save bitmap
  Utils.matToBitmap(outputImg, imageMatched);
  ImageView.setImageBitmap(imageMatched);

Eventually you can implement good matches. I hope this thread will be helpful.

Community
  • 1
  • 1
COvayurt
  • 827
  • 2
  • 11
  • 36
  • 1
    Hi thank you for the response, now i want a good condition to found a good similarity but this condition is not efficace why ? if(row_count>490&&good_matches.size()<60 &&min_dist<12) logo_detected=true; else logo_detected=false; – Mirlo Apr 20 '13 at 15:44
  • Your welcome.I don't want to mislead but I think it depends on what you are working on. You have to calculate for your own project. – COvayurt Apr 21 '13 at 10:08
  • I have used your code, and tested it with 10-12 images, but it is not giving perfect match, i just want to find the coordinates of the exact matching location but it is not able to give me the perfect result. if possible then give me the way by which i can increaser the accuracy of matching – Mehul Thakkar Jan 03 '14 at 11:13
  • It seems like there is a few way to increase the accuracy of matching but i do not know how to do it. Maybe there is no way it just does it its own way. Because it is native library in android. So that we can not see inside of the methods. Also i tried to use the average of the scores and i defined a threshold(it depends on what you are working on) for eliminate the bad matches. – COvayurt Jan 06 '14 at 00:08
5

Good Matches method is basing on removing from your MatOfDMatch matches = new MatOfDMatch(); list matched points that has different descriptors or spacial location. What I suggest to do is to loop over matches list and put to the new list matches that are satisfy conditions like:

int DIST_LIMIT = 80;
List<DMatch> matchesList = matches.toList();
List<DMatch> matches_final= new ArrayList<DMatch>();
for(int i=0; i<matchesList.size(); i++)
   if(matchesList .get(i).distance <= DIST_LIMIT){
       matches_final.add(matches.toList().get(i));
   }
}

MatOfDMatch matches_final_mat = new MatOfDMatch();
matches_final_mat.fromList(matches_final);

Same thing you can do with matched points coordinates. Here is the useful link.

andriy
  • 4,074
  • 9
  • 44
  • 71
  • i can't convert matches to list ! because Feature2d.drawMatches() need a MatOfDmatch and not a List MatOfDMatch **matches**, matches12, matches21; matcher.match( descriptors1, descriptors2, matches12 ); matcher.match( descriptors2, descriptors1, matches21 ); // iterate matches12 DMatch forward = matches12[i]; DMatch backward = matches21[forward.trainIdx]; if( backward.trainIdx == forward.queryIdx ) // add forward to **matches** Features2d.drawMatches(img1, keypoints, mGraySubmat, mKeyPoints, **matches**,mIntermediateMat2); – Mirlo Mar 21 '13 at 13:14
  • You can convert it with `MatOfDMatch matches = new MatOfDMatch(); matches.fromList(matches_final);`. It is not so efficient, but I don't see another way ho to do Good Matches in java. – andriy Mar 21 '13 at 14:22
  • yes thnx i fixed why ? and if we call function c++ jni? did you have another solution – Mirlo Mar 21 '13 at 14:45
  • @Andriy - What would be the best threshold for `DIST_LIMIT`? – Karthik Balakrishnan Apr 15 '13 at 13:40
  • @Torcellite I'm using 80. Note that this is a Hamming distance between matched descriptors. If you convert point's descriptor to 512bit binary string, there can be 80 different bits. – andriy Apr 15 '13 at 13:47
  • Could you take a look at this project and tell me how I would go about implementing the method to find the best matches, please? http://github.com/torcellite/imageComparator – Karthik Balakrishnan Apr 15 '13 at 14:23
  • 1
    @Torcellite inside of the compare() function, after matcher.match() at line 162 add code of my answer. I just have edited it. I also suggest to use BRUTEFORCE_HAMMING matcher. And if your images are very similar, you should use smaller DIST_LIMIT. I'm using 80, because of the noise on images – andriy Apr 15 '13 at 14:38
  • I do not know what should be to put as dist_min because my case is generic, I want to detect any object which can then be analyzed any help please – Mirlo Apr 25 '13 at 21:08
  • I suggest you to set it as 80. Then test if objects are correctly recognized. If no object recognized, increment it. If objects are incorrectly recognized then set it to lower value. It's impossible to know exact value of DIST_LIMIT. You should adjust it by yourself. – andriy Apr 25 '13 at 21:44
  • thank you its working, is there another solution (condition) that is efficace ? otherwise i read some articles about the descriptors, but I have not come to understand the difference between them ORB FREAK FAST SURF ... if you have a good article that shows their thnks – Mirlo Apr 25 '13 at 21:56
  • No I'm sorry, I do not know any paper which compares all this algorithms. – andriy Apr 25 '13 at 22:21
  • no problem i found one :) thanks http://computer-vision-talks.com/2011/01/comparison-of-the-opencvs-feature-detection-algorithms-2/ – Mirlo Apr 25 '13 at 22:33
  • is it possible to track the recognized object? – Mirlo Apr 30 '13 at 13:29
  • 1
    Yes. Transform matches and keypoints to list `List matches_list = matches.toList();List kp_list = keypoints.toList();` and then iterate through the list kp_list.get(matches_list.get(i).queryIdx) and find the minimum and maximum X and Y of matched keypoints in order to encounter two points that will define your rectangle. Then define a rectangle `Rect roi = new Rect(new Point(minX,minY),new Point(maxX,maxY))` and then you can draw rectangle around matched(recognized) region. Taken from my previous [answer](http://stackoverflow.com/a/16225663/548601) – andriy Apr 30 '13 at 13:53
  • @viktorovich thanks, but it can also help me to pose estimation and registration of graphical objects on the recognized objects? – Mirlo May 06 '13 at 15:30