Copy select rows into new matrix
Asked Answered
P

4

16

I want to copy the rows 0, 2 and 4 of my matrix A into B, in this order. Let A = [a0, a1, a2, a3, a4]^T , with a_i being row-vectors, then B should be: [a0, a2, a4]^T.

The code below does what I want but I wonder whether there is a prettier solution (maybe using Eigen)?

#include <iostream>
#include <vector>
#include <opencv/cv.h>


int main(int argc, char **argv) {
    const int num_points = 5;
    const int vec_length = 3;
    cv::Mat A(num_points, vec_length, CV_32FC1);
    cv::RNG rng(0); // Fill A with random values
    rng.fill(A, cv::RNG::UNIFORM, 0, 1);
// HACK Ugly way to fill that matrix .
    cv::Mat B = cv::Mat(3,vec_length, CV_32FC1);
    cv::Mat tmp0 = B(cv::Rect(0,0,vec_length,1));
    cv::Mat tmp1 = B(cv::Rect(0,1,vec_length,1));
    cv::Mat tmp2 = B(cv::Rect(0,2,vec_length,1));
    A.row(0).copyTo(tmp0);
    A.row(2).copyTo(tmp1);
    A.row(4).copyTo(tmp2);

    std::cout << "A: " << A << std::endl;
    std::cout << "B: " << B << std::endl;
    return 0;
}
Pokorny answered 9/8, 2011 at 9:41 Comment(0)
P
19

I found push_back.

Create B with size 0 x vec_length and then use push_back to add the selected rows from A:

#include <iostream>
#include <vector>
#include <opencv/cv.h>


int main(int argc, char **argv) {
    const int num_points = 5;
    const int vec_length = 3;
    cv::Mat A(num_points, vec_length, CV_32FC1);
    cv::RNG rng(0); // Fill A with random values
    rng.fill(A, cv::RNG::UNIFORM, 0, 1);
    cv::Mat B = cv::Mat(0,vec_length, CV_32FC1);
    B.push_back(A.row(0));
    B.push_back(A.row(2));
    B.push_back(A.row(4));
    std::cout << "A: " << A << std::endl;
    std::cout << "B: " << B << std::endl;
    return 0;
}
Pokorny answered 25/8, 2011 at 11:9 Comment(1)
this is awesome! Treating cv::Mat as vectors! Thanks to the new C++ API.Nonsuit
D
27

The way in OpenCV 2.4.1 is:

A.row(0).copyTo(B.row(0));
A.row(2).copyTo(B.row(1));
A.row(4).copyTo(B.row(2));
Derman answered 8/8, 2012 at 16:36 Comment(0)
P
19

I found push_back.

Create B with size 0 x vec_length and then use push_back to add the selected rows from A:

#include <iostream>
#include <vector>
#include <opencv/cv.h>


int main(int argc, char **argv) {
    const int num_points = 5;
    const int vec_length = 3;
    cv::Mat A(num_points, vec_length, CV_32FC1);
    cv::RNG rng(0); // Fill A with random values
    rng.fill(A, cv::RNG::UNIFORM, 0, 1);
    cv::Mat B = cv::Mat(0,vec_length, CV_32FC1);
    B.push_back(A.row(0));
    B.push_back(A.row(2));
    B.push_back(A.row(4));
    std::cout << "A: " << A << std::endl;
    std::cout << "B: " << B << std::endl;
    return 0;
}
Pokorny answered 25/8, 2011 at 11:9 Comment(1)
this is awesome! Treating cv::Mat as vectors! Thanks to the new C++ API.Nonsuit
E
1

Since they are non-contiguous I don't think there's any shortcut. In this particular case you could make the code cleaner with a loop:

for (int i=0; i<3; i++) {
    cv::Mat tmp = B(cv::Rect(0,i,vec_length,1));
    A.row(i * 2).copyTo(tmp);
}
Equipment answered 9/8, 2011 at 12:53 Comment(2)
Okay, but in my case that shortcut doesn't work because I'm using different values than (0,2,4). Thanks anyway!Pokorny
Depending on your circumstance, perhaps you could build up a vector of source and destination duples. You could use a similar loop that runs through the vector and copies the source row to the destination row. Good luck!Equipment
G
0
Mat row = old.row(0);
old.row(0).copyTo(row);
new.push_back(row);
Ginny answered 10/3, 2014 at 18:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.