积木逐个经过平面传送带到达我的相机。但它们可能倒置、侧放或"正常"放置。
我的方法是通过在许多不同位置和旋转中使用相机捕获图像,从而让分拣机学习积木。每个视图的特征由SURF算法计算出来。
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》中的描述进行操作:
with the matcher (=cv::BFMatcher(cv::NORM_L2)) the two nearest neighbours in both directions are searched
matcher.knnMatch(descriptorsImage1, descriptorsImage2, matches1, 2); matcher.knnMatch(descriptorsImage2, descriptorsImage1, matches2, 2);
I check the ratio between the distances of the found nearest neighbours. If the two distances are very similar it's likely that a false value is used.
// loop for matches1 and matches2 for(iterator matchIterator over all matches) if( ((*matchIterator)[0].distance / (*matchIterator)[1].distance) > 0.65 ) throw away
Finally only symmatrical match-pairs are accepted. These are matches in which not only n1 is the nearest neighbour to feature f1, but also f1 is the nearest neighbour to 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张图片中计算出基本矩阵,并过滤掉不适合投影的特征 - 难道没有一种方法可以使用3张或更多张图片做到同样的事情吗?(关键词三线性张量)。这样匹配应该会变得更加稳定。但我既不知道如何使用OpenCV实现这一点,也无法在Google上找到任何相关信息。