6

I found that Eigen's Matrix is default column-major, which is like MATLAB, but how do I initialize an Eigen::MatrixXd from an cv::Mat? The following code is my test. But none of them could be compiled successfully. Could someone give me some advice, please? or some other links? Thanks.

    cv::Mat A_M=cv::Mat(rows, cols, CV_64FC1);
    double *A=(double *)A_M.data();
    typedef Map<MatrixXd> MapMat;
    MapMat A_eigen(A,m,n);

    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> A_eigen;
    Eigen::Map<Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> >(A,m,n) = A_eigen;

Updated:

    double *A=(double *)A_M.data();//m*n
    double *B=(double *)B_M.data();//n*p
    double *C=(double *)C_M.data();//m*p
    //regular Eigen Matrix
    Eigen::MatrixXd A_eigenMat;
    Eigen::MatrixXd B_eigenMat;
    Eigen::MatrixXd C_eigenMat;
    Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > A_mappedMat (A, m, n);
    Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > B_mappedMat (B, n, p);
    Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > C_mappedMat (C, m, p);
    // Eigen handles the conversion from row major to column major
    A_eigenMat = A_mappedMat;
    B_eigenMat = B_mappedMat;
    C_eigenMat = C_mappedMat;

    // multiplication
    C_eigenMat=A_eigenMat*B_eigenMat;

Then, when I output the M_C, its result is wrong. It seems the C_eigenMat didn't copy the data into M_C.data.

mining
  • 3,557
  • 5
  • 39
  • 66

2 Answers2

5

Sample from Conversion between OpenCV and Eigen:

cv::Mat_<float> a = Mat_<float>::ones(2,2);
Eigen::Matrix<float,Dynamic,Dynamic> b;
cv2eigen(a,b);

It is already answered on SO:

//allocate memory for a 4x4 float matrix
cv::Mat cvT(4,4,CV_32FC1); 

//directly use the buffer allocated by OpenCV
Eigen::Map<Matrix4f> eigenT( cvT.data() ); 

and in one more SO post

Community
  • 1
  • 1
MikroDel
  • 6,705
  • 7
  • 39
  • 74
  • Thanks very much for so fast reply! and The Right answer. – mining Oct 01 '13 at 12:33
  • @MikroDel could I add a small relevant question? it looks like Eigen dynamic Matrix is being used. It's convenient but will it affect performance speed significantly? in case, matrix is an image size e.g. 640x480? Thank you! – TSL_ Apr 10 '16 at 10:46
5

MikroDel's answer uses OpenCV's functionality, but cv2eigen includes a copy of the data, which is not optimal if you just want to map the data pointer. Using Eigen::Map<> is normally a better option. I modified your code, this example works:

int main(int argc, char *argv[]) {
  int rows = 4, cols = 3;
  cv::Mat A_M=cv::Mat::eye(rows, cols, CV_64FC1);
  A_M.at<double>(0,2) = 10;
  double *A=(double *)A_M.data;
  //regular Eigen Matrix
  Eigen::MatrixXd eigenMat;

  Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> > mappedMat (A,rows, cols);
  // Eigen handles the conversion from row major to column major
  eigenMat = mappedMat;   

  std::cout << A_M << std::endl;
  std::cout << eigenMat << std::endl;
  return 0;
}
user1906
  • 2,310
  • 2
  • 20
  • 37
  • Thanks, this is what I really means. but I have tested with the code MikroDel given, no error. And I did not view the source code of cv2eigen, if this function need to copy data, it is very inefficient. Your answer is really what I want to do. I don't want to copy data, just let the Eigen use the Mat::data() buffer. So it should save memory use. – mining Oct 03 '13 at 00:49
  • It seems the `cv2eigen` function has no data copy. And I have tested your given code, seems `eigenMatC_MxP=eigenMatA_MxN * eigenMatB_NxP` has wrong result. Anything wrong? – mining Oct 03 '13 at 01:12
  • cv2eigen does have a data copy in the `transpose()` call (or `convertTo()`, depending on the options). Please paste the code you are using that give the wrong result. – user1906 Oct 03 '13 at 02:09
  • I can't try to fix code without seeing it, please paste it here (or update the question) – user1906 Oct 03 '13 at 05:02
  • The code works. Note that the line `A_eigenMat = A_mappedMat;` makes a copy of the matrix, the data is not shared, as in OpenCV. So your results will not be stored in C_mappedMat; More importantly, Eigen works in both row and column major (although column major is the default). If you want to just make the multiplication in Eigen, simply do:`C_mappedMat = A_mappedMat * B_mappedMat;` – user1906 Oct 03 '13 at 05:27
  • Yeah, the code works now. I just found that I have made `A_mappedMat = B_mappedMat * C_mappedMat;`, so it of course didn't work. Thanks, man. – mining Oct 03 '13 at 07:48