2013-02-09 6 views
20

Czy istnieje odwracalny sposób przekonwertowania obiektu OpenCV cv::Mat na obiekt Eigen::Matrix?OpenCV CV :: Mat i Eigen :: Matrix

np Niektóre ze sposobów:

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

Próbowałem za pomocą cv2eigen i eigen2cv, ale wynikający cvMat jest całkowicie zniekształcone i nie jestem do końca pewien dlaczego. Wymiary są poprawne, ale grafika jest całkowicie zniszczona, a więc prawdopodobnie w bajtach na piksel lub problem z datasize?

Odpowiedz

19

Powinieneś rozważyć użycie Eigen :: Map do owinięcia macierzy OpenCV w celu użycia bezpośrednio przez Eigen SDK. To pozwala na zastosowanie niemal wszystkie funkcje zaimplementowane w Eigen na matrycy przydzielonego przez OpenCV

W szczególności po prostu instancję Eigen :: Mapa zapewniając wskaźnik do bufora 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()); 

dla więcej informacji na Eigen :: Mapa przyjrzeć Eigen Tutorial: Map Class

+0

Doskonały, dokładnie to, czego szukałem. Jeśli korzystasz z obrazu wielokanałowego (RGB, YUV lub jakiejkolwiek innej kombinacji kanałów), jak najlepiej go przekonwertować? Oddzielna matryca na kanał? Do matrycy 3D szerokości XheightXchannels? Lub po prostu rozszerzyć go o szerokość (szerokość * 3) * wysokość? – Yeraze

+8

Obrazy wielokanałowe są zwykle przechowywane jako tablice z przeplotem (np. RGBRGBRGB ...).W zależności od tego, co chcesz z nimi zrobić, możesz rozważyć mapowanie każdego kanału na inny Eigen :: Map wykorzystujący parametr kroku: 'cv :: Mat cvT (4,4, CV_32FC3); // 3-kanałowa macierz float Eigen :: Mapa > czerwona (cvT.data); Eigen :: Mapa > zielona (cvT.data +1); Eigen :: Mapa > niebieski (cvT.data +2); ' – Pierluigi

+0

Używanie cvT.data() nie działa dla mnie, powoduje błąd kompilatora. Opublikowalem odpowiedzi na temat tego, jak to zrobilam ponizej, w tym informacje jak to zrobic dla macierzy o dowolnych rozmiarach iz odwrotna konwersja z Eigen do OpenCV. – Ela782

41

można również użyć

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

i

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

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

18

Możesz mapować dowolne macierze między Eigen i OpenCV (bez kopiowania danych).

Trzeba zdawać sobie sprawę z dwóch rzeczy jednak:

  • EIGEN domyślnie przechowywania kolumnowej-dur, sklepy OpenCV row-major. Dlatego należy używać flagi Eigen :: RowMajor podczas mapowania danych OpenCV.

  • Macierz OpenCV musi być ciągła (tj. OcvMatrix.isContinuous() musi mieć wartość true). Dzieje się tak, jeśli przydzielimy pamięć macierzy za jednym razem przy tworzeniu macierzy (np. Jak w moim przykładzie poniżej lub jeśli macierz jest wynikiem operacji takiej jak Mat W = A.inv();)

Przykład:

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

Dla matryc wielokanałowych (np obrazów), można użyć 'Stride' dokładnie jak Pierluigi zasugerował w swoim komentarzu!

0

Wersja Pierluigiego nie działa dla mnie całkowicie w przypadku obrazów 3-kanałowych! Po pewnym dochodzeniu zakończyłem z następującym rozwiązaniem, które zadziałało dla mnie:

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;