从阵列创建或重塑OpenCV 3通道垫

时间:2014-03-27 17:39:53

标签: c++ opencv

我想从任意数据类型,行尺寸,列尺寸和通道尺寸的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 :: Reshape但结果是一样的。

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

修改:问题限制

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

2 个答案:

答案 0 :(得分: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};

或从您的数据中构建单独的'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);

答案 1 :(得分:2)

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