将Mat对象推回向量的安全方法

时间:2014-04-08 10:27:20

标签: c++ opencv vector computer-vision mat

我有一个虚假的问题,因为发生了一些非常奇怪的事情。我试图将Mat对象推送到矢量。例如:

int main()
{
vector<Mat_<float>> a;
Mat M(2,1, CV_32FC1, Scalar(100));
Mat K(2,1, CV_32FC1, Scalar(150));
Mat b;
b=K-M;
a.push_back(b);
b=K+M;
a.push_back(b);

cout<<a[0]<<endl<<endl;
cout<<a[1]<<endl<<endl;

system("pause");
}

这个不好用。最后我的矢量只包含b = K + M Mat。 这是预期的,我认为因为我每次只推送标题,如果数据发生变化,这会影响向量中的两个匹配。如果我使用a.push_back(b).clone,问题就解决了。 现在,当我运行这样的代码(将CV_32FC1更改为CV_8UC1)时:

    int main()
{
vector<Mat_<float>> a;
Mat M(2,1, CV_8UC1, Scalar(100));
Mat K(2,1, CV_8UC1, Scalar(150));
Mat b;
b=K-M;
a.push_back(b);
b=K+M;
a.push_back(b);

cout<<a[0]<<endl<<endl;
cout<<a[1]<<endl<<endl;

system("pause");
}

最终的向量包含我推回的两个矩阵。如何发生这种情况?也许我还不明白第一种情况究竟发生了什么,但我找不到任何其他方式安全地通过Mat对象到向量(就像在这种情况下),不使用clone()。

3 个答案:

答案 0 :(得分:6)

将cv :: Mat类型从CV_32FC1更改为CV_8UC1不会改变任何内容 - 添加到向量时仍然会执行标题复制。这是预期和期望的。默认情况下,opencv避免复制整个矩阵数据。如果您希望将元素存储在向量中并且它们彼此不同按值,则必须使用clone()。这就像一个证明。假设你没有使用clone(),并且仍然希望通过它们的值来区分向量中的矩阵。在我看来,这似乎是一个矛盾。 Opencv Mat就像一个智能指针。它存储数据,直到变量的引用计数为0.所以安全地,您可以按照自己在问题中注意到的方式执行以下操作:

b=K-M;
a.push_back(b.clone());
b=K+M;
a.push_back(b);

答案 1 :(得分:3)

在第二种情况下,您创建的std::vector应包含cv::Mat_<float>类型的元素,但您要在其中添加cv::Mat_<unsigned char>类型的元素。因此,您将面临未定义的行为。

如果要创建CV_8UC1类型的矩阵,则应将它们放在std::vector< cv::Mat_<unsigned char> >类型的向量中。

您也可以使用cv::Mat类型而不是cv::Mat_将其设为通用。

std::vector<cv::Mat> a;

答案 2 :(得分:0)

正如他们已经说过默认cv :: Mat不复制,而是他们尽可能多地使用已分配的数据,在你的代码中使用了两次。另一种解决方案是直接push_back(K-M)(K+M),正如您在我的代码中看到的那样。如果你想清楚地表明你可以push_back(cv::Mat_<float>(K-M))只是为了表明你每次构建一个新的cv::Mat

int main() {
    vector<Mat_<float>> a;
    Mat M(2, 1, CV_32FC1, Scalar(100));
    Mat K(2, 1, CV_32FC1, Scalar(150));
    a.push_back(K-M);
    a.push_back(K+M);

    cout << a[0] << endl << endl;
    cout << a[1] << endl << endl;

    system("pause");
}