【问题标题】:Template matching with Orb : error with batchDistance method与 Orb 匹配的模板:batchDistance 方法出错
【发布时间】:2013-07-09 14:36:26
【问题描述】:

我正在尝试检测模板图像(徽标)是否存在于 pdf 文档中。该文档可以是封装在 pdf 中的扫描件,也可以是“纯”pdf 文档,但这完全是随机的。

首先,我使用 ImageMagick 的转换工具将 pdf 文档转换为 png 图像,然后将输出图像切成两半,因为它们太大了,然后我尝试将数据库中的徽标与任何半切图像中存在的形状。

为此,我使用了一个带有 Orb 描述符的 Orb 特征检测器和一个 RobustMatcher(一种改进的 BruteForce 匹配器,源代码可用 here)。这是我改编的一段代码:

// Read input images
Mat image1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
Mat image2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);

if (!image1.data || !image2.data) {
    std::cout << " --(!) Error reading images " << std::endl;
    exit(1);
}

// Setting up values for ORB Detector
int nfeatures = 800;
//float scaleFactor = 1.10;
int nlevels = 8;
int edgeThreshold = 12;
int firstLevel = 0;
int WTA_K = 2;
int scoreType = 0;
int patchSize = 31;

// Prepare the matcher
RobustMatcher rmatcher;
rmatcher.setConfidenceLevel(0.98);
rmatcher.setMinDistanceToEpipolar(1.0);
rmatcher.setRatio(0.80f);
cv::Ptr<cv::FeatureDetector> pfd = new cv::OrbFeatureDetector(nfeatures, scaleFactor, nlevels, edgeThreshold, firstLevel, WTA_K, scoreType, patchSize);
rmatcher.setFeatureDetector(pfd);
cv::Ptr<cv::DescriptorExtractor> pde = new cv::OrbDescriptorExtractor();
rmatcher.setDescriptorExtractor(pde);

// Match the two images
std::vector<cv::DMatch> matches;
std::vector<cv::KeyPoint> keypoints1, keypoints2;
cv::Mat fundemental = rmatcher.match(image1, image2, matches, keypoints1, keypoints2);

// If nothing could be matched, stop here
if(matches.size() < 4){
    exit(2);
}

代码在我仔细选择的一些示例上效果很好,具有高度可识别的徽标和干净的图像,具有一定的比例......等等。但是当我尝试将该过程应用于随机 pdf 文件时,我开始从 OpenCV 得到这个错误:

OpenCV 错误:batchDistance 中的断言失败 (type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U)),文件 /home/das/Downloads /opencv-2.4.5/modules/core/src/stat.cpp,第 1797 行 在抛出 'cv::Exception' 的实例后调用终止 what(): /home/das/Downloads/opencv-2.4.5/modules/core/src/stat.cpp:1797: 错误: (-215) type == src2.type() && src1.cols == src2 .cols && (type == CV_32F || type == CV_8U) in function batchDistance

中止(核心转储)

我检查了这个错误,发现 src1.cols != src2.cols,一个快速的解决方法是在尝试匹配图像之前测试条件。问题是我这样做会错过很多图像,只有在我处理视频流时才可以这样做……但我不是,下一张图像与前一张没有任何共同之处,并且我无法确定我的徽标是否出现在文档中。

这是 stat.cpp 中的代码,第 1789 到 1826 行:(断言在第 1797 行的开头)

void cv::batchDistance( InputArray _src1, InputArray _src2,
                    OutputArray _dist, int dtype, OutputArray _nidx,
                    int normType, int K, InputArray _mask,
                    int update, bool crosscheck )
{
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
int type = src1.type();
CV_Assert( type == src2.type() && src1.cols == src2.cols &&
           (type == CV_32F || type == CV_8U));
CV_Assert( _nidx.needed() == (K > 0) );

if( dtype == -1 )
{
    dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F;
}
CV_Assert( (type == CV_8U && dtype == CV_32S) || dtype == CV_32F);

K = std::min(K, src2.rows);

_dist.create(src1.rows, (K > 0 ? K : src2.rows), dtype);
Mat dist = _dist.getMat(), nidx;
if( _nidx.needed() )
{
    _nidx.create(dist.size(), CV_32S);
    nidx = _nidx.getMat();
}

if( update == 0 && K > 0 )
{
    dist = Scalar::all(dtype == CV_32S ? (double)INT_MAX : (double)FLT_MAX);
    nidx = Scalar::all(-1);
}

if( crosscheck )
{
    CV_Assert( K == 1 && update == 0 && mask.empty() );
    Mat tdist, tidx;
    batchDistance(src2, src1, tdist, dtype, tidx, normType, K, mask, 0, false);

所以我想知道这个断言是什么意思? stat.cpp 中的 src1 和 src2 文件到底是什么?为什么它们需要具有相同的列数?

我尝试更换为 Surf 检测器和提取器,但仍然出现错误。

如果有人有想法,请不要犹豫,我欢迎任何建议或通知!

提前致谢。

编辑

我现在有一个更精确的问题:我如何确保 src1.cols == src2.cols ?为了回答这个问题,我想我应该知道在调用 batchDistance(...) 之前应用于我的 cv::Mat image1 和 image2 的转换是什么,以便在 image1 和 image2 上找到一个条件,这将确保 @987654325 @,所以我的代码看起来像这样:

// Match the two images
std::vector<cv::DMatch> matches;
std::vector<cv::KeyPoint> keypoints1, keypoints2;
    if( CONDITION_ON_IMAGE1&IMAGE2_TO_ENSURE_SRC1.COLS==SRC2.COLS ){
    cv::Mat fundemental = rmatcher.match(image1, image2, matches, keypoints1, keypoints2);
    }

【问题讨论】:

  • 您是否尝试将较小的图像粘贴到尺寸与另一张匹配的空白图像中?这可能是一个快速而肮脏的解决方案......
  • 行得通!我没有错误了。但是检测可靠性下降了......这意味着源图像大小之间必须存在相关性才能使算法起作用。问题是这种相关性是什么?
  • 好吧,让我们看看...图像越大,要检测的像素数就越多。功能质量更好。等等……
  • @morynicz 是的,但我的意思是“两个输入图像的比例必须大致相同”或“模板图像的大小必须至少是文档图像”。我不知道,这种断言的某种后果......
  • 要知道对图片做了哪些变换,需要分析modules/ml/src/matcher.cpp的代码。第 366 和 420 行包含对 batchDistance 的调用。

标签: c++ opencv orb


【解决方案1】:
  1. 为了消除错误,您可以将图像复制并粘贴到所需大小的空图像中,但这只是断言的一种快速而肮脏的解决方案。
  2. 要使检测器和描述符正常工作,您可能需要了解它是如何工作的。也许那时您将能够获得可行的图像。在阅读this article 之后,看起来ORB 在缩放方面会遇到问题(他们在结论部分提到了它)。这意味着您需要找到一种解决方法(例如图像金字塔,或在多个比例下检查图像的其他方法)或使用另一个提取器和描述符,它是比例和旋转不变的。

【讨论】:

  • 解决方案 n°1 是不可接受的:在某些情况下,任何带有大量空白区域的小图像都被检测为匹配...解决方案 n°2 很困难:我无法确保扫描的文档将具有与我的数据库相同大小的徽标。一种解决方法是允许使用不同大小的相同徽标更新数据库。
  • 我认为您的想法是正确的。您可能想查看图像金字塔。我不是特征提取器和描述符专家,但经过一些阅读,看起来通过改变分析图像的分辨率几次来获得尺度不变性,并在每个尺度上搜索特征(如果我理解,SIFT 会这样做)正确)。
  • 拥有一个大数据库显然是要走的路:检测精度超出了我的预期!但是我仍然在某些图像上遇到错误,我仍然无法弄清楚如何避免它。
  • 好吧,我听从了您的建议,并在尝试匹配它们之前对图像进行了缩放:我摆脱了错误,而没有失去准确性。但是,解决方案不是简单的复制粘贴到空白图像上,我必须确定两个图像的比例条件:如果图像在一个方向上拉伸过大,那么我就忽略它。它适用于我的目的。感谢您为我指明正确的方向:)
  • @morynicz 我有一个类似的问题,我在这里的一个问题中问过:stackoverflow.com/questions/45534183/…。如果您能看一下,我将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
  • 1970-01-01
相关资源
最近更新 更多