Отображение BGR OpenCV Mat на собственный тензор - PullRequest
1 голос
/ 09 июня 2019

Я пытаюсь преобразовать 3-канальный мат OpenCV в трехмерный тензор собственных значений.

Пока что я могу преобразовать 1-канальный мат в оттенках серого с помощью:

    cv::Mat mat = cv::imread("/image/path.png", cv::IMREAD_GRAYSCALE);
    Eigen::MatrixXd myMatrix;
    cv::cv2eigen(mat, myMatrix);

Myпопытка конвертировать коврик BGR в Tensor:

    cv::Mat mat = cv::imread("/image/path.png", cv::IMREAD_COLOR);
    Eigen::MatrixXd temp;
    cv::cv2eigen(mat, temp);
    Eigen::Tensor<double, 3> myTensor = Eigen::TensorMap<Eigen::Tensor<double, 3>>(temp.data(), 3, mat.rows, mat.cols);

Однако я получаю следующую ошибку:

libc++abi.dylib: terminating with uncaught exception of type cv::Exception: OpenCV(4.1.0) /tmp/opencv-20190505-12101-14vk1fh/opencv-4.1.0/modules/core/src/matrix_wrap.cpp:1195:
error: (-215:Assertion failed) !fixedType() || ((Mat*)obj)->type() == mtype in function 'create'

в строке: cv::cv2eigen(mat, temp);

Любая помощь приветствуется!

1 Ответ

1 голос
/ 09 июня 2019

Ответ может быть неутешительным для вас.

Пройдя 12 страниц, я пришел к выводу, что вам нужно разделить RGB на отдельный канал MAT, а затем преобразовать в собственную матрицу. Или создайте свой собственный тип Eigen и функцию преобразования opencv

В OpenCV это тестируется следующим образом. Это позволяет только одноканальное изображение в градациях серого

https://github.com/daviddoria/Examples/blob/master/c%2B%2B/OpenCV/ConvertToEigen/ConvertToEigen.cxx

А в OpenCV это реализовано так. Который не дает вам много возможностей для пользовательского типа aka cv :: scalar для eigen std :: vector

https://github.com/stonier/opencv2/blob/master/modules/core/include/opencv2/core/eigen.hpp

И согласно этому посту,

https://stackoverflow.com/questions/32277887/using-eigen-array-of-arrays-for-rgb-images

Я думаю, что Эйген не должен был использоваться таким образом (с векторами как «скалярные» типы).

у них также есть трудности в работе с изображением RGB в собственном.

Обратите внимание, что Opencv Scalar и eigen Scalar имеют различное значение

Это можно сделать только в том случае, если вы используете собственную матрицу данных типа aka matrix

Таким образом, вы либо сохраняете информацию о 3 каналах в 3 собственных матрицах, и можете использовать собственную маршрутизацию по умолчанию и opencv.

Mat src = imread("img.png",CV_LOAD_IMAGE_COLOR); //load  image
Mat bgr[3];   //destination array
split(src,bgr);//split source    
//Note: OpenCV uses BGR color order
imshow("blue.png",bgr[0]); //blue channel
imshow("green.png",bgr[1]); //green channel
imshow("red.png",bgr[2]); //red channel
Eigen::MatrixXd bm,gm,rm;
cv::cv2eigen(bgr[0], bm); 
cv::cv2eigen(bgr[1], gm); 
cv::cv2eigen(bgr[2], rm);

Или вы можете определить свой собственный тип и написать собственную версию функции opencv cv2eigen

Собственный собственный тип. и это не будет красиво

https://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html
https://eigen.tuxfamily.org/dox/TopicNewExpressionType.html

Перепишите свою собственную функцию cv2eigen_custom, похожую на эту

https://github.com/stonier/opencv2/blob/master/modules/core/include/opencv2/core/eigen.hpp

Так что удачи.

Редактировать

Так как вам нужен тензор. забудьте о функции cv

Mat image;
image = imread(argv[1], CV_LOAD_IMAGE_COLOR); 
Tensor<float, 3> t_3d(image.rows, image.cols, 3);

// t_3d(i, j, k) where i is row j is column and k is channel. 
for (int i = 0; i < image.rows; i++) 
  for (int j = 0; j < image.cols; j++) 
  {
       t_3d(i, j, 0) = (float)image.at<cv::Vec3b>(i,j)[0]; 
       t_3d(i, j, 1) = (float)image.at<cv::Vec3b>(i,j)[1];
       t_3d(i, j, 2) = (float)image.at<cv::Vec3b>(i,j)[2];
       //cv ref Mat.at<data_Type>(row_num, col_num)
  }

следите за i, j, так как они не уверены в заказе. Я пишу код только на основе ссылки. не скомпилировал для него.

Также следите за проблемой приведения типа изображения к тензорному типу. Иногда вы можете не получить то, что хотели.

этот код должен в принципе решить вашу проблему

Редактировать номер 2

по примеру этого

int storage[128];  // 2 x 4 x 2 x 8 = 128
TensorMap<Tensor<int, 4>> t_4d(storage, 2, 4, 2, 8);

Применительно к вашему делу

cv::Mat frame=imread('myimg.ppm');
TensorMap<Tensor<float, 3>> t_3d(frame.data, image.rows, image.cols, 3);

проблема в том, что я не уверен, сработает или нет. Даже если это работает, вы все равно должны выяснить, как организованы внутренние данные, чтобы вы могли правильно получить форму. Удачи

...