基于OpenCV的简单图片特征匹配

基于OpenCV的简单图片特征匹配                     http://ranjiao.com/blog/index.php/2012/picture_matching/

{0 Comments}

前两个月闲的蛋疼做了一个图片匹配的东东,原本以为直接用OpenCV就可以用图像特征的方式来做了,结果发现OpenCV只是封装了比较低层的特征识别算法,并没有高级的端口。这里把特征匹配的实现思路记录如下:

1. 计算出descriptor:

? View Code CPP
1
2
3
4
5
Mat img = imread(filename);
cv::Feature2D *detector = new cv::OrbFeatureDetector();
cv::Feature2D *extractor = new cv::OrbDescriptorExtractor();
detector->detect(img, kpImg);
extractor->compute(img, kpImg, descImg);

其中的detector负责提取图片中的特征点,并由extractor提取出descriptor,最终保存到descImg中。

2. 两张图片的descriptor进行对比

? View Code CPP
1
2
3
4
5
6
7
8
BruteForceMatcher< L2 > matcher;
matcher.knnMatch(desc1, desc2, matches1, 2);
matcher.knnMatch(desc2, desc1, matches2, 2);
 
ratioTest(matches1);
ratioTest(matches2);
 
symmetryTest(matches1, matches2, symMatches);

首先会使用BruteForceMatcher找出两个descriptor到对方的配对点,然后使用ratioTest和SymmetryTest来剔除不靠谱的匹配特征点,也就是下面所要说的剔除匹配点的操作。

3. 剔除低质量匹配点
ratioTest用来剔除距离比例相差过大的配对点,配对点之间的距离相差越大,能匹配上的概率也就越小。这里使用一个参数ratio来控制剔除距离相差在一定范围之外的特征点。

? View Code CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int ratioTest( VVecMatch &matches )
{
  float ratio = 0.8f;
  int removed=0;
  // for all matches
  for (std::vector<std::vector>::iterator
    matchIterator= matches.begin();
    matchIterator!= matches.end(); ++matchIterator) 
  {
    // if 2 NN has been identified
    if (matchIterator->size() > 1) 
    {
      // check distance ratio
      if ((*matchIterator)[0].distance/
        (*matchIterator)[1].distance > ratio) {
          matchIterator->clear(); // remove match
          removed++;
      }
    } else { // does not have 2 neighbours
      matchIterator->clear(); // remove match
      removed++;
    }
  }
  return removed;
}

symmetryTest用来判断两个图像间的特征点匹配是否是一一映射,对于不是的点则剔除掉。

? View Code CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void symmetryTest( const VVecMatch matches1, 
                               const VVecMatch matches2, 
                               VecMatch& symMatches )
{
  // for all matches image 1 -> image 2
  for (std::vector<std::vector>::const_iterator matchIterator1= matches1.begin();
    matchIterator1!= matches1.end(); ++matchIterator1) 
  {
    // ignore deleted matches
    if (matchIterator1->size() < 2)       
      continue;
 
    // for all matches image 2 -> image 1
    for (std::vector<std::vector>::const_iterator matchIterator2= matches2.begin();
      matchIterator2!= matches2.end();
      ++matchIterator2) 
    {
      // ignore deleted matches
      if (matchIterator2->size() < 2)         
        continue;       
      // Match symmetry test
      if ((*matchIterator1)[0].queryIdx ==
         (*matchIterator2)[0].trainIdx &&
         (*matchIterator2)[0].queryIdx ==
         (*matchIterator1)[0].trainIdx)
        {
         // add symmetrical match
         symMatches.push_back(
           cv::DMatch((*matchIterator1)[0].queryIdx,
           (*matchIterator1)[0].trainIdx,
           (*matchIterator1)[0].distance));
         break; // next match in image 1 -> image 2
      }
    }
  }
}

4. 判断是否匹配上

经过上面的特征匹配和剔除,剩下来的应该都是比较靠谱的匹配点了。如果用一个图片来和一个模板集合来进行比对,那么通过简单的比较能够匹配到的特征点数目就能够判断出是否匹配上了。

PS:对于OpenCV中的所有特征匹配算法都可以用这个办法来做,比如SIFT, SURF等等。只需要简单的替换第一步中的extractor和detector就可以了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值