对于C ++和Python OpenCV库,图像之间的SURF关键点检测和FLANN匹配的结果差别很大

时间:2018-02-07 12:53:15

标签: python c++ opencv surf flann

我已经实现了在Python中匹配图像之间关键点的工作流程,并且我正在将其转换为Objective C ++,以便在iOS项目中使用。我在两个平台上都使用OpenCV 3.4。虽然我与我的代码匹配,但结果似乎大不相同。

Python实现:

def simple(source_image_name, sample_image_name):
    surf = cv2.xfeatures2d.SURF_create(400, nOctaves=3, nOctaveLayers=4, extended=False, upright=True)

    source_image = cv2.imread(source_image_name, 0)

    # Detect keypoints in source image
    source_keypoints, source_descriptors = surf.detectAndCompute(source_image, None)

    print("source keypoints: " + str(len(source_keypoints)))

    sample_image = cv2.imread(sample_image_name, 0)

    # Detect keypoints in sample image
    sample_keypoints, sample_descriptors = surf.detectAndCompute(sample_image, None)

    print("sample keypoints: " + str(len(sample_keypoints)))

    # Find matches between the images
    FLANN_INDEX_KDTREE = 0
    index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
    search_params = dict()
    flann = cv2.FlannBasedMatcher(index_params, search_params)

    matches = flann.knnMatch(source_descriptors, sample_descriptors, k=2)

    print("matches: " + str(len(matches)))

    # Filter to good matches
    good_matches = []

    for match1, match2 in matches:
        if match1.distance < match2.distance * 0.75:
            good_matches.append(match1)

    print("good matches: " + str(len(good_matches)))

Objective C ++实现:

+ (void)simpleWithSourceImage:(UIImage *)sourceImage sampleImage:(UIImage *)sampleImage {
    Ptr<SURF> surf = cv::xfeatures2d::SURF::create(400, 3, 4, false, true);

    cv::Mat sourceImageMat;
    UIImageToMat(sourceImage, sourceImageMat);

    std::vector<KeyPoint> sourceKeypoints;
    cv::Mat sourceDescriptors;

    //Detect keypoints in source image
    surf->detectAndCompute(sourceImageMat, noArray(), sourceKeypoints, sourceDescriptors);

    NSLog(@"source keypoints: %lu", sourceKeypoints.size());

    cv::Mat sampleImageMat;
    UIImageToMat(sampleImage, sampleImageMat);

    std::vector<KeyPoint> sampleKeypoints;
    cv::Mat sampleDescriptors;

    //Detect keypoints in sample image
    surf->detectAndCompute(sampleImageMat, noArray(), sampleKeypoints, sampleDescriptors);

    NSLog(@"sample keypoints: %lu", sampleKeypoints.size());

    //Find matches between the images
    FlannBasedMatcher matcher(new cv::flann::KDTreeIndexParams(5));

    std::vector<std::vector<DMatch>> matches;

    matcher.knnMatch(sampleDescriptors, sourceDescriptors, matches, 2);

    NSLog(@"matches: %lu", matches.size());

    //Filter to good matches
    std::vector<DMatch> goodMatches;

    for (int i = 0; i < matches.size(); i++) {
        std::vector<DMatch> match = matches[i];

        if (match[0].distance < match[1].distance * 0.75) {
            DMatch goodMatch = match[0];

            goodMatches.push_back(goodMatch);
        }
    }

    NSLog(@"good matches: %lu", goodMatches.size());
}

这两种实现都是:

  1. 以他们需要的格式将图像加载到内存中。
  2. 检测每张图片上的关键点和描述符。
  3. 查找图片之间的匹配。
  4. Python控制台日志:

    source keypoints: 16133
    sample keypoints: 18265
    matches: 16133
    good matches: 3785
    

    C ++控制台日志:

    source keypoints: 16281
    sample keypoints: 18040
    matches: 18040
    good matches: 558
    

    虽然他们已经获得相同的图像,但两个图像中检测到的关键点的数量略有不同。也许这与它阅读图像的方式有关。那里约1%的细微差别并不是太大的问题。

    然而,匹配的差异更大,差异大约为11%,尽管C ++实际上更高。然后,C ++的好匹配数 - 相差86%。

    我更多地研究了matches的差异......

    Python匹配:

    match 1 average: 0.220831272634
    distance average: 0.840705045962
    

    C ++匹配:

    match 1 average: 0.298346
    distance average: 0.924873
    

    因此,C ++结果的匹配1平均值明显更高,并且第一场比赛和第二场比赛之间的平均距离非常接近。

    我尝试将用于加载图像文件的初始代码更改为:

    NSFileHandle* sourceHandle = [NSFileHandle fileHandleForReadingAtPath:sourceImageName];
    NSData *sourceData = [sourceHandle readDataToEndOfFile];
    v::Mat sourceImageMat = cv::imdecode(cv::Mat(1, [sourceData length], CV_8UC1, (void*)sourceData.bytes), CV_LOAD_IMAGE_UNCHANGED);
    

    确实影响了结果,但没有影响结论 - C ++匹配仍然低得多,距离平均值很高,结果之间的距离匹配很近:

    source keypoints: 16116
    sample keypoints: 18253
    matches: 18253
    good matches: 518
    match 1 average: 0.299299
    distance average: 0.925706
    

    我也尝试在Python代码上查看匹配2的平均值,平均值为0.26 - 仍然低于C ++代码的数学1平均值。换句话说,Python的第二好结果平均比C ++的最佳匹配好。

    我试图找出这种差异的来源。我的实现不匹配吗?

0 个答案:

没有答案