Ask Your Question
0

Fill a vector<vector<Mat>>

asked 2017-07-31 05:58:28 -0600

Alvaro gravatar image

I want to fill a vector<vector<mat>> B with a Mat dest, this matrix will change in a for loop. The problem is B[0][0] is the same that B[last_number][last_numer]. Here is the code:

vector<vector<Mat>> B;
for (int i = 0; i<2; i++) {
    B.push_back(vector<Mat>());
    for (int j = 0; j < 3; j++)
        B[i].push_back(Mat::zeros(10, 10, CV_64F));
}

Mat dest = Mat::ones(10, 10, CV_64F);
for (int i = 0; i<2; i++) {
    for (int j = 0; j < 3; j++)
    {
        dest = 2 * dest;
        B[i][j] = dest;
    }
}

cout << B[0][0];

An this is the output:

[64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64;
 64, 64, 64, 64, 64, 64, 64, 64, 64, 64]
edit retag flag offensive close merge delete

Comments

as berak has well explained your problem is shallow copy. Here I would just suggest a different method to declare your matrix. You might avoid push_backwhich causes an automatic reallocation of the allocated storage space. When it's possible I prefer to construct a container with N x M elements like below:

int rows = 2; int cols = 3; 
vector<vector <Mat>> B(rows, vector<Mat>(cols)); //rows x cols matrix of cv::Mat
Mat dest = Mat::ones(10, 10, CV_64F);
for (int r = 0; r<rows; r++)
    for (int c = 0; c < cols; c++) {
        dest *= 2;
        dest.copyTo(B[r][c]);
    }
pklab gravatar imagepklab ( 2017-07-31 11:46:42 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
2

answered 2017-07-31 07:03:43 -0600

berak gravatar image

yea, careful there ..

if you do something simple as Mat A,B; A=B; , then this is a shallow copy, then both Mats will point to the same data ! (another one, my favourite: vector<Mat> T(10,Mat(1,1,0)); same problem !)

here's a simplified example:

Mat A(1,1,CV_32F,1.0f);
Mat B = A;
cerr << A << " " << B << endl;
A = 3;
cerr << A << " " << B << endl;

[1] [1]
[3] [3] // yea, both.

to achieve a deep copy, use B=A.clone() or A.copyTo(B)

in your example above, you unfortunately reassign dest to itself (and then to B), so all your B's are indeed the same.

remedy:

either do a clone() (expensive):

for (int i = 0; i<2; i++) {
    for (int j = 0; j < 3; j++)  {
        dest = 2 * dest;
        B[i][j] = dest.clone();

or avoid the situation, by creating a new Mat header (the temp result from the multiplication):

for (int i = 0; i<2; i++) {
    for (int j = 0; j < 3; j++)  {
        B[i][j] = dest * (1<<((i+1)*(j+1)));
edit flag offensive delete link more

Comments

@berak To underline side effect of shallow copy It's never enough Tank you !

But, are you sure 2nd option is less expensive ? The point here is that new data must be allocated and assigned for each Mat in B. This is the expensive part which happens either with clone or within temp result. In addiction creating new mat header for the temp result introduces useless overhead.

For sure using clone or copyTo is much more clean and general solution.

pklab gravatar imagepklab ( 2017-07-31 11:27:43 -0600 )edit
1

@pklab , i thould a) would be: per-element mult, then make a new Mat, and copy over, b) would be: make a new Mat, initialize each element. i think, it saves a copy.

but right, it should be: dest.copyTo(B[i][j]); so it can reuse an existing B Mat

berak gravatar imageberak ( 2017-07-31 11:44:19 -0600 )edit
1

ok, user says matrix will change in a for loop maybe his dest *= 2 is just a test. What in case of dest is a video frame or something else ?

pklab gravatar imagepklab ( 2017-07-31 11:57:35 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2017-07-31 05:58:28 -0600

Seen: 2,704 times

Last updated: Jul 31 '17