OpenCV:vector <vector <point>的转换&gt; to vector <mat>,引用调用的问题</mat> </vector <point>

时间:2014-11-03 10:53:05

标签: c++ opencv scope mat pass-by-reference

我试图使用OpenCV 2.4.9从图像中提取轮廓线 findContours函数执行大部分工作,但它返回轮廓线
作为类型vector < vector < Point > >。 我需要将它们转换为vector < Mat >类型以供日后使用 我使用了Mat类的构造函数来完成这项工作,一切正常,直到我通过引用调用将结果从一个函数传递给另一个函数。 以下代码重现错误:

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

void getCont(Mat& img, vector<Mat>& cLines, int thresh)
{
    //binarize the image
    Mat imgBin;
    threshold(img, imgBin, thresh, 255, THRESH_BINARY_INV);

    //find contour lines
    vector<vector<Point>> contours;
    findContours(imgBin, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    //convert vector<vector<Point>> to vector<Mat>
    for (int i = 0; i < contours.size(); i++)
        cLines.push_back(Mat(contours[i])); 

    cerr << "cLines[0] in getCont:\n";
    cerr << "cLines[0].rows: " << cLines[0].rows << "\n";
    cerr << "cLines[0].cols: " << cLines[0].cols << "\n";
    cerr << "cLines[0].channels(): " << cLines[0].channels() << "\n";
    cerr << "cLines[0].type(): " << cLines[0].type() << "\n";
    cerr << "cLines[0].row(0): " << cLines[0].row(0) << "\n";
    cerr << endl << endl;
}

int main()
{
    Mat img = imread("leaf.jpg", 0);
    int thresh = 124;

    vector<Mat> cLines;
    getCont(img, cLines, thresh);

    cerr << "cLines[0] in main:\n";
    cerr << "cLines[0].rows: " << cLines[0].rows << "\n";
    cerr << "cLines[0].cols: " << cLines[0].cols << "\n";
    cerr << "cLines[0].channels(): " << cLines[0].channels() << "\n";
    cerr << "cLines[0].type(): " << cLines[0].type() << "\n";
    cerr << "cLines[0].row(0): " << cLines[0].row(0) << "\n";

    return 0;
}

当我尝试打印cLines的第一个元素的第一行时,在return语句之前的行中的main中发生错误。对于不同的输入图像,我得到一条消息,告诉我,.exe不能正常工作并且必须退出或实际打印出值,但它们与getCont函数的输出不同(在main中,我得到负值,所以看起来有一些溢出)。我在Windows 8,64位机器上使用Visual Studio 2013 Express(但我使用的是OpenCV的x86 DLL库)。任何人都可以在不同的系统上重现错误吗?

我认为有一些隐式类型转换,所以我在cLinesgetCont中打印出main的大小和类型,但结果是相同的。当我将getCont函数的代码放入main时,不会发生错误,因此我避免了额外的函数调用。 此外,当我更换循环

时,一切正常
for (int i = 0; i < contours.size(); i++)
    cLines.push_back(Mat(contours[i])); 

通过以下内容:

for (int i = 0; i < contours.size(); i++)
{
    vector<Point> currPts = contours.at(i);
    Mat currLine(currPts.size(), 1, CV_32SC2);
    for (int j = 0; j < currPts.size(); j++)
    {
        currLine.at<Vec2i>(j, 0).val[0] = currPts.at(j).x;
        currLine.at<Vec2i>(j, 0).val[1] = currPts.at(j).y;
    }
    cLines.push_back(currLine);
}

有谁知道发生了什么事?

1 个答案:

答案 0 :(得分:2)

您正在使用正确的构造函数,但错误地接受第二个参数的默认值。以Mat作为输入的std::vector构造函数的声明:

//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit Mat(const vector<_Tp>& vec, bool copyData=false);

cv :: Mat构造函数的online documentation表示:

  

copyData - 用于指定是否应将STL向量或旧式CvMat或IplImage的基础数据复制到(true)或与新构造的矩阵共享(false)的标志。复制数据时,使用Mat引用计数机制管理分配的缓冲区。在共享数据时,引用计数器为NULL,并且在矩阵未被破坏之前不应释放数据。

你需要这样做:

cLines.push_back(Mat(contours[i],true));

否则,当您返回main时,向量将超出范围,并且vector<vector<Point>> contours中声明的getCont的数据缓冲区将被取消分配。

对于cv::VecPoint_Point3_copyData的默认设置为true,与std::vector不同。