从数组创建或重塑OpenCV 3通道垫

Create or Reshape OpenCV 3 Channel Mat From Array

本文关键字:OpenCV 通道 数组 创建      更新时间:2023-10-16

我想从任意数据类型、行维、列维和通道维的1D数据数组中构建一个3通道矩阵。在我的例子中,我有一个1x12的双数组数据,我想把它转换成一个2x2x3的OpenCv矩阵。

double rawData[] = {1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0};

我的目标是拥有:

Channel 1:
[  1,   1;
   1,   1]
Channel 2:
[  2,   2;
   2,   2]
Channel 3:
[  3,   3;
   3,   3]

这是我尝试过的:

cv::Mat aMat = cv::Mat(2, 2, CV_64FC3, rawData)

但是OpenCv不同意它应该如何使用rawData缓冲区。当我按通道分割矩阵并打印每个单独的通道时:

cv::Mat channels[3];
cv::split(aMat ,channels);

:

Channel 1:
[  1,   1;
   2,   3]
Channel 2:
[  1,   2;
   2,   3]
Channel 3:
[  1,   2;
   3,   3]

我也试过在1D Mat中加载数据,然后使用cv::重塑,但结果是相同的。

如何让通道看起来像我想要的那样?我真的必须手动分配每个索引还是有更优雅/优化的方式?

编辑:问题约束

rawData中数据的顺序不应该重新排列,因为那样会给确定维度和数据类型带来额外的复杂性。如果可能的话,我宁愿使用OpenCV接口。

我的解决方案接近berak的,将数据分成单独的通道。除了一个重要的(我认为)区别。我用已经编码的数据类型初始化一个单行矩阵,即:

cv::Mat aMat = cv::Mat(1, 12, CV_64F, data);

然后使用colRange方法提取列的部分内容:

std::vector<cv::Mat> channelVector(3);
channelVector[0] = aMat.colRange(0,4);
channelVector[1] = aMat.colRange(4,8);
channelVector[2] = aMat.colRange(8,12);

这样做是为了避免指针运算。这里的优点是,我可以让我的数据缓冲区类型为void*,我不必担心首先将指针转换为正确的类型,以便增加缓冲区指针。

然后迭代一些重塑动作。

for(cv::Mat& channel : channelVector)
    channel = channel.reshape(1,2);

最后合并。

cv::Mat combinedMatrix;
cv::merge(channelVector, combinedMatrix);

这应该是有效的,因为这些操作是O(1)。我不确定合并,我认为它实际上复制了数据,但我无法验证…但无论如何我要clone()的最终结果,所以这对我来说是可行的。

重新排列你的数据:

double rawData[] = {1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0};

或从您的数据中构建单独的'channel' Mats,然后合并:

double rawData[] = {1.0, 1.0, 1.0, 1.0,
                    2.0, 2.0, 2.0, 2.0,
                    3.0, 3.0, 3.0, 3.0};
Mat chan[3] = {
    Mat(2,2,CV_64F, rawData),
    Mat(2,2,CV_64F, rawData+4),
    Mat(2,2,CV_64F, rawData+8)
};
Mat merged;
cv::merge(chan,3,merged);