将 BGR OpenCV 垫映射到特征张量

Map BGR OpenCV Mat to Eigen Tensor

本文关键字:特征 张量 映射 BGR OpenCV      更新时间:2023-10-16

我正在尝试将OpenCV 3通道垫转换为3D特征张量。

到目前为止,我可以通过以下方式转换 1 通道灰度垫:

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

我尝试将 BGR 垫转换为张量是:

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

任何帮助不胜感激!

答案可能会让你失望。

在浏览了 12 页之后,我的结论是您必须将 RGB 分离到单个通道 MAT,然后转换为特征矩阵。或者创建自己的特征类型和opencv转换函数

在OpenCV中,它是这样测试的。它只允许单通道灰度图像

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

在OpenCV中,它是这样实现的。这没有给你太多的选择自定义类型,又名cv::标量到特征标准::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 标量和特征标量具有不同的含义

当且仅当您使用自己的数据类型(又名矩阵)时,才有可能这样做

因此,您可以选择将 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);

问题是我不确定这是否有效。即使它有效,您仍然必须弄清楚内部数据的组织方式,以便您可以正确获得形状。祝你好运

更新的答案 - OpenCV 现在具有 Eigen::Tensor 的转换函数,它将解决您的问题。我也需要同样的功能,所以我为项目做出了贡献,供大家使用。请参阅此处的文档:

https://docs.opencv.org/3.4/d0/daf/group__core__eigen.html

注意:如果你想要RGB顺序,你仍然需要在转换为Eigen::Tensor之前对OpenCV中的通道重新排序