2013-02-09 261 views
20

是否有可逆方式将OpenCV cv::Mat对象转换为Eigen::MatrixOpenCV CV :: Mat和Eigen :: Matrix

例如,在做的一些方式:

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

我使用cv2eigeneigen2cv,但由此产生的cvMat试图完全是错位的,我不知道是什么原因。尺寸是正确的,但图形完全被丢弃,所以可能是每像素或数据大小的问题?

回答

19

您应该考虑使用Eigen :: Map来包装OpenCV矩阵,以便由Eigen SDK直接使用。 这可以让你几乎适用于所有功能由OpenCV的分配矩阵征实施

特别是只需要简单的征::地图提供的指针CV ::垫缓冲:

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

为在本征::地图更多信息看一看 Eigen Tutorial: Map Class

+0

完美,这几乎正是我所期待的。当使用多通道图像(RGB,YUV或任何其他通道组合)时,您如何最好地转换它?每个通道有单独的矩阵?进入widthXheightXchannels的3D矩阵?或者只是扩大它的宽度(宽* 3)*高? – Yeraze 2013-02-14 15:50:10

+8

多通道图像通常存储为交错阵列(例如RGBRGBRGB ...)。根据你想要对它们做什么,你可能会考虑将每个单独的通道映射到一个不同的Eigen :: Map,它利用了步长参数: 'cv :: Mat cvT(4,4,CV_32FC3); // 3通道浮点矩阵 Eigen :: Map > red(cvT.data); Eigen :: Map > green(cvT.data +1); Eigen :: Map > blue(cvT.data +2);' – Pierluigi 2013-02-15 10:55:26

+0

使用cvT.data()不起作用,给我一个编译器错误。我发表了一个关于如何在下面做的答案,包括如何为任意大小的矩阵和从Eigen到OpenCV的反向转换的信息。 – Ela782 2014-02-11 16:02:24

41

您还可以使用

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

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

#include <opencv2/core/eigen.hpp>

18

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

你必须要知道的,虽然两件事情:

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

  • OpenCV矩阵必须是连续的(即ocvMatrix.isContinuous()需要为真)。如果您在创建矩阵时一次性为矩阵分配存储空间(例如,如下例所示,或矩阵是Mat W = A.inv();等操作的结果),那么就是这种情况。

例子:

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

对于多通道矩阵(如图像),可以使用“跨越论”正是因为皮耶路易吉在他的评论中建议!

0

Pierluigi的版本并没有完全适用于我的3频道图像!经过一番调查后,我结束了以下解决方案,它已为我工作:

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;