我想从任意数据类型、行维、列维和通道维的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);