Reputation: 23
I was trying to extract contour lines from an image, using OpenCV 2.4.9.
The findContours
function does most of the work, but it returns the contour lines
as type vector < vector < Point > >
.
I need to convert them to type vector < Mat >
for later uses.
I used a constructor of the Mat
class to do the job and everything works fine until I pass the result from one function to the other via call by reference.
The following code reproduces the error:
#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;
}
The error occurs in main, in the line preceding the return statement, when I try to print out the first row of the first element of cLines
. For different input images, I either get a message, which tells me, that the .exe is not working properly and has to quit or the values are actually printed out, but they differ from the output of the getCont
function (in main, I get negative values, so it looks like there is some overflow). I'm using Visual Studio 2013 Express on Windows 8, 64 bit machine (but I'm using the x86 DLL libraries of OpenCV). Can anyone reproduce the error on a different system?
I thought there was some implicit type cast, so I printed out the size and type of cLines
in getCont
and main
, but the results are the same. The error does not occur, when I put the code of the getCont
function into main
, so that I avoid the additional function call.
Also, everything works fine, when I replace the loop
for (int i = 0; i < contours.size(); i++)
cLines.push_back(Mat(contours[i]));
by the following:
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);
}
Does anyone know what's going on?
Upvotes: 2
Views: 2921
Reputation: 30589
You are using the right constructor but incorrectly accepting the default for the second parameter. The declaration for the Mat
constructor taking std::vector
as an input:
//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit Mat(const vector<_Tp>& vec, bool copyData=false);
The online documentation for the cv::Mat constructors states:
copyData
– Flag to specify whether the underlying data of the STL vector or the old-style CvMat or IplImage should be copied to (true) or shared with (false) the newly constructed matrix. When the data is copied, the allocated buffer is managed using Mat reference counting mechanism. While the data is shared, the reference counter is NULL, and you should not deallocate the data until the matrix is not destructed.
You need to do:
cLines.push_back(Mat(contours[i],true));
Otherwise the vector will go out of scope when you return to main
and the data buffer for the vector<vector<Point>> contours
declared in getCont
will have been deallocated.
For cv::Vec
, Point_
, and Point3_
, the default for copyData
is true, unlike for std::vector
.
Upvotes: 2