Reputation: 105
I have a dummy question because something really weird happening. I am trying to push Mat objects to a vector. For example:
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");
}
This one doesn't work nice .In the end my vector contains the b=K+M Mat only. This is expected, i think because i push_back only the header each time and if the data change this affects both Mats in the vector.The problem is solved if i use a.push_back(b).clone instead. now when i run the code like this(change CV_32FC1 to 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");
}
the final vector contains both of the matrices i push back in.How this can happen?Maybe i haven't understand what exactly is happening to the first case either, but i can't find any other way to safely pass Mat objects to a vector(like in this case), without using the clone().
Upvotes: 3
Views: 5377
Reputation: 127
As they already say by default cv::Mat do not copy, instead they use as much as possible already allocated data, in your code b is used twice. Another solution is directly push_back(K-M)
and (K+M)
as you could see in my code. If you want to make clearly you could push_back(cv::Mat_<float>(K-M))
just to make clear you are construct a new cv::Mat
each time.
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");
}
Upvotes: 0
Reputation: 16816
In the second case, you are creating an std::vector
which should contain elements of type cv::Mat_<float>
, but you are adding elements of type cv::Mat_<unsigned char>
into it. Therefore you are facing undefined behavior.
If you are creating matrices of type CV_8UC1
, then you should put them in a vector of type std::vector< cv::Mat_<unsigned char> >
.
You can also make it generic by using the cv::Mat
type instead of cv::Mat_
.
std::vector<cv::Mat> a;
Upvotes: 3
Reputation: 4074
Changing the cv::Mat type from CV_32FC1 to CV_8UC1 does not change anything - you still did a header copy when adding to the vector. And this is expected and desired. By default, opencv avoids copying entire matrix data. If you would like to store elements in vector and they are different from each other by values you have to use clone(). It is like a proof. Let's say you are not using clone() and still want to distinguish matrices in vector by their values. It seems to me like a contradiction. Opencv Mat works like a smart pointer. It stores the data until the reference count for the variable goes 0. So safely, you can do following as you yourself noticed in the question:
b=K-M;
a.push_back(b.clone());
b=K+M;
a.push_back(b);
Upvotes: 7