How to map/built the c++ vector from the eigen matrix? - c++

MatrixXf A = MatrixXf::Random(3, 3);
MatrixXf B = A.row(1);
std::vector<float> vec;
I want to built the vector "vec" with elements from the row Eigen matrix "B". Something like this "vec=B.data()"

In addition to the obvious answer (manual push_backs or pre-allocation + index-by-index assignment), you can initialize it directly using the base pointer returned by ::data():
Eigen::MatrixXf A = Eigen::MatrixXf::Random(3, 3);
Eigen::MatrixXf B = A.row(1);
std::vector<float> vec(B.data(), B.data() + B.size());
Just be careful that Eigen may use memory alignment to take advantage of SSE-family instructions, so it may not work correctly with higher dimensions.

Just use a loop:
MatrixXf A = MatrixXf::Random(3, 3);
MatrixXf B = A.row(1);
std::vector<float> vec(B.size());
for(size_t row=0; row < vec.size(); row++) {
vec[row] = B[row];
}

Related

copying elements from an opencv matrix to a eigen matrix

I have a std::vector filled with 3x3 opencv matrices. I want to unfold the matrices and write them in a 9xn eigen::matrix.
std::vector<cv::Mat1d> cvMatrix;
// some code that generates a std::vector with 3880 cv matrices, the cv matrices have the size 3x3
Eigen::Matrix<double, Eigen::Dynamic, 9> eigenMatrix;
for (int i = 0; i < curvatures.size(); i++) {
eigenMatrix.resize(i + 1, 9);
for (int j = 0; j < 9; j++) {
eigenMatrix(i, j) = cvMatrix[i](j / 3, j % 3);
}
}
If I check the elements right after they are written (e.g. printing the values of eigenMatrix if i==10) everything seems to be find, but after the for loop is finished that does not hold anymore. Most of the elements in eigenMatrix seem to contain zeros. Does anyone can explain what happens here?
eigenMatrix.resize(i + 1, 9); destroys the content of eigenMatrix.
Since you already know the final dimension at the beginning, just write
Eigen::Matrix<double, Eigen::Dynamic, 9> eigenMatrix;
eigenMatrix.resize(curvatures.size(), 9);
or even just
Eigen::Matrix<double, Eigen::Dynamic, 9> eigenMatrix(curvatures.size(), 9);
before starting the for-loop.
If you need to resize a matrix, but keep the content, you can use conservativeResize() -- but that should be avoided since it requires a full copy for each resizing.

Initialize Eigen matrix from multiple existing matrices [duplicate]

I have two eigen matrices and I would like to concatenate them, like in matlab cat(0, A, B)
Is there anything equivalent in eigen?
Thanks.
You can use the comma initializer syntax for that.
Horizontally:
MatrixXd C(A.rows(), A.cols()+B.cols());
C << A, B;
Vertically:
// eigen uses provided dimensions in declaration to determine
// concatenation direction
MatrixXd D(A.rows()+B.rows(), A.cols()); // <-- D(A.rows() + B.rows(), ...)
D << A, B; // <-- syntax is the same for vertical and horizontal concatenation
For readability, one might format vertical concatenations with whitespace:
D << A,
B; // <-- But this is for readability only.
I'd use Eigen's block indexing in a way similar to this post (which concatenates to an existing matrix).
The block indexing avoids the direction ambiguity in the accepted approach, and is pretty compact syntax. The following is equivalent to C = cat(2, A, B) in MATLAB:
MatrixXd C(A.rows(), A.cols()+B.cols());
C.leftCols(A.cols()) = A;
C.rightCols(B.cols()) = B;
I had a slightly different use case: To vertically stack a std::vector of Eigen matrices. Here is how I implemented a function which is more general purpose. Let me know if this can be further improved:
// matrix_eig = Eigen::MatrixXf in RowMajor format
matrix_eig VStack(const std::vector<matrix_eig> &mat_vec) {
assert(!mat_vec.empty());
long num_cols = mat_vec[0].cols();
size_t num_rows = 0;
for (size_t mat_idx = 0; mat_idx < mat_vec.size(); ++mat_idx) {
assert(mat_vec[mat_idx].cols() == num_cols);
num_rows += mat_vec[mat_idx].rows();
}
matrix_eig vstacked_mat(num_rows, num_cols);
size_t row_offset = 0;
for (size_t mat_idx = 0; mat_idx < mat_vec.size(); ++mat_idx) {
long cur_rows = mat_vec[mat_idx].rows();
vstacked_mat.middleRows(row_offset, cur_rows) = mat_vec[mat_idx];
row_offset += cur_rows;
}
return vstacked_mat;
}

C++ : Create 3D array out of stacking 2D arrays

In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
Is there any way to do this in C++?
In particular, I have loaded a image into a Mat variable with OpenCV like:
cv::Mat im = cv::imread("image.png", 0);
I would like to make a 3D array/Mat of N layers by stacking copies of that Mat variable.
EDIT: This new 3D matrix has to be "travellable" by adding an integer to any of its components, such that if I am in the position (x1,y1,1) and I add +1 to the last component, I arrive to (x1,y1,2). Similarly for any of the coordinates/components of the 3D matrix.
SOLVED: Both answers from #Aram and #Nejc do exactly what expected. I set #Nejc 's answer as the correct one for his shorter code.
The Numpy function vstack returns a contiguous array. Any C++ solution that produces vectors or arrays of cv::Mat objects does not reflect the behaviour of vstack in this regard, becase separate "layers" belonging to individual cv::Mat objects will not be stored in contiguous buffer (unless a careful allocation of underlying buffers is done in advance of course).
I present the solution that copies all arrays into a three-dimensional cv::Mat object with a contiguous buffer. As far as the idea goes, this answer is similar to Aram's answer. But instead of assigning pixel values one by one, I take advantage of OpenCV functions. At the beginning I allocate the matrix which has a size N X ROWS X COLS, where N is the number of 2D images I want to "stack" and ROWS x COLS are dimensions of each of these images.
Then I make N steps. On every step, I obtain the pointer to the location of the first element along the "outer" dimension. I pass that pointer to the constructor of temporary Mat object that acts as a kind of wrapper around the memory chunk of size ROWS x COLS (but no copies are made) that begins at the address that is pointed-at by pointer. I then use copyTo method to copy i-th image into that memory chunk. Code for N = 2:
cv::Mat img0 = cv::imread("image0.png", CV_IMREAD_GRAYSCALE);
cv::Mat img1 = cv::imread("image1.png", CV_IMREAD_GRAYSCALE);
cv::Mat images[2] = {img0, img1}; // you can also use vector or some other container
int dims[3] = { 2, img0.rows, img0.cols }; // dimensions of new image
cv::Mat joined(3, dims, CV_8U); // same element type (CV_8U) as input images
for(int i = 0; i < 2; ++i)
{
uint8_t* ptr = &joined.at<uint8_t>(i, 0, 0); // pointer to first element of slice i
cv::Mat destination(img0.rows, img0.cols, CV_8U, (void*)ptr); // no data copy, see documentation
images[i].copyTo(destination);
}
This answer is in response to the question above of:
In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
This is certainly possible, you can add matrices into a vector which would be your "stack"
For instance you could use a
std::vector<cv::Mat>>
This would give you a vector of mats, which would be one slice, and then you could "layer" those by adding more slices vector
If you then want to have multiple stacks you can add that vector into another vector:
std::vector<std::vector<cv::Mat>>
To add matrix to an array you do:
myVector.push_back(matrix);
Edit for question below
In such case, could I travel from one position (x1, y1, z1) to an immediately upper position doing (x1,y1,z1+1), such that my new position in the matrix would be (x1,y1,z2)?
You'll end up with something that looks a lot like this. If you have a matrix at element 1 in your vector, it doesn't really have any relationship to the element[2] except for the fact that you have added it into that point. If you want to build relationships then you will need to code that in yourself.
You can actually create a 3D or ND mat with opencv, you need to use the constructor that takes the dimensions as input. Then copy each matrix into (this case) the 3D array
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
// Dimensions for the constructor... set dims[0..2] to what you want
int dims[] = {5, 5, 5}; // 5x5x5 3d mat
Mat m = Mat::zeros(5, 5, CV_8UC1);
for (size_t i = 0; i < 5; i++) {
for (size_t k = 0; k < 5; k++) {
m.at<uchar>(i, k) = i + k;
}
}
// Mat with constructor specifying 3 dimensions with dimensions sizes in dims.
Mat 3DMat = Mat(3, dims, CV_8UC1);
// We fill our 3d mat.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
3DMat.at<uchar>(i, k, j) = m.at<uchar>(k, j);
}
}
}
// We print it to show the 5x5x5 array.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
std::cout << (int) 3DMat.at<uchar>(i, k, j) << " ";
}
std::cout << endl;
}
std::cout << endl;
}
return 0;
}
Based on the question and comments, I think you are looking for something like this:
std::vector<cv::Mat> vec_im;
//In side for loop:
vec_im.push_back(im);
Then, you can access it by:
Scalar intensity_1 = vec_im[z1].at<uchar>(y, x);
Scalar intensity_2 = vec_im[z2].at<uchar>(y, x);
This assumes that the image is single channel.

How to initialize an empty global vector in C++

I have a general question. Hopefully, one of you has a good approach to solve my problem. How can I initialize an empty vector?
As far as I read, one has to know the size of an array at compiling time, though for vectors it is different. Vectors are stored in the heap (e.g. here: std::vector versus std::array in C++)
In my program I want to let the client decide how accurate interpolation is going to be done. That's why I want to use vectors.
The problem is: For reasons of clear arrangement I want to write two methods:
one method for calculating the coefficients of an vector and
one method which is providing the coefficients to other functions.
Thus, I want to declare my vector as global and empty like
vector<vector<double>> vector1;
vector<vector<double>> vector2;
However, in the method where I determine the coefficients I cannot use
//vector containing coefficients for interpolation
/*vector<vector<double>>*/ vector1 (4, vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++) {vector1[ii][0] = ...;
}
"nn" will be given by the client when running the program. So my question is how can I initialize an empty vector? Any ideas are appreciated!
Note please, if I call another function which by its definition gives back a vector as a return value I can write
vector2= OneClass.OneMethod(SomeInputVector);
where OneClass is an object of a class and OneMethod is a method in the class OneClass.
Note also, when I remove the comment /**/ in front of the vector, it is not global any more and throws me an error when trying to get access to the coefficients.
Use resize:
vector1.resize(4, vector<double>(nn - 1));
Use resize() function as follows:
vector<vector<double>> v;
int f(int nn){
v.resize(4);
for(int i = 0; i < 4; i++){
v[i].resize(nn - 1);
}
}
It look to me that you're actually asking how to add items to your global vector. If so this might help:
//vector containing coefficients for interpolation
for (int i = 0; i < 4; ++i)
vector1.push_back(vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++)
{
vector1[ii][0] = ...;
}
Unsure if it is what you want, but assign could be interesting :
vector<vector<double>> vector1; // initialises an empty vector
// later in the code :
vector<double> v(nn -1, 0.); // creates a local vector of size 100 initialized with 0.
vector1.assign(4, v); // vector1 is now a vector of 4 vectors of 100 double (currently all 0.)

Convert Eigen Matrix to C array

The Eigen library can map existing memory into Eigen matrices.
float array[3];
Map<Vector3f>(array, 3).fill(10);
int data[4] = 1, 2, 3, 4;
Matrix2i mat2x2(data);
MatrixXi mat2x2 = Map<Matrix2i>(data);
MatrixXi mat2x2 = Map<MatrixXi>(data, 2, 2);
My question is, how can we get c array (e.g. float[] a) from eigen matrix (e.g. Matrix3f m)? What it the real layout of eigen matrix? Is the real data stored as in normal c array?
You can use the data() member function of the Eigen Matrix class. The layout by default is column-major, not row-major as a multidimensional C array (the layout can be chosen when creating a Matrix object). For sparse matrices the preceding sentence obviously doesn't apply.
Example:
ArrayXf v = ArrayXf::LinSpaced(11, 0.f, 10.f);
// vc is the corresponding C array. Here's how you can use it yourself:
float *vc = v.data();
cout << vc[3] << endl; // 3.0
// Or you can give it to some C api call that takes a C array:
some_c_api_call(vc, v.size());
// Be careful not to use this pointer after v goes out of scope! If
// you still need the data after this point, you must copy vc. This can
// be done using in the usual C manner, or with Eigen's Map<> class.
To convert normal data type to eigen matrix type
double *X; // non-NULL pointer to some data
You can create an nRows x nCols size double matrix using the Map functionality like this:
MatrixXd eigenX = Map<MatrixXd>( X, nRows, nCols );
To convert eigen matrix type into normal data type
MatrixXd resultEigen; // Eigen matrix with some result (non NULL!)
double *resultC; // NULL pointer <-- WRONG INFO from the site. resultC must be preallocated!
Map<MatrixXd>( resultC, resultEigen.rows(), resultEigen.cols() ) = resultEigen;
In this way you can get in and out from eigen matrix. Full credits goes to http://dovgalecs.com/blog/eigen-how-to-get-in-and-out-data-from-eigen-matrix/
If the array is two-dimensional, one needs to pay attention to the storage order. By default, Eigen stores matrices in column-major order. However, a row-major order is needed for the direct conversion of an array into an Eigen matrix. If such conversions are performed frequently in the code, it might be helpful to use a corresponding typedef.
using namespace Eigen;
typedef Matrix<int, Dynamic, Dynamic, RowMajor> RowMatrixXi;
With such a definition one can obtain an Eigen matrix from an array in a simple and compact way, while preserving the order of the original array.
From C array to Eigen::Matrix
int nrow = 2, ncol = 3;
int arr[nrow][ncol] = { {1 ,2, 3}, {4, 5, 6} };
Map<RowMatrixXi> eig(&arr[0][0], nrow, ncol);
std::cout << "Eigen matrix:\n" << eig << std::endl;
// Eigen matrix:
// 1 2 3
// 4 5 6
In the opposite direction, the elements of an Eigen matrix can be transferred directly to a C-style array by using Map.
From Eigen::Matrix to C array
int arr2[nrow][ncol];
Map<RowMatrixXi>(&arr2[0][0], nrow, ncol) = eig;
std::cout << "C array:\n";
for (int i = 0; i < nrow; ++i) {
for (int j = 0; j < ncol; ++j) {
std::cout << arr2[i][j] << " ";
}
std::cout << "\n";
}
// C array:
// 1 2 3
// 4 5 6
Note that in this case the original matrix eig does not need to be stored in row-major layout. It is sufficient to specify the row-major order in Map.
You need to use the Map function again. Please see the example here:
http://forum.kde.org/viewtopic.php?f=74&t=95457
The solution with Map above segfaults when I try it (see comment above).
Instead, here's a solution that works for me, copying the data into a std::vector from an Eigen::Matrix. I pre-allocate space in the vector to store the result of the Map/copy.
Eigen::MatrixXf m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = 0;
cout << m << "\n";
// Output:
// 3 -1
// 2.5 0
// Segfaults with this code:
//
// float* p = nullptr;
// Eigen::Map<Eigen::MatrixXf>(p, m.rows(), m.cols()) = m;
// Better code, which also copies into a std::vector:
// Note that I initialize vec with the matrix size to begin with:
std::vector<float> vec(m.size());
Eigen::Map<Eigen::MatrixXf>(vec.data(), m.rows(), m.cols()) = m;
for (const auto& x : vec)
cout << x << ", ";
cout << "\n";
// Output: 3, 2.5, -1, 0
I tried this : passing the address of the element at (0,0) and iterating forward.
Eigen::Matrix<double, 3, 8> coordinates3d;
coordinates3d << 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0;
double *p = &coordinates3d(0,0);
std::vector<double> x2y2;
x2y2.assign(p, p + coordinates3d.size());
for(int i=0;i < coordinates3d.size(); i++) {
std::cout <<x2y2[i];
}
This is the output : 001011111101000010110100
The data is stored row-major it seems
ComplexEigenSolver < MyMatrix > es;
complex<double> *eseig;
es.compute(H);
es.eigenvalues().transpose();
eseig=(complex<double> *)es.eigenvalues().data();