Java OpenCV-从knnMatch中提取良好匹配
我正在尝试实现一个非常简单的程序来查找两个图像之间的相似性 我正在使用ORB特征检测器和图像描述符执行此任务,并使用knnMatch识别匹配项:Java OpenCV-从knnMatch中提取良好匹配,java,opencv,Java,Opencv,我正在尝试实现一个非常简单的程序来查找两个图像之间的相似性 我正在使用ORB特征检测器和图像描述符执行此任务,并使用knnMatch识别匹配项: FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB); DescriptorMatcher m
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
// DETECTION
// first image
Mat img1 = Imgcodecs.imread(path1, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
Mat descriptors1 = new Mat();
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
descriptor.compute(img1, keypoints1, descriptors1);
// second image
Mat img2 = Imgcodecs.imread(path2, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
Mat descriptors2 = new Mat();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector.detect(img2, keypoints2);
descriptor.compute(img2, keypoints2, descriptors2);
// MATCHING
// match these two keypoints sets
List<MatOfDMatch> matches = new ArrayList<MatOfDMatch>();
matcher.knnMatch(descriptors1, descriptors2, matches, 5);
问题是有太多的比赛,它也包括那些太远了。我似乎找不到如何只提取好的匹配项(超过某个阈值)?有人能给我指出正确的方向,或者让我看一些基本的工作示例吗?我在这上面花了好几个小时,好像迷路了
编辑:
我试过查看,但标准(非knn)匹配使用了不同的结构,我无法使其工作。如其他答案中所述,有几种方法可以删除异常值和错误匹配。我猜您找到了使用
match
而不是knnMatch
的示例和教程,使用了其中一些方法
因此,正如您所知,knnMatch
为descriptor1
中的每个描述符返回descriptor2
中的n个最佳匹配项。也就是说,你得到的不是一个匹配列表,而是一个匹配列表。我想这就是你有问题的原因
使用knnMatch
的主要优点是可以执行比率测试。因此,如果从descriptor1
中的一个描述符到descriptor2
中的两个最佳描述符之间的距离相似,则表明图像中存在重复模式(例如草地前的尖桩围栏的尖端)。因此,这种匹配是不可靠的,应该删除。
(我不知道为什么要搜索五个最佳匹配项-每个描述符传递5到knnMatch
。而是搜索两个。)
如果现在只想访问每个描述符的最佳匹配,只需访问“子列表”的第一个元素即可。在下面的示例中,您将发现使用RANSAC的比率测试和单应性估计(我替换了knnMatch
之后的所有内容):
//比率测试
LinkedList good_matches=新建LinkedList();
for(Iterator Iterator=matches.Iterator();Iterator.hasNext();){
MatOfDMatch MatOfDMatch=(MatOfDMatch)迭代器.next();
如果(matOfDMatch.toArray()[0]。距离/matOfDMatch.toArray()[1]。距离<0.9){
良好的匹配。添加(matOfDMatch.toArray()[0]);
}
}
//获取好匹配的关键点坐标,以查找单应性并使用ransac删除异常值
List pts1=new ArrayList();
List pts2=new ArrayList();
对于(int i=0;在检查时也提出了一个非常类似的问题@Darshan@pyan是的,我看过这个。但是,我似乎无法重写代码来与knn matcher一起工作。谢谢,这很有效!你知道如何使用好的匹配来计算某种分数来标记这些相似性吗两张比较过的图片?取决于你所说的相似性。如果相似意味着两张图片在同一场景中显示不同的视图,那么我认为你的方法是可以的(取决于场景)。否则我会寻找不同的方法。你能举个例子吗?这正是我的用例。相同的对象,但从不同的角度拍摄。目前,我使用提取的良好匹配数作为标记相似性的“分数”。对我来说很有意义。也许你可以使用#良好匹配/#所有匹配来获得比率。(否则,两个结构较低的图像可能比两个具有更多关键点的高结构图像更不相似)如果matOfDMatch.toArray()[0]始终为我提供ArrayIndexOutOfBounds,这是一个错误吗?
// DRAWING OUTPUT
Mat outputImg = new Mat();
// this will draw all matches, works fine
Features2d.drawMatches2(img1, keypoints1, img2, keypoints2, matches, outputImg);
// save image
Imgcodecs.imwrite("result.jpg", outputImg);
// ratio test
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
for (Iterator<MatOfDMatch> iterator = matches.iterator(); iterator.hasNext();) {
MatOfDMatch matOfDMatch = (MatOfDMatch) iterator.next();
if (matOfDMatch.toArray()[0].distance / matOfDMatch.toArray()[1].distance < 0.9) {
good_matches.add(matOfDMatch.toArray()[0]);
}
}
// get keypoint coordinates of good matches to find homography and remove outliers using ransac
List<Point> pts1 = new ArrayList<Point>();
List<Point> pts2 = new ArrayList<Point>();
for(int i = 0; i<good_matches.size(); i++){
pts1.add(keypoints1.toList().get(good_matches.get(i).queryIdx).pt);
pts2.add(keypoints2.toList().get(good_matches.get(i).trainIdx).pt);
}
// convertion of data types - there is maybe a more beautiful way
Mat outputMask = new Mat();
MatOfPoint2f pts1Mat = new MatOfPoint2f();
pts1Mat.fromList(pts1);
MatOfPoint2f pts2Mat = new MatOfPoint2f();
pts2Mat.fromList(pts2);
// Find homography - here just used to perform match filtering with RANSAC, but could be used to e.g. stitch images
// the smaller the allowed reprojection error (here 15), the more matches are filtered
Mat Homog = Calib3d.findHomography(pts1Mat, pts2Mat, Calib3d.RANSAC, 15, outputMask, 2000, 0.995);
// outputMask contains zeros and ones indicating which matches are filtered
LinkedList<DMatch> better_matches = new LinkedList<DMatch>();
for (int i = 0; i < good_matches.size(); i++) {
if (outputMask.get(i, 0)[0] != 0.0) {
better_matches.add(good_matches.get(i));
}
}
// DRAWING OUTPUT
Mat outputImg = new Mat();
// this will draw all matches, works fine
MatOfDMatch better_matches_mat = new MatOfDMatch();
better_matches_mat.fromList(better_matches);
Features2d.drawMatches(img1, keypoints1, img2, keypoints2, better_matches_mat, outputImg);
// save image
Imgcodecs.imwrite("result.jpg", outputImg);