【问题标题】:Create or Reshape OpenCV 3 Channel Mat From Array从阵列创建或重塑 OpenCV 3 通道垫
【发布时间】:2014-05-06 20:58:33
【问题描述】:

我想从 任意数据类型、行维度、列维度和通道维度的一维数据数组构建一个 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::Reshape 但结果是一样的。

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

编辑:问题约束

不应重新排列 rawData 中数据的顺序,因为这会增加确定维度和数据类型的复杂性。如果可能,我更愿意使用 OpenCV 接口。

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    我的解决方案类似于 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() 最终结果,所以这对我来说很有效。

    【讨论】:

      【解决方案2】:

      只需重新排列您的数据:

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

      或从您的数据中构建单独的“通道”垫,然后合并:

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

      【讨论】:

      • 我不希望重新排列原始数据。它以 void* 的形式出现,我不想找出它是什么类型,转换数据,然后相应地重新排列。如果有一个选项可以用来指定填充矩阵的顺序,即行、列、通道,那将是理想的。
      • 您可能至少需要一些关于输入数据的知识。不是你说的“任意”。
      • 当然有与之关联的元数据,否则我将如何指定 CV_64F* 字段?我可以重新排列数据,但我不希望这样做。从某种意义上说,传入的数据可以是任何数据类型和维度,这是任意的。
      • 你的例子已经假设了连续的通道数据(不是交错的,像大多数“像素”一样)
      • 我确实是独立完成的。给你正确的答案,因为这是我坚持的。也请参阅我的答案。
      猜你喜欢
      • 1970-01-01
      • 2023-03-14
      • 2017-06-02
      • 2017-08-28
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2023-03-31
      相关资源
      最近更新 更多