2014-11-03 3 views
2

Я пытался извлечь контурные линии из изображения, используя OpenCV 2.4.9.
Функция findContours выполняет большую часть работы, но возвращает контурные линии
как тип vector < vector <Point> >. Мне нужно их преобразовать в тип vector <Mat> для последующего использования.
Я использовал конструктор класса Mat, чтобы выполнить эту работу, и все работает нормально, пока я не передам результат от одной функции к другой через вызов по ссылке. Следующий код воспроизводит ошибку:OpenCV: преобразование вектора <вектор <Point>> в вектор <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. Для разных входных изображений я либо получаю сообщение, которое говорит мне, что .exe работает некорректно и должен выйти, либо значения действительно распечатываются, но они отличаются от вывода функции getCont (в основном, I получить отрицательные значения, так что похоже, что есть переполнение). Я использую Visual Studio 2013 Express для Windows 8, 64-битной машины (но я использую библиотеки DLL x86 для OpenCV). Может ли кто-нибудь воспроизвести ошибку в другой системе?

Я думал, что был какой-то неявный тип, поэтому я распечатал размер и тип cLines в getCont и 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); 
} 

Кто-нибудь знает, что происходит?

+0

Не должно ли объявление 'cLines' быть похоже на' Mat currLine (currPts.size(), 1, CV_32SC2); '? В основном, нигде он не говорит 'CV_32SC2'. –

+0

@ a-Jays: Спасибо за ваш ответ. Я не устанавливаю явно тип, когда объявляю cLines, но вывод cLines [0] .type() равен 12 (это CV_32SC2 в перечислении), как в main, так и в getCont. – Kuchenschaf

+0

Хорошо работает для меня. Вы загрузили изображение успешно? Вы можете попробовать «imshow» его проверить. – herohuyongtao

ответ

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); 

online documentation для резюме :: Мастут конструкторы гласит:

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.

Вам нужно сделать:

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

В противном случае вектор выйдет за рамки, когда вы вернетесь к main и буферу данных r для vector<vector<Point>> contours, объявленного в getCont, будет освобожден.

Для cv::Vec, Point_ и Point3_, по умолчанию для copyData правда, в отличие от std::vector.

Смежные вопросы