【问题标题】:distinguishing objects with opencv用opencv区分对象
【发布时间】:2013-09-24 07:25:34
【问题描述】:

我想识别用于构建乐高分拣机的乐高积木(我使用 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

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

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

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

我有两个不同的想法:

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

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

【问题讨论】:

    标签: algorithm opencv image-processing computer-vision object-detection


    【解决方案1】:

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

    在图像分析方面:

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

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

    在机械方面:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      相关资源
      最近更新 更多