OpenCV - Java - 使用DescriptorMatcher无法匹配两张相反的图片

7
我试图使用OpenCV的DescriptorMatcher匹配两张相反的图像,但没有成功。 这两张图片分别是:http://i61.tinypic.com/28whu0g.jpg(从左到右)和http://i61.tinypic.com/x35vte.jpg(从右到左)。
我的代码与StackOverflow和网上看到的许多示例非常相似,但我始终找不到匹配项。
        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");
        }

有什么提示我做错了吗?


你有多少个关键点和描述符?你能可视化它们吗?你确定你的阈值方案没有过于激进地剔除匹配项吗?请考虑在完美的世界中,由于存在奇偶差异(从左到右与从右到左),因此不应该有匹配项,并且描述符旨在区分这种差异。你可以尝试在从左到右和从右到左的水平翻转之间进行匹配吗? - Iwillnotexist Idonotexist
我必须说,我真的不明白你在问什么 :( 但是,我尝试匹配两张相同的图像(同一文件),仍然得到“无匹配项”。 - Avi L
2个回答

5
如@Iwillnotexist-Idonotexist所述,第一个问题是您应用的阈值。尝试使用不依赖于描述符之间距离的阈值,因为某些描述符比其他描述符更具有区分度,这样会给您带来更好的结果。我建议您使用D. Lowe在SIFT论文中提出的Ratio Test。
请查看第7.1节:http://cs.ubc.ca/~lowe/papers/ijcv04.pdf 第二个问题是您正在使用BRISK来检测图像中的特征。这个OpenCV实现存在错误(您可以在此处检查:http://code.opencv.org/issues/3976),因此尝试使用另一个FeatureDetector,如FAST、ORB等(描述符不错,因此可以继续使用)。
最终,我在您的图片上测试了不同的检测器/描述符,并取得了一些结果: (没有匹配的关键点->黄色)
BRISK检测器和描述符:
左图关键点:74 右图关键点:86 匹配:3(即使使用错误的检测器,我也得到了匹配)
ORB检测器和BRISK描述符:
左图关键点:499 右图关键点:500 匹配:26
ORB检测器和描述符:
左图关键点:841 右图关键点:907 匹配:43
所有结果都是使用比率测试来消除虚假匹配得到的。
希望这可以帮助您!
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]);
    }
}

谢谢zedv!我尝试搜索比例匹配的代码示例,但没有找到...你能否给我推荐一个? - Avi L
你能把你的C++代码放在这里吗?很抱歉,我甚至不知道要使用哪些类... - Avi L
我没有放任何代码,因为我不使用Java。无论如何,我认为将我的C++代码转换会很容易。 我已经更新了我的答案,并附上了代码。希望这有所帮助。 - zedv

4

Java版本为:

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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接