C++ OpenCV CV::Mat 和 Eigen::Matrix

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14783329/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:41:39  来源:igfitidea点击:

OpenCV CV::Mat and Eigen::Matrix

c++opencveigen

提问by Yeraze

Is there a reversible way to convert an OpenCV cv::Matobject to an Eigen::Matrix?

是否有可逆的方式将 OpenCVcv::Mat对象转换为Eigen::Matrix?

e.g., Some way of doing:

例如,某种做法:

cv::Mat cvMat;
Eigen::Matrix eigMat;
camera->retrieve(cvMat);

// magic to convert cvMat to eigMat
// work on eigMat
// convert eigMat back to cvMat

imshow("Image", cvMat);

I've tried using cv2eigenand eigen2cv, but the resulting cvMatis completely mangled and I'm not exactly sure why. The dimensions are correct, but the graphics are totally trashed, so possibly a bytes-per-pixel or datasize issue?

我试过使用cv2eigenand eigen2cv,但结果cvMat完全混乱,我不确定为什么。尺寸是正确的,但图形完全被破坏了,所以可能是每像素字节或数据大小问题?

采纳答案by Pierluigi

You should consider using Eigen::Map to wrap OpenCV matrices in order to be used directly by the Eigen SDK. This allows you to apply almost all functionalities implemented in Eigen on matrix allocated by OpenCV

您应该考虑使用 Eigen::Map 来包装 OpenCV 矩阵,以便由 Eigen SDK 直接使用。这允许您将 Eigen 中实现的几乎所有功能应用到 OpenCV 分配的矩阵上

In particular you simply instantiate an Eigen::Map providing the pointer to the cv::Mat buffer:

特别是,您只需实例化一个 Eigen::Map 提供指向 cv::Mat 缓冲区的指针:

//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() ); 

for more information on Eigen::Map take a look at Eigen Tutorial: Map Class

有关 Eigen::Map 的更多信息,请查看 Eigen 教程:地图类

回答by CodeFinder

You can also use

你也可以使用

void eigen2cv(const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, Mat& dst)

and

void cv2eigen(const Mat& src, Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst)

from #include <opencv2/core/eigen.hpp>.

#include <opencv2/core/eigen.hpp>.

回答by Ela782

You can map arbitrary matrices between Eigen and OpenCV (without copying data).

您可以在 Eigen 和 OpenCV 之间映射任意矩阵(无需复制数据)。

You have to be aware of two things though:

不过,你必须注意两件事:

  • Eigen defaults to column-major storage, OpenCV stores row-major. Therefore, use the Eigen::RowMajor flag when mapping OpenCV data.

  • The OpenCV matrix has to be continuous (i.e. ocvMatrix.isContinuous() needs to be true). This is the case if you allocate the storage for the matrix in one go at the creation of the matrix (e.g. as in my example below, or if the matrix is the result of a operation like Mat W = A.inv();)

  • Eigen 默认为列优先存储,OpenCV 存储行优先。因此,在映射 OpenCV 数据时使用 Eigen::RowMajor 标志。

  • OpenCV 矩阵必须是连续的(即 ocvMatrix.isContinuous() 需要为真)。如果您在创建矩阵时一次性为矩阵分配存储,就会出现这种情况(例如,在我下面的示例中,或者如果矩阵是像 Mat W = A.inv(); 这样的操作的结果)

Example:

例子:

Mat A(20, 20, CV_32FC1);
cv::randn(A, 0.0f, 1.0f); // random data

// Map the OpenCV matrix with Eigen:
Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> A_Eigen(A.ptr<float>(), A.rows, A.cols);

// Do something with it in Eigen, create e.g. a new Eigen matrix:
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> B = A_Eigen.inverse();

// create an OpenCV Mat header for the Eigen data:
Mat B_OpenCV(B.rows(), B.cols(), CV_32FC1, B.data());

For multi-channel matrices (e.g. images), you can use 'Stride' exactly as Pierluigi suggested in his comment!

对于多通道矩阵(例如图像),您可以完全按照 Pierluigi 在他的评论中建议的那样使用“Stride”!

回答by GPrathap

This works for me,

这对我有用,

  #include <opencv2/core/eigen.hpp>

  cv::Mat image;
  image = cv::imread("/dataset/images/15207_angle_image.jpg", CV_LOA D_IMAGE_GRAYSCALE);   // Read the file
  Eigen::Matrix<float,Eigen::Dynamic, Eigen::Dynamic> eigen_mat;
  cv::cv2eigen(image, eigen_mat);

回答by Benjamin J?hn

Pierluigi's version has not worked for me completely for 3 channel images! After some investigation I ended with the following solution which has worked for me:

对于 3 通道图像,Pierluigi 的版本对我来说并不完全适用!经过一番调查,我以以下对我有用的解决方案结束:

using namespace Eigen;

constexpr uint32_t height = 3;
constexpr uint32_t width = 7;

cv::Mat img(height, width, CV_32FC3, cv::Scalar(1.0f, 2.0f, 3.0f));

using MatrixXfRowMajor = Matrix<float, Dynamic, Dynamic, RowMajor>;
using C3Stride = Stride<Dynamic, 3>;
C3Stride c3Stride(width *3,3);


using cvMap = Map<MatrixXfRowMajor, Unaligned, C3Stride >;
cvMap imgC1(reinterpret_cast<float*>(img.data) + 0, img.rows, img.cols, c3Stride);
cvMap imgC2(reinterpret_cast<float*>(img.data) + 1, img.rows, img.cols, c3Stride);
cvMap imgC3(reinterpret_cast<float*>(img.data) + 2, img.rows, img.cols, c3Stride);

std::cout << imgC1 << std::endl << std::endl;
std::cout << imgC2 << std::endl << std::endl;
std::cout << imgC3 << std::endl << std::endl;