OpenCV CV:: Mat et Eigen:: Matrix

Existe-t-il un moyen réversible de convertir un OpenCV cv::Mat objet Eigen::Matrix?

par exemple, une Certaine façon de faire:

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

j'ai essayé d'utiliser cv2eigen et eigen2cv, mais le résultat de l' cvMat est complètement mutilé et je ne sais pas exactement pourquoi. Les dimensions sont correctes, mais les graphismes sont totalement saccagé, peut-être un octets par pixel ou données. datasize problème?

22
demandé sur Walfie 2013-02-09 04:02:40

4 réponses

Vous devriez envisager D'utiliser Eigen:: Map pour envelopper les matrices OpenCV afin d'être utilisé directement par le SDK Eigen. Cela vous permet d'appliquer presque toutes les fonctionnalités implémentées dans Eigen sur matrix alloué par OpenCV

en particulier vous instanciez simplement un Eigen:: Map fournissant le pointeur vers le tampon 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() ); 

pour plus D'informations sur Eigen:: Map Tutorial Eigen: Map Class

23
répondu Pierluigi 2018-02-02 12:46:19

vous pouvez aussi utiliser

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

et

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

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

46
répondu CodeFinder 2013-07-03 17:29:08

Vous pouvez cartographier des matrices arbitraires entre Eigen et OpenCV (sans copier de données).

Vous devez être conscient de deux choses:

  • Eigen par défaut à la colonne-stockage majeur, OpenCV magasins ligne-majeur. Par conséquent, utilisez le drapeau eigen::RowMajor lors de la cartographie des données OpenCV.

  • la matrice OpenCV doit être continue (c.-à-d. ocvMatrix.isContinuous() doit être vrai). C'est le cas si vous allouer du stockage de la matrice on va à la création de la matrice (par exemple comme dans mon exemple ci-dessous, ou si la matrice est le résultat D'une opération comme Mat W = A. inv ();)

Exemple:

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

pour les matrices multicanaux (par exemple des images), vous pouvez utiliser 'Stride' exactement comme Pierluigi l'a suggéré dans son commentaire!

23
répondu Ela782 2014-02-11 16:00:16

la version de Pierluigi n'a pas fonctionné pour moi complètement pour 3 images de canal! Après quelques recherches, j'ai fini avec la solution suivante qui a fonctionné pour moi:

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;
0
répondu Benjamin Jähn 2017-07-12 12:09:04