Подтвердить что ты не робот

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

Я пробовал использовать cv2eigen и eigen2cv, но полученный cvMat полностью искалечен, и я не совсем уверен, почему. Размеры правильны, но графики полностью разбиты, возможно, проблема с байтами на пиксель или объем данных?

4b9b3361

Ответ 1

Вам следует рассмотреть возможность использования Eigen :: Map для обертывания матриц OpenCV, чтобы использовать их непосредственно Eigen SDK. Это позволяет применять практически все функциональные возможности, реализованные в Eigen, к матрице, выделенной OpenCV.

В частности, вы просто создаете экземпляр 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

Ответ 2

Вы также можете использовать

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>.

Ответ 3

Вы можете сопоставить произвольные матрицы между 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());

Для многоканальных матриц (например, изображений) вы можете использовать "Stride" точно так же, как Пьерлуиги предложил в своем комментарии!

Ответ 4

Версия Пьерлуиджи не работает для меня полностью для 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;

Ответ 5

Это работает для меня,

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