Keypoint Matching funktioniert nur zweimal ...? (Java OpenCV)
Ich habe ein sehr seltsames Problem. Ich verwende diesen Code, um ein Bild in einem anderen zu erkennen (Java OpenCV):
AKTUALISIERTER CODE:
public void startRecognition() {
//load images, I want to find img_object in img_scene
Mat img_scene = Highgui.imread("D:/opencvws/ImageRecognition/src/main/resources/ascene.jpg");
Mat img_object = Highgui.imread("D:/opencvws/ImageRecognition/src/main/resources/aobj1.jpg");
run++;
System.out.println("RUN NO: " + run);
//init detector
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
//keypoint detection for both images (keyponts_scene for img_scene, keypoint_object for img_object)
MatOfKeyPoint keypoints_object = new MatOfKeyPoint();
MatOfKeyPoint keypoints_scene = new MatOfKeyPoint();
detector.detect(img_object, keypoints_object);
detector.detect(img_scene, keypoints_scene);
System.out.println("OK: " + keypoints_object.total());
System.out.println("SK: " + keypoints_scene.total());
//extractor init
DescriptorExtractor extractor = DescriptorExtractor.create(2); //2 = SURF;
Mat descriptor_object = new Mat();
Mat descriptor_scene = new Mat() ;
//Compute descriptors
extractor.compute(img_object, keypoints_object, descriptor_object);
extractor.compute(img_scene, keypoints_scene, descriptor_scene);
//init matcher
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED); // 1 = FLANNBASED
matcher.clear();
MatOfDMatch matches = new MatOfDMatch();
//match both descriptors
matcher.match(descriptor_object, descriptor_scene, matches);
List<DMatch> matchesList = matches.toList();
//calc min/max dist
Double max_dist = 0.0;
Double min_dist = 100.0;
for(int i = 0; i < descriptor_object.rows(); i++){
Double dist = (double) matchesList.get(i).distance;
if(dist < min_dist) min_dist = dist;
if(dist > max_dist) max_dist = dist;
}
//filter good matches
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
MatOfDMatch gm = new MatOfDMatch();
//good match = distance > 2*min_distance ==> put them in a list
for(int i = 0; i < descriptor_object.rows(); i++){
if(matchesList.get(i).distance < 2*min_dist){
good_matches.addLast(matchesList.get(i));
}
}
//List -> Mat
gm.fromList(good_matches);
//mat for resulting image
Mat img_matches = new Mat();
//filter keypoints (use only good matches); First in a List, iterate, afterwards ==> Mat
LinkedList<Point> objList = new LinkedList<Point>();
LinkedList<Point> sceneList = new LinkedList<Point>();
List<KeyPoint> keypoints_objectList = keypoints_object.toList();
List<KeyPoint> keypoints_sceneList = keypoints_scene.toList();
for(int i = 0; i<good_matches.size(); i++){
objList.addLast(keypoints_objectList.get(good_matches.get(i).queryIdx).pt);
sceneList.addLast(keypoints_sceneList.get(good_matches.get(i).trainIdx).pt);
}
MatOfPoint2f obj = new MatOfPoint2f();
obj.fromList(objList);
MatOfPoint2f scene = new MatOfPoint2f();
scene.fromList(sceneList);
//calc transformation matrix; method = 8 (RANSAC) ransacReprojThreshold=3
Mat hg = Calib3d.findHomography(obj, scene, 8,3);
//init corners
Mat obj_corners = new Mat(4,1,CvType.CV_32FC2);
Mat scene_corners = new Mat(4,1,CvType.CV_32FC2);
//obj
obj_corners.put(0, 0, new double[] {0,0});
obj_corners.put(1, 0, new double[] {img_object.cols(),0});
obj_corners.put(2, 0, new double[] {img_object.cols(),img_object.rows()});
obj_corners.put(3, 0, new double[] {0,img_object.rows()});
//transform obj corners to scene_img (stored in scene_corners)
Core.perspectiveTransform(obj_corners,scene_corners, hg);
//move points for img_obg width to the right to fit the matching image
Point p1 = new Point(scene_corners.get(0,0)[0]+img_object.cols(), scene_corners.get(0,0)[1]);
Point p2 = new Point(scene_corners.get(1,0)[0]+img_object.cols(), scene_corners.get(1,0)[1]);
Point p3 = new Point(scene_corners.get(2,0)[0]+img_object.cols(), scene_corners.get(2,0)[1]);
Point p4 = new Point(scene_corners.get(3,0)[0]+img_object.cols(), scene_corners.get(3,0)[1]);
//create the matching image
Features2d.drawMatches(
img_object,
keypoints_object,
img_scene,
keypoints_scene,
gm,
img_matches);
//draw lines to the matching image
Core.line(img_matches, p1 , p2, new Scalar(0, 255, 0),4);
Core.line(img_matches, p2, p3, new Scalar(0, 255, 0),4);
Core.line(img_matches, p3, p4, new Scalar(0, 255, 0),4);
Core.line(img_matches, p4, p1, new Scalar(0, 255, 0),4);
// resizing...
Mat resizeimage = new Mat();
Size sz = new Size(1200, 1000);
Imgproc.resize(img_matches, img_matches, sz);
panel1.setimagewithMat(img_matches);
frame1.repaint();
//tried to prevent any old references to mix up new calculation
matcher.clear();
img_matches = new Mat();
img_object = new Mat();
img_scene = new Mat();
keypoints_object = new MatOfKeyPoint();
keypoints_scene = new MatOfKeyPoint();
hg = new Mat();
}
Wenn ich die Methode startRecognition in meiner laufenden Anwendung zweimal ausführe (die opencv-Bibliothek wird beim Start geladen), erhalte ich für beide Erkennungen das gleiche Ergebnis. Beim dritten Versuch werden andere Schlüsselpunkte erkannt und eine weitere Transformationsmatrix (hg) berechnet. Beispiele:
nach dem 2. Versuch:
nach dem 3.:
ann jemand erklären, warum? Oder sag mir, wie ich das verhindern kann? Wenn ich das ganze Programm neu starte, wird es wieder 2 mal richtig erkennen und danach variieren. Nach mehreren Versuchen berechnet es erneut den korrekten hg (vom ersten und zweiten Versuch an). Ich kann nicht herausfinden, warum das passiert.
Danke im Vorau
gemorra