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?
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
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>
.
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!
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;