2013-02-09 4 views
20

Gibt es eine reversible Möglichkeit, ein OpenCV cv::Mat Objekt in ein Eigen::Matrix Objekt zu konvertieren?OpenCV CV :: Mat und Eigen :: Matrix

zum Beispiel einen Weg zu tun:

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

Ich habe versucht, mit cv2eigen und eigen2cv, aber die resultierende cvMat ist völlig verstümmelt und ich bin mir nicht ganz sicher, warum. Die Abmessungen sind korrekt, aber die Grafiken sind völlig zerstört, also möglicherweise ein Byte pro Pixel oder Datengröße Problem?

Antwort

19

Sie sollten erwägen, mit Eigen :: Map OpenCV-Matrizen zu umhüllen, damit sie direkt vom Eigen-SDK verwendet werden können. Auf diese Weise können Sie fast alle Funktionen in Eigen auf Matrix von OpenCV

Insbesondere Sie einfach instanziiert ein Eigen :: Map bietet den Zeiger auf den cv :: Mat Puffer zugeordnet umgesetzt gelten:

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

für weitere Informationen zu Eigen :: Map zu sehen, Eigen Tutorial: Map Class

+0

Perfekt, das ist ziemlich genau das wonach ich gesucht habe. Wenn Sie ein Mehrkanalbild (RGB, YUV oder eine andere Kombination von Kanälen) verwenden, wie würden Sie es am besten konvertieren? Eine separate Matrix pro Kanal? In eine 3D-Matrix von widthXheightXchannels? Oder erweitern Sie es einfach um Breite (Breite * 3) * Höhe? – Yeraze

+8

Mulit-Channel-Bilder werden normalerweise als Interleaved-Arrays gespeichert (z. B. RGBRGBRGB ...).Abhängig davon, was Sie mit ihnen machen wollen, könnten Sie in Betracht ziehen, jeden einzelnen Kanal einer anderen Eigen :: Map zuzuweisen, die den Schrittparameter ausnutzt: 'cv :: Mat cvT (4,4, CV_32FC3); // eine 3-Kanal-Float-Matrix Eigen :: Map > rot (cvT.data); Eigen :: Map > grün (cvT.data +1); Eigen :: Map > blau (cvT.data +2); ' – Pierluigi

+0

Die Verwendung von cvT.data() funktioniert nicht für mich, gibt einen Compilerfehler. Ich habe eine Antwort darauf geschrieben, wie ich es unten mache, einschließlich Informationen, wie man es für beliebig große Matrizen macht und mit der umgekehrten Umwandlung von Eigen zu OpenCV. – Ela782

41

Sie auch

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

und

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

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

18

Sie können beliebige Matrizen zwischen Eigen und OpenCV abbilden (ohne Daten zu kopieren).

Sie haben sich aber bewusst von zwei Dinge sein:

  • Eigen standardmäßig column-Hauptspeicher, OpenCV speichert Reihe-Dur. Verwenden Sie daher beim Zuordnen von OpenCV-Daten das Eigen :: RowMajor-Flag.

  • Die OpenCV-Matrix muss kontinuierlich sein (d. H. OcvMatrix.isContinuous() muss wahr sein). Dies ist der Fall, wenn Sie bei der Erstellung der Matrix den Speicher für die Matrix auf einmal vergeben (zB wie in meinem Beispiel unten, oder wenn die Matrix das Ergebnis einer Operation wie Mat W = A.inv() ist;)

Beispiel:

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

Für Mehrkanal-Matrizen (zB Bilder), können Sie 'Stride' genau wie Pierluigi in seinem Kommentar vorgeschlagen!

0

Pierluigis Version hat bei 3-Kanal-Bildern nicht komplett funktioniert! Nach einigem Nachdenken habe ich mit folgender Lösung geendet, die bei mir funktioniert hat:

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;