web-dev-qa-db-fra.com

OpenCV CV :: Mat et Eigen :: Matrix

Existe-t-il un moyen réversible de convertir un OpenCV cv::Mat s'oppose à un Eigen::Matrix?

par exemple, une 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 cvMat résultant est complètement altéré et je ne sais pas exactement pourquoi. Les dimensions sont correctes, mais les graphiques sont totalement saccagés, donc peut-être un problème d'octets par pixel ou de taille de données?

27
Yeraze

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 la matrice allouée par OpenCV

En particulier, vous instanciez simplement une 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 jetez un oeil à Eigen Tutorial: Map Class

27
Pierluigi

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)

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

53
CodeFinder

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

Vous devez cependant être conscient de deux choses:

  • Eigen utilise par défaut le stockage sur colonne, OpenCV stocke la ligne sur ligne. Par conséquent, utilisez l'indicateur Eigen :: RowMajor lors du mappage des données OpenCV.

  • La matrice OpenCV doit être continue (c'est-à-dire que ocvMatrix.isContinuous () doit être vrai). C'est le cas si vous allouez le stockage de la matrice en une seule fois lors de 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 les images), vous pouvez utiliser 'Stride' exactement comme Pierluigi l'a suggéré dans son commentaire!

26
Ela782

La version de Pierluigi n'a pas complètement fonctionné pour moi pour les images à 3 canaux! Après quelques recherches, je me suis retrouvé 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;
1
Benjamin Jähn

Cela fonctionne pour moi,

  #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);
0
GPrathap