【问题标题】:Compare images SIFT /SURF details in .yml files OpenCV?比较.yml文件OpenCV中的图像SIFT / SURF细节?
【发布时间】:2015-07-02 01:03:55
【问题描述】:

我是 java android 开发人员,我对 C/C++ 或 Matlab 函数了解不多。 在我的代码中做的简单的事情就是创建 sift/Surf 图像详细信息并将详细信息保存在 .yml 文件中。

这是我如何创建筛选的代码

vector < KeyPoint > keypoints;
Mat descriptors;
// Create a SIFT keypoint detector.
SiftFeatureDetector detector;
detector.detect(image, keypoints);
LOGI("Detected %d keypoints\n", (int) keypoints.size());
// Compute feature description.
detector.compute(image, keypoints, descriptors);

将生成的描述符保存在 (.yml) 文件中,然后使用 OpenCV 的 FlannBasedMatcher 比较该 yml 文件

这是我的代码

descriptors1 & descriptors2 是从 .yml 文件创建的两个 mat 对象。

FlannBasedMatcher matcher;
vector<double> ee;
vector < DMatch > good_matches;
double good_matches_sum = 0.0;
vector < vector<DMatch> > matches;
matcher.knnMatch(descriptors1, descriptors2, matches, 2);
for (int i = 0; i < matches.size(); i++) {
   if (matches[i][0].distance < 0.8 * matches[i][1].distance) {

       good_matches.push_back(matches[i][0]);
       good_matches_sum += matches[i][0].distance;
    }
}

LOGI("good_matches_sum   %d s\n", good_matches_sum);
LOGI("the distance   k   %f s\n", good_matches_sum);

double score = (double) good_matches_sum / (double) good_matches.size();

LOGI("score   %f k   %d s\n", score, good_matches.size());

问题出在上面的代码中,每次我得到不同的结果。e

这里是我的两张图片

//first time run for two images
good_matches_sum   1006632960 
the distance   k   3054.279755 
scores   254.523313 k   12 s


//Second time run for same two images
good_matches_sum   -402653184 
the distance   k   2835.513489 
score score scores   257.773954 k   11 s


//Third time run for same two images
good_matches_sum   -1946157056 
the distance   k   2794.588959 
score score scores   254.053542 k   11 s

根据正面结果和负面结果,我假设图像更模糊或不同。但是每次都有这种不同的结果,我无法判断图像是否相似。

请帮助我,我不了解 Opencv 和 c,所以如果有人有任何想法,请建议更正的代码。谢谢。

【问题讨论】:

    标签: android c opencv java-native-interface opencv4android


    【解决方案1】:

    基本上,SIFT/SURF 无法判断两个图像是否相似。它只能告诉您一张图像中的哪个关键点与另一张图像中的哪个对应点匹配。

    幸运的是,这两个函数还为您提供了更多信息,例如匹配的“距离”以及图像中匹配的总数。

    我的想法告诉两个图像有多相似:

    1. Use findHomography() to get the homography of two images
    2. Check whether the homography is valid (such as 4 of the points form a rectangle). 
    3. Count the number of "good" matches (match.distance < SOME_DISTANCE)
    4. Use some math to generate a score
    5. If the previous homography is valid, increase the score
    

    这是我曾经使用过的一段代码,但还是有一些缺陷(对于某些特定类型的匹配,得分不合理。但这种情况很少发生)。

    注意,MY_****_DISTANCE 取决于您使用的是 SIFT 还是 SURF,以及您提供的 SIFT/SURF 函数的参数。

    //===========SCORE ============
    vector<double> matchDistance;
    double avg = 0;
    int avgCount = 0;
    int goodCount = 0 ;
    
    for( unsigned i = 0; i < matches.size(); i++ )
    {
        double dist = matches[i].distance;
    
        //This is a "average match"
        if( dist < MY_AVG_DISTANCE  && dist > MY_LEAST_DISTANCE )
        {
            avg += dist;        //Count the average of distance of "average matches"
            avgCount++;
        }
    
        //This is a good match, and number of good match have a great impact on the result
        //Good matches are also average matches, that is, {GOOD_MATCH} is a subset of {AVERAGE_MATCH}
        if(dist < MY_GOOD_DISTANCE && dist > MY_LEAST_DISTANCE ){
            goodCount++;    //Count the number of "good matches"
        }
    }
    
    if(avgCount > 6){
        avg /= avgCount;    //Gives the average value
        if(goodCount < 12){ //If there are too few good matches, make a punishment
            avg = avg + (12-goodCount) * 4;
        }
    }else{
        avg = MY_MAX_DISTANCE;
    }
    
    avg = avg > MY_AVG_DISTANCE ? MY_AVG_DISTANCE : avg;
    avg = avg < MY_MIN_DISTANCE ? MY_MIN_DISTANCE : avg;
    
    
    double score_avg = (MY_AVG_DISTANCE - avg) / ( MY_AVG_DISTANCE - MY_MIN_DISTANCE ) * 100;
    
    if(homography_valid){   //If the previous homography is valid, make a reward. 
        score_avg += 40;
        score_avg = score_avg > 100 ? 100 : score_avg;
    }else{
        score_avg -= 5;     //Or, make a little punishment
        score_avg = score_avg < 0 ? 0 : score_avg;
    }
    
    return score_avg
    

    更新

    我的_****_距离

    My_****_DISTANCE 是我自己定义的,抱歉之前没有解释。这是我使用的值,但您可能希望更改它以更好地适应您的代码。

    #define MY_MIN_DISTANCE  200
    #define MY_GOOD_DISTANCE 310
    #define MY_AVG_DISTANCE 350
    #define MY_MAX_DISTANCE 500
    #define MY_MIN_HESSIAN 2000
    #define MY_LEAST_DISTANCE 100
    

    当使用参数 SiftFeatureDetector detector(400, 3, 0.04, 10.0, 1.6); 运行 SIFT 时,与某些“正确”匹配相比,某些“错误”匹配的结果是:

    Wrong   Right
    307.993 330.124
    470.419 307.374
    219.775 371.026
    294.389 400.696
    355.321 259.239
    331.926 189.042
    222.317 457.089
    320.718 379.061
    423.09  201.95
    371.098 200.646
    362.427 343.229
    441.167 359.32
    253.253 382.15
    367.191 215.678
    405.19  358.686
    390.251 343.798
    341.905 238.002
    341.073 226.519
    363.775 262.5
    340.742 174.877
    320.214 415.802
    249.405 195.261
    347.357 328.76
    343.839 116.331
    351.058 383.93
    286.224 111.472
    352.976 138.701
    298.409 238.044
    385.34  223.716
    264.571 331.115
    333.339 208.103
    329.588 128.168
    372.971 267.83
    331.804 222.578
    301.935 232.459
    351.504 342.524
    300.762 379.87
    346.872 390.031
    374.281 308.198
    304.746 401.452
    307.184 193.298
    229.943 98.0714
    286.163 133.978
    363.634 171.415
    361.656 111.077
    357.108 134.186
    289.712 123.199
    371.496 339.944
    318.708 192.164
    360.547 425.937
    331.225 336.535
    297.688 309.419
    351.898 162.296
    408.206 311.055
    309.023 457.352
    281.375 337.529
    362.266 407.757
    229.295 388.567
    317.005 161.118
    386.907 108.936
    363.942 215.311
    374.832 343.376
    311.264 184.318
    364.745 188.963
    466.795 308.48
    381.667 318.828
    381.826 119.591
    377.338 105.527
    377.333 199.206
    279.228 369.394
    295.078 387.979
    267.408 196.942
    386.063 307.815
    372.14  184.83
            294.927
            417.138
            348.458
            97.8621
            234.199
            144.094
            172.377
            131.412
            250.503
            227.139
            233.32
            116.258
            205.331
            354.505
            95.0368
            108.434
            116.46
            138.246
            406.135
            308.2
            92.817
            194.838
            312.103
            323.163
            312.946
            377.798
            359.393
            396.191
            320.272
            375.025
            309.383
            280.826
            278.456
    

    很明显,“错误”匹配的平均值大于“正确”匹配的平均值。但是如果你浏览很多图片,你会遇到一些异常(例如匹配较少但平均距离较低的错误匹配),其中一些我还没有弄清楚如何消除。因此,基于匹配距离的原始数据,您还必须做出一个相当“个人”的分数。

    findHomography

    这是您可能需要的一段演示。

    std::vector<Point2f> obj_corners(4);
    obj_corners[0] = Point(0,0); 
    obj_corners[1] = Point( img_object.cols, 0 );
    obj_corners[2] = Point( img_object.cols, img_object.rows ); 
    obj_corners[3] = Point( 0, img_object.rows );
    std::vector<Point2f> scene_corners(4);
    Mat H = findHomography( obj, scene, RANSAC );
    perspectiveTransform( obj_corners, scene_corners, H);
    

    你可以找到详细信息in this tutorial

    更新 #2

    Check_Valid_Homography

    这取决于您如何定义“有效”。看官方的例子,左边的图片(“对象”图片)是右边图片(“场景”图片)的一部分。然后,将单应矩阵应用于“物体”图像的顶点向量,我们最终得到一个绿色的四边形出现在右侧,它标记了“物体”图像的位置。

    就我而言,根据教程,我对“有效”的定义是: 1.四个点组成一个四边形 2.四边形的边长不能太小 3、四边形的角不能太小。 4、四边形不宜倒置。

    执行一些基本数学运算,这是验证过程的一部分。

    bool RectChecker::check_order(const vector<Point2f> &corners, int height, int width){
        if(corners[0].y + 5 >= corners[3].y || corners[1].y + 5 >= corners[2].y){       //Point 0 should be above Point 3, so do Point1 and Point2
            return false;
        }
        if(corners[0].x + 5 >= corners[1].x || corners[3].x + 5 >= corners[2].x){       //Point 0 should be on the left of Point 1, so do Point3 and Point2
            return false;
        }
        int cnt = 0;
        for(int i = 0 ; i < corners.size() ; i++){          
            if(corners[i].x < -30 || corners[i].x > width + 30){
                    cnt++;
                    continue;
            }
            if(corners[i].y < -20 || corners[i].y > height + 20){               //This point is outside the image
                    cnt++;
            }
        }
        if(cnt == 4){       //All points are outside the image
            return false;
        }
        return true;
    }
    

    再一次,您可能想要创建自己的验证流程,而对于验证,这在很大程度上取决于您的要求。但在我看来,这部分是最简单的部分,而最重要的部分是评分过程。

    【讨论】:

    • 非常感谢您的帮助,我真的很感激。由于我在 c / Opencv 方面很差,我无法找出变量的默认值(MY_****_DISTANCE),我用筛选点检测更新了我的问题。请看一下,让我知道在我的情况下变量的默认值是什么,以及在我的情况下如何 findHomography(),抱歉问得太多了。再次感谢您的帮助:)
    • 但就我而言,我的图像中没有任何矩形,我将只捕获虹膜图像,它会像圆形图像。那么我还需要这个 findHomography 吗?
    • 我想我已经到了最后一点,关心的是如何计算homography_valid或Not?
    【解决方案2】:

    问题出在上面的代码中,我得到了不同的结果 时间

    这是因为 FLANN 匹配器会找到近似最近邻,并且基于使用随机数进行的初始化。为保证每次运行的答案相同,请播种随机数生成器(例如,调用 srand(123456);)或使用速度较慢但始终获得最准确结果的 BruteForceMatcher

    【讨论】:

      猜你喜欢
      • 2021-06-07
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-25
      • 2023-03-21
      • 2018-06-27
      相关资源
      最近更新 更多