6

我想识别用于构建乐高分拣机的乐高积木(我使用 c++ 和 opencv)。这意味着我必须区分看起来非常相似的对象。

砖块通过平板传送带单独送到我的相机。但它们可能以任何可能的方式放置:倒置、侧放或“正常”。

我的方法是通过用相机在许多不同的位置和旋转上贴上砖块来教分拣机。每个视图的特征都是通过冲浪算法计算的。

void calculateFeatures(const cv::Mat& image,
        std::vector<cv::KeyPoint>& keypoints,
        cv::Mat& descriptors)
{
  // detector == cv::SurfFeatureDetector(10)
  detector->detect(image,keypoints);
  // extractor == cv::SurfDescriptorExtractor()
  extractor->compute(image,keypoints,descriptors);
}

如果有一个未知的砖块(我想要排序的砖块),它的特征也会被计算并与已知的匹配。为了找到错误匹配的特征,我按照 OpenCV 2 Cookbook 中的描述进行:

  1. 使用匹配器 (=cv::BFMatcher(cv::NORM_L2)) 在两个方向上搜索两个最近的邻居

    matcher.knnMatch(descriptorsImage1, descriptorsImage2,
      matches1,
          2);
    matcher.knnMatch(descriptorsImage2, descriptorsImage1,
      matches2,
      2);
    
  2. 我检查找到的最近邻居的距离之间的比率。如果这两个距离非常相似,则很可能使用了错误值。

    // loop for matches1 and matches2
    for(iterator matchIterator over all matches)
      if( ((*matchIterator)[0].distance / (*matchIterator)[1].distance) > 0.65 )
        throw away
    
  3. 最后只接受对称匹配对。这些匹配中不仅 n1 是特征 f1 的最近邻,而且 f1 也是 n1 的最近邻。

    for(iterator matchIterator1 over all matches)
      for(iterator matchIterator2 over all matches)
        if ((*matchIterator1)[0].queryIdx == (*matchIterator2)[0].trainIdx  &&
        (*matchIterator2)[0].queryIdx == (*matchIterator1)[0].trainIdx)
          // good Match
    

现在只剩下相当不错的比赛了。为了过滤掉一些更糟糕的匹配,我使用基本矩阵检查哪些匹配适合 img1 在 img2 上的投影。

std::vector<uchar> inliers(points1.size(),0);
cv::findFundamentalMat(
    cv::Mat(points1),cv::Mat(points2), // matching points
    inliers,
    CV_FM_RANSAC,
    3,
    0.99);

std::vector<cv::DMatch> goodMatches
// extract the surviving (inliers) matches
std::vector<uchar>::const_iterator itIn= inliers.begin();
std::vector<cv::DMatch>::const_iterator itM= allMatches.begin();
// for all matches
for ( ;itIn!= inliers.end(); ++itIn, ++itM)

  if (*itIn)
    // it is a valid match

好比赛 结果相当不错。但在极端相似的情况下,仍然会出现错误。
在上图中,您可以看到类似的砖块被很好地识别。

糟糕的比赛 然而,在第二张图片中,也可以识别出错误的砖块。

现在的问题是如何改进匹配。

我有两个不同的想法:

所有可能的砖视图

  • 第二张图片中的匹配可以追溯到真正合适的特征,但前提是视野发生了剧烈变化。无论如何,要识别一块砖,我必须在许多不同的位置进行比较(至少如图三所示)。这意味着我知道我只能最小限度地改变视野。视野变化的强度信息应该隐藏在基本矩阵中。我如何从这个矩阵中读出房间中的位置变化了多远?尤其是旋转和强缩放应该是令人感兴趣的;如果砖块曾经在左侧贴得更远,这无关紧要。

  • 第二个想法:
    我从两张图片中计算出基本矩阵并过滤掉不适合投影的特征——难道不应该有一种方法可以使用三张或更多图片来做同样的事情吗?(关键字三焦张量)。这样匹配应该会变得更加稳定。但我既不知道如何使用 OpenCV 做到这一点,也无法在谷歌上找到任何相关信息。

4

1 回答 1

2

我没有完整的答案,但我有一些建议。

在图像分析方面:

  • 看起来您的相机设置非常稳定。很容易将砖块与背景分开。我还看到您的系统在后台查找功能。这是不必要的。将所有非砖像素设置为黑色以将它们从分析中删除。
  • 当您只找到砖块时,您的第一步应该是根据砖块的大小(即像素数)过滤可能的候选者。这样,您显示的示例错误匹配已经不太可能了。
  • 您可以考虑其他特征,例如砖的边界框的纵横比,砖的长轴和短轴(中心矩的协方差矩阵的特征向量)等。

这些更简单的功能将为您提供合理的第一个过滤器来限制您的搜索空间。

在机械方面:

  • 如果砖块实际上是从传送带上下来的,您应该能够使用类似于杆的东西沿直边“拉直”砖块,该杆与传送带上的传送带方向成一定角度,以便砖块更均匀地到达您的像这样的相机。
  • 与前一点类似,您可以使用悬挂在传送带上的非常松的刷子之类的东西,在砖块经过时将它们推倒。

同样,这两点都会限制您的搜索空间。

于 2013-09-26T21:25:45.467 回答