4

我正在做一个项目,我将在分类器中使用单应性作为特征。我的问题是自动计算单应性,我正在使用 SIFT 描述符来查找要计算单应性的两个图像之间的点,但是 SIFT 给我的结果很差,因此我不能在我的工作中使用它们。

我正在使用 OpenCV 2.4.3。

起初我使用的是 SURF,但我得到了类似的结果,因此我决定使用速度较慢但更精确的 SIFT。我的第一个猜测是我的数据集中的图像分辨率太低,但我在最先进的数据集(Pointing 04)上运行我的算法,我得到了几乎相同的结果,所以问题在于我做了什么而不是在我的数据集中。

在每个图像中找到的 SIFT 关键点之间的匹配是使用 FlannBased 匹配器完成的,我尝试了 BruteForce 匹配器,但结果再次几乎相同。

这是我找到的匹配示例(来自 Pointing 04 数据集的图像) 我的算法匹配

上图显示了我的程序找到的匹配有多差。只有 1 分是正确的匹配。我需要(至少)4 个正确的匹配项来完成我必须做的事情。

这是我使用的代码:

这是从每个图像中提取 SIFT 描述符的函数

void extract_sift(const Mat &img, vector<KeyPoint> &keypoints, Mat &descriptors, Rect* face_rec) {

        // Create masks for ROI on the original image
    Mat mask1 = Mat::zeros(img.size(), CV_8U);  // type of mask is CV_8U

    Mat roi1(mask1, *face_rec);
    roi1 = Scalar(255, 255, 255);

    // Extracts keypoints in ROIs only
    Ptr<DescriptorExtractor> featExtractor;
    Ptr<FeatureDetector> featDetector;
    Ptr<DescriptorMatcher> featMatcher;

    featExtractor = new SIFT(); 
    featDetector = FeatureDetector::create("SIFT"); 

    featDetector->detect(img,keypoints,mask1); 
    featExtractor->compute(img,keypoints,descriptors); 

}

这是匹配两个图像描述符的函数

void match_sift(const Mat &img1, const Mat &img2, const vector<KeyPoint> &kp1,
            const vector<KeyPoint> &kp2, const Mat &descriptors1, const Mat &descriptors2,
            vector<Point2f> &p_im1, vector<Point2f> &p_im2) {

//  Matching descriptor vectors using FLANN matcher
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
std::vector< DMatch > matches;
matcher->match( descriptors1, descriptors2, matches );

double max_dist = 0; double min_dist = 100;

// Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors1.rows; ++i ){
    double dist = matches[i].distance;
    if( dist < min_dist ) min_dist = dist;
    if( dist > max_dist ) max_dist = dist;
 }

 // Draw only the 4 best matches
 std::vector< DMatch > good_matches;

 // XXX: DMatch has no sort method, maybe a more efficent min extraction algorithm can be used here?
 double min=matches[0].distance;
 int min_i = 0;
 for( int i = 0; i < (matches.size()>4?4:matches.size()); ++i ) {
     for(int j=0;j<matches.size();++j)
         if(matches[j].distance < min) {
            min = matches[j].distance;
            min_i = j;
         }
    good_matches.push_back( matches[min_i]);
    matches.erase(matches.begin() + min_i);
    min=matches[0].distance;
    min_i = 0;
 }

  Mat img_matches;
  drawMatches( img1, kp1, img2, kp2,
               good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
               vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
  imwrite("imgMatch.jpeg",img_matches);
  imshow("",img_matches);
  waitKey();

  for( int i = 0; i < good_matches.size(); i++ )
  {
    // Get the points from the best matches
    p_im1.push_back( kp1[ good_matches[i].queryIdx ].pt );
    p_im2.push_back( kp2[ good_matches[i].trainIdx ].pt );
  }
}

这些函数在这里被调用:

extract_sift(dataset[i].img,dataset[i].keypoints,dataset[i].descriptors,face_rec);

[...]

//  Extract keypoints from i+1 image and calculate homography
    extract_sift(dataset[i+1].img,dataset[i+1].keypoints,dataset[i+1].descriptors,face_rec);
    dataset[front].points_r.clear(); // XXX: dunno if clearing the points every time is the best way to do it..
    match_sift(dataset[front].img,dataset[i+1].img,dataset[front].keypoints,dataset[i+1].keypoints,
        dataset[front].descriptors,dataset[i+1].descriptors,dataset[front].points_r,dataset[i+1].points_r);

    dataset[i+1].H = findHomography(dataset[front].points_r,dataset[i+1].points_r, RANSAC);

非常感谢任何有关如何提高匹配性能的帮助,谢谢。

4

1 回答 1

5

您显然在代码中使用了匹配距离的“最佳四点”。换句话说,如果两个描述符确实相似,则您认为匹配有效。我相信这是错误的。你试过画出所有的比赛吗?他们中的许多人应该是错误的,但许多人也应该是好的。

比赛的距离只是说明两个点的相似程度。这并不能说明匹配是否在几何上是连贯的。选择最佳匹配绝对应该考虑几何形状。

以下是我的做法:

  1. 检测角落(你已经这样做了)
  2. 找到matches(你已经这样做了)
  3. 尝试通过使用matches(不要过滤它们之前!)使用找到两个图像之间的单应变换findHomography(...)
  4. findHomography(...)会告诉你哪些是内点。那些是你的good_matches
于 2013-07-10T06:19:17.817 回答