2013-02-09 263 views
20

是否有可逆方式將OpenCV cv::Mat對象轉換爲Eigen::MatrixOpenCV CV :: Mat和Eigen :: Matrix

例如,在做的一些方式:

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

我使用cv2eigeneigen2cv,但由此產生的cvMat試圖完全是錯位的,我不知道是什麼原因。尺寸是正確的,但圖形完全被丟棄,所以可能是每像素或數據大小的問題?

回答

19

您應該考慮使用Eigen :: Map來包裝OpenCV矩陣,以便由Eigen SDK直接使用。 這可以讓你幾乎適用於所有功能由OpenCV的分配矩陣徵實施

特別是只需要簡單的徵::地圖提供的指針CV ::墊緩衝:

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

爲在本徵::地圖更多信息看一看 Eigen Tutorial: Map Class

+0

完美,這幾乎正是我所期待的。當使用多通道圖像(RGB,YUV或任何其他通道組合)時,您如何最好地轉換它?每個通道有單獨的矩陣?進入widthXheightXchannels的3D矩陣?或者只是擴大它的寬度(寬* 3)*高? – Yeraze 2013-02-14 15:50:10

+8

多通道圖像通常存儲爲交錯陣列(例如RGBRGBRGB ...)。根據你想要對它們做什麼,你可能會考慮將每個單獨的通道映射到一個不同的Eigen :: Map,它利用了步長參數: 'cv :: Mat cvT(4,4,CV_32FC3); // 3通道浮點矩陣 Eigen :: Map > red(cvT.data); Eigen :: Map > green(cvT.data +1); Eigen :: Map > blue(cvT.data +2);' – Pierluigi 2013-02-15 10:55:26

+0

使用cvT.data()不起作用,給我一個編譯器錯誤。我發表了一個關於如何在下面做的答案,包括如何爲任意大小的矩陣和從Eigen到OpenCV的反向轉換的信息。 – Ela782 2014-02-11 16:02:24

41

您還可以使用

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

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

#include <opencv2/core/eigen.hpp>

18

您可以在Eigen和OpenCV之間映射任意矩陣(無需複製數據)。

你必須要知道的,雖然兩件事情:

  • 徵默認爲列爲主的存儲,存儲OpenCV的行爲主。因此,在映射OpenCV數據時使用Eigen :: RowMajor標誌。

  • OpenCV矩陣必須是連續的(即ocvMatrix.isContinuous()需要爲真)。如果您在創建矩陣時一次性爲矩陣分配存儲空間(例如,如下例所示,或矩陣是Mat W = A.inv();等操作的結果),那麼就是這種情況。

例子:

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

對於多通道矩陣(如圖像),可以使用「跨越論」正是因爲皮耶路易吉在他的評論中建議!

0

Pierluigi的版本並沒有完全適用於我的3頻道圖像!經過一番調查後,我結束了以下解決方案,它已爲我工作:

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;