2013-02-09 81 views
20

OpenCV cv::MatオブジェクトをEigen::Matrixに変換する可逆な方法はありますか?OpenCV 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 SDKで直接使用するには、Eigen :: Mapを使用してOpenCV行列をラップすることを検討する必要があります。

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

のために: は、これは、あなたが単に固有::地図CVへのポインタを提供する::マットバッファをインスタンス化し、特に

のOpenCVによって割り当てられたマトリックス上に固有に実装され、ほぼすべての機能を適用することができます固有の詳細について::地図 Eigen Tutorial: Map Class

+0

完璧な、それは私が探していたものです。マルチチャンネル画像(RGB、YUV、またはその他のチャンネルの組み合わせ)を使用する場合は、どのように変換するのが最適でしょうか?チャネルごとに別々のマトリックス? widthXheightXchannelsの3Dマトリックスに?または、幅(幅* 3)*高さで拡大しますか? – Yeraze

+8

マルチチャンネル画像は、通常、インターリーブされた配列(例えば、RGBRGBRGB ...)として格納される。あなたがそれらで何をしたいかに応じて、各シングルチャンネルをストライドパラメータを利用する別のEigen :: Mapにマッピングすることを検討するかもしれません: 'cv :: Mat cvT(4,4、CV_32FC3); // 3チャネル浮動行列 Eigen :: Map >赤(cvT.data); Eigen :: Map >緑色(cvT.data +1); Eigen :: Map > blue(cvT.data +2); ' – Pierluigi

+0

cvT.data()を使用しても動作しません。コンパイラエラーが発生します。私は、任意のサイズの行列に対してやEigenからOpenCVへの逆変換を行う方法についての情報を含め、私が下でどのように行うかに関する答えを投稿しました。 – Ela782

41

を見てみます。また

void eigen2cv(const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, Mat& dst) 
を使用することができます #include <opencv2/core/eigen.hpp>から

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

18

(データをコピーせずに)EigenとOpenCVの間で任意の行列をマップできます。

あなたはかかわらず、二つのことに注意する必要があります:列優先ストレージへ

  • 固有のデフォルト値、行優先OpenCVの店。したがって、OpenCVデータをマッピングするときは、Eigen :: RowMajorフラグを使用します。

  • OpenCVマトリックスは連続的でなければならない(すなわち、ocvMatrix.isContinuous()が真でなければならない)。これは、行列の作成時に行列の記憶域を1つに割り当てる場合です(たとえば、下の例のように、または行列が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; 
関連する問題