我正在尝试将OpenCV 3通道Mat转换为3D本征张量。
到目前为止,我可以通过以下方式转换1通道灰度Mat:
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);
感谢您的帮助!
答案 0 :(得分:1)
答案可能会让您失望。
浏览12页后,我的结论是,您必须将RGB分离到单个通道MAT,然后转换为特征矩阵。或创建您自己的本征类型和opencv转换功能
在OpenCV中,将像这样进行测试。它仅允许单通道灰度图像
https://github.com/daviddoria/Examples/blob/master/c%2B%2B/OpenCV/ConvertToEigen/ConvertToEigen.cxx
在OpenCV中,它是这样实现的。自定义类型aka cv :: scalar到本征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
我认为Eigen并非以这种方式使用(将向量 “标量”类型)。
它们也很难处理本征中的RGB图像。
请注意,Opencv标量和本征标量具有不同的含义
仅当您使用自己的数据类型aka矩阵时,才可以这样做
因此,您可以选择将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
祝你好运。
编辑
因为您需要张量。忘记简历功能
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);
问题是我不确定这是否行得通。即使有效,您仍然必须弄清楚内部数据的组织方式,以便正确获取形状。祝你好运
答案 1 :(得分:0)
更新的答案-OpenCV现在具有Eigen :: Tensor的转换功能,可以解决您的问题。我也需要相同的功能,所以我为项目做出了贡献,供所有人使用。请参阅此处的文档:
https://docs.opencv.org/3.4/d0/daf/group__core__eigen.html
注意:如果要进行RGB排序,在转换为Eigen :: Tensor
之前,仍然需要在OpenCV中对通道进行重新排序。