我使用ORB特征检测器查找两个图像之间的匹配,使用以下代码:
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);;
DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
// First photo
Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
Mat descriptors1 = new Mat();
MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
detector.detect(img1, keypoints1);
descriptor.compute(img1, keypoints1, descriptors1);
// Second photo
Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGB2GRAY);
Mat descriptors2 = new Mat();
MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
detector.detect(img2, keypoints2);
descriptor.compute(img2, keypoints2, descriptors2);
// Matching
MatOfDMatch matches = new MatOfDMatch();
MatOfDMatch filteredMatches = new MatOfDMatch();
matcher.match(descriptors1, descriptors2, matches);
// Linking
Scalar RED = new Scalar(255,0,0);
Scalar GREEN = new Scalar(0,255,0);
List<DMatch> matchesList = matches.toList();
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 < min_dist)
min_dist = dist;
if ( dist > max_dist)
max_dist = dist;
}
LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
for(int i = 0;i < matchesList.size(); i++){
if (matchesList.get(i).distance <= (1.5 * min_dist))
good_matches.addLast(matchesList.get(i));
}
// Printing
MatOfDMatch goodMatches = new MatOfDMatch();
goodMatches.fromList(good_matches);
System.out.println(matches.size() + " " + goodMatches.size());
Mat outputImg = new Mat();
MatOfByte drawnMatches = new MatOfByte();
Features2d.drawMatches(img1, keypoints1, img2, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
Highgui.imwrite("matches.png", outputImg);
我的问题是,我找不到一种方法来过滤匹配,以便他们只有在照片中有相似的位置时才匹配。我总是为一个关键点找到多个匹配,即使它们离位置很远。
有办法更好地过滤它们吗?
为了获得更好的匹配结果,您应该按照给定的顺序包含这些过滤方法。
-
对第一幅图像中的每个点进行两个方向的匹配在第二张图片中找到最匹配的,反之亦然。
-
之间进行比值检验(欧几里得距离比值检验)
- 执行RANSAC测试:这是一种模型拟合算法,它可以找到适合模型的最佳数据并去除异常值。
- 执行单形图:这是一个图像投影算法。
你可以在Computer vision application programming cookbook的第9章中获得上述方法的所有细节。它还提供了实现这些过滤技术的示例代码。这很容易理解。(注意:本书中的代码是用c++编写的,但一旦你理解了,它也可以很容易地在JAVA中实现)
看完Rober Langaniere的书。我知道有一个办法。它是去除距离较远的火柴。在java中,如下所示
Collections.sort(bestMatches,new Comparator<DMatch>() {
@Override
public int compare(DMatch o1, DMatch o2) {
if(o1.distance<o2.distance)
return -1;
if(o1.distance>o2.distance)
return 1;
return 0;
}
});
if(bestMatches.size()>3){
bestMatches = bestMatches.subList(0,3);
}
通过取两个描述符之间的最短汉明距离来完成匹配。因此,您将始终获得检测到的特征之间的匹配。
您应该修改ORB检测器的阈值。这样,你就减少了从背景(即噪声)中检测特征的可能性,所以你检测到的大部分特征将来自感兴趣的主题。