2013-02-09 25 views
20

Esiste un modo reversibile per convertire un oggetto OpenCV cv::Mat in un Eigen::Matrix?OpenCV CV :: Mat ed Eigen :: Matrix

per esempio, un certo senso di fare:

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

Ho provato con cv2eigen e eigen2cv, ma la risultante cvMat è completamente maciullato e io non sono esattamente sicuro perché. Le dimensioni sono corrette, ma la grafica è totalmente tratteggiata, quindi probabilmente un problema di byte per pixel o di dati?

risposta

19

Si dovrebbe considerare l'utilizzo di Eigen :: Map per avvolgere le matrici OpenCV per poter essere utilizzate direttamente da Eigen SDK. Ciò consente di applicare quasi tutte le funzionalità implementate in Eigen su matrice allocata da OpenCV

In particolare è sufficiente istanziare un Eigen :: Mappa fornire il puntatore al cv :: Mat buffer:

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

per maggiori informazioni su Eigen :: Mappa dare un'occhiata a Eigen Tutorial: Map Class

+0

Perfetto, è praticamente esattamente quello che stavo cercando. Quando si utilizza un'immagine multicanale (RGB, YUV o qualsiasi altra combinazione di canali), come si converte meglio? Una matrice separata per canale? In una matrice 3D di widthXheightXchannels? O semplicemente espandilo per larghezza (larghezza * 3) * altezza? – Yeraze

+8

Le immagini del canale Mulit vengono generalmente memorizzate come array interfogliati (ad esempio RGBRGBRGB ...).A seconda di ciò che si vorrebbe fare con essi, si potrebbe considerare di mappare ogni singolo canale su un diverso Eigen :: Map che sfrutta il parametro passo: 'cv :: Mat cvT (4,4, CV_32FC3); // a 3 canali float matrix Eigen :: Map > red (cvT.data); Eigen :: Map > green (cvT.data +1); Eigen :: Map > blue (cvT.data +2); ' – Pierluigi

+0

L'utilizzo di cvT.data() non funziona per me, fornisce un errore del compilatore. Ho postato una risposta su come lo faccio qui sotto, comprese le informazioni su come farlo per matrici di dimensioni arbitrarie e con la conversione inversa da Eigen a OpenCV. – Ela782

41

È inoltre possibile utilizzare

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

e

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

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

18

È possibile mappare matrici arbitrarie tra Eigen e OpenCV (senza copiare i dati).

dovete essere consapevoli di due cose però:

  • Eigen default stoccaggio column-major, negozi OpenCV row-major. Pertanto, utilizzare il flag Eigen :: RowMajor quando si mappano i dati OpenCV.

  • La matrice OpenCV deve essere continua (vale a dire ocvMatrix.isContinuous() deve essere true). Questo è il caso se si assegna la memoria per la matrice in un colpo solo alla creazione della matrice (es. Come nel mio esempio qui sotto, o se la matrice è il risultato di un'operazione come Mat W = A.inv();)

Esempio:

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

per le matrici multicanale (ad esempio immagini), si può usare 'Stride' esattamente come Pierluigi suggerito nel suo commento!

0

La versione di Pierluigi non ha funzionato completamente per le immagini a 3 canali! Dopo alcune indagini ho finito con la seguente soluzione che ha funzionato per me:

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;