OpenCV特征检测和匹配-绘制匹配时出现段错误

4

这个示例之后,我正在尝试构建一个识别视频中物体的应用程序。
我的程序由以下步骤组成(请参见每个步骤的代码示例):

  1. 将要识别的对象的图像读入cv::Mat对象中。
  2. 检测对象中的关键点并计算描述符。
  3. 读取视频的每一帧,
  4. 检测每一帧的关键点并计算描述符,
  5. 将帧的描述符与对象的描述符进行匹配,
  6. 绘制结果。

问题:第6步导致分段错误(请参见下面的代码)。
问题:是什么原因导致了这个错误,如何修复它?

谢谢!

注:

  1. 在段错误之前,该程序运行了几帧。崩溃发生在第23帧,这是视频中第一个有内容的帧(即不完全为黑色的帧)。
  2. 通过删除drawMatches(...);的行,没有崩溃。
  3. 在Windows 7、OpenCV 2.4.2和MinGW上运行。

调试尝试:

通过gdb运行程序会产生以下消息:

Program received signal SIGSEGV, Segmentation fault.
0x685585db in _fu156___ZNSs4_Rep20_S_empty_rep_storageE () from c:\opencv\build\install\bin\libopencv_features2d242.dll

步骤1 - 读取对象的图像:

Mat object;
object = imread(OBJECT_FILE, CV_LOAD_IMAGE_GRAYSCALE);

第二步 - 检测对象中的关键点并计算描述符:

SurfFeatureDetector detector(500);
SurfDescriptorExtractor extractor;
vector<KeyPoint> keypoints_object;
Mat descriptors_object;
detector.detect(object , keypoints_object);
extractor.compute(object, keypoints_object, descriptors_object);

步骤3-6:

VideoCapture capture(VIDEO_FILE);
namedWindow("Output",0);
BFMatcher matcher(NORM_L2,true);
vector<KeyPoint> keypoints_frame;
vector<DMatch> matches;
Mat frame,
    output,
    descriptors_frame;

while (true)
{
    //step 3:
    capture >> frame;
    if(frame.empty())
    {
        break;
    }
    cvtColor(frame,frame,CV_RGB2GRAY);

    //step 4:
    detector.detect(frame, keypoints_frame);
    extractor.compute(frame, keypoints_frame, descriptors_frame);

    //step 5:
    matcher.match(descriptors_frame, descriptors_object, matches);

    //step 6:
    drawMatches(object, keypoints_object, frame, keypoints_frame, matches, output);
    imshow("Output", output);
    waitKey(1);
}
段错误前的截屏: 截屏 第22帧(完全黑色): 第22帧 第23帧(发生段错误的帧): 第23帧
2个回答

5
问题出在drawMatches参数的顺序上。
正确的顺序如下:
drawMatches(frame, keypoints_frame, object, keypoints_object, matches, output);
解释:

在第5步中,我正在使用匹配器对象的match方法:

matcher.match(descriptors_frame, descriptors_object, matches);

这个方法的签名可以在这里找到。
void match( const Mat& queryDescriptors, const Mat& trainDescriptors,
            CV_OUT vector<DMatch>& matches, const Mat& mask=Mat() ) const;

这意味着matches包含了从trainDescriptorsqueryDescriptors的匹配项。
在我的情况下,训练描述符是object,查询描述符是frame,因此matches包含了从objectframe的匹配项。

drawMatches签名为:

void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
                  const Mat& img2, const vector<KeyPoint>& keypoints2,
                  const vector<DMatch>& matches1to2,
                  ... );

当使用错误的参数顺序调用drawMatches时:

drawMatches(object, keypoints_object, frame, keypoints_frame, matches, output);

该方法在错误的图像中寻找匹配项的坐标,这可能导致尝试访问“越界”像素;因此出现了分割错误。

0

你尝试在调试器中运行程序了吗?

猜测一下,如果没有可绘制的匹配项,drawmatch 就会崩溃? 试试在调用 drawMatches 之前添加 if(!matches.empty())。顺便问一下,你确定在调用 matcher.matches(...) 之前已清空 matches 吗? 如果没有,请在每次循环迭代时手动清除。


谢谢您的回复。是的,我尝试通过调试器运行程序,但由于我正在使用OpenCV DLL,所以无法进入库的代码。我只知道问题出在drawMatches上。此外,我怀疑这不是库本身的问题;我认为我可能是在错误地使用它。另外,问题不在于matches,因为还有其他空帧,在其中matches为空,并且问题不会发生。顺便说一下,我每次迭代都会清空matches对象(虽然我认为这并不是真正必要的);我只是没有在这里写出来。 - EyalAr
1
尝试以调试模式编译OpenCV。使用CMake应该很简单。对于minGW,您应该生成Linux makefiles。但是它也可以与VC++ 2010 Express一起使用,我上周刚刚这样做了。 - remi
谢谢,这是个好主意,但实际上解决方案要简单得多,我由于注意力不够而错过了它(请看我的回答)。 - EyalAr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接