【问题标题】:OpenCV CV::Mat and Eigen::MatrixOpenCV CV::Mat 和 Eigen::Matrix
【发布时间】:2013-02-09 00:02:40
【问题描述】:

是否有一种可逆的方式将 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 完全被破坏了,我不确定为什么。尺寸是正确的,但图形完全是垃圾,所以可能是每像素字节数或数据大小问题?

【问题讨论】:

    标签: c++ opencv eigen


    【解决方案1】:

    你也可以使用

    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 &lt;opencv2/core/eigen.hpp&gt;

    【讨论】:

      【解决方案2】:

      您应该考虑使用 Eigen::Map 来包装 OpenCV 矩阵,以便 Eigen SDK 直接使用。 这允许您在 OpenCV 分配的矩阵上应用 Eigen 中实现的几乎所有功能

      特别是您只需实例化一个 Eigen::Map 提供指向 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() ); 
      

      有关 Eigen::Map 的更多信息,请查看 Eigen Tutorial: Map Class

      【讨论】:

      • 多通道图像通常存储为交错数组(例如 RGBRGBRGB...)。根据您想对它们做什么,您可能会考虑利用 stride 参数将每个通道映射到不同的 Eigen::Map:cv::Mat cvT(4,4,CV_32FC3); //a 3 channel float matrix Eigen::Map&lt;Matrix4f, RowMajor, Stride&lt;3,1&gt;&gt; red( cvT.data ); Eigen::Map&lt;Matrix4f, RowMajor, Stride&lt;3,1&gt;&gt; green( cvT.data +1 ); Eigen::Map&lt;Matrix4f, RowMajor, Stride&lt;3,1&gt;&gt; blue( cvT.data +2 );
      • 使用 cvT.data() 对我不起作用,会出现编译器错误。我在下面发布了关于如何执行此操作的答案,包括如何针对任意大小的矩阵执行此操作以及从 Eigen 到 OpenCV 的反向转换。
      • 嗨! @Pierluigi 是对的 Eigen::Map 是一个很好的起点。我创建了一个简单的 eigen2cv 包装器,它允许将 Eigen 类型映射到 OpenCV,反之亦然。它支持与 OpenCV 的读/写映射,还支持从 Eigen 表达式的只读映射。更详细的概述和实现可以在我的帖子中找到:computer-vision-talks.com/articles/mapping-eigen-to-opencv
      • @lubosz 不过使用cv_mat.ptr&lt;float&gt;() 会好得多。并且要小心,我认为您将行主要数据映射到列主要矩阵 - 我认为您的结果可能是错误的,它将是转置。我想你需要Eigen::RowMajor
      • @Ela782。谢谢,因此我实际上有转置矩阵。我现在正在使用这个(也使用 opencv 的 MatX):cv::Matx33f cv_mat; Eigen::Map&lt;Eigen::Matrix&lt;float,3,3,Eigen::RowMajor&gt;&gt; eigen_mat(cv_mat.val);
      【解决方案3】:

      您可以在 Eigen 和 OpenCV 之间映射任意矩阵(无需复制数据)。

      您必须注意两件事:

      • Eigen 默认以列为主存储,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());
      

      对于多通道矩阵(例如图像),您可以完全按照 Pierluigi 在评论中的建议使用“Stride”!

      【讨论】:

      • 这非常有用。另一个选项需要使用标志 WITH_EIGEN 编译 opencv,这可能无法在组织范围内强制执行。
      【解决方案4】:

      这对我有用,

        #include <opencv2/core/eigen.hpp>
      
        cv::Mat image;
        image = cv::imread("/dataset/images/15207_angle_image.jpg", CV_LOA D_IMAGE_GRAYSCALE);   // Read the file
        Eigen::Matrix<float,Eigen::Dynamic, Eigen::Dynamic> eigen_mat;
        cv::cv2eigen(image, eigen_mat);
      

      【讨论】:

        【解决方案5】:

        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;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多