我想从任意数据类型,行尺寸,列尺寸和通道尺寸的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接口。
答案 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()
最终结果,所以这对我来说很有用。