C++:将向量重塑为 3D 数组
C++: Reshape vector to 3D array
编辑:我已将矢量作为文本文件上传到云端硬盘,以防有人想看一看:https://drive.google.com/file/d/0B0wsPU8YebRQbDUwNFYza3ljSnc/view?usp=sharing
我正在尝试将我的向量 h
重塑为 3D 数组。 h
包含 295788 个元素。在这种情况下 height = 314
、width = 314
和 depth = 3
。
基本上我想做的是 MATLAB 用它的 reshape 函数做的。
h = reshape(h, height, width, depth)
到目前为止,这是我的尝试,但是当我打印它时,我看到的都是零,这是不对的。我仔细检查了 h
是否包含我期望的数字。
vector<vector<vector<double> > > array3D;
int height = 314, width = 314, depth = 3;
// Set up sizes
array3D.resize(height);
for (int i = 0; i < height; ++i) {
array3D[i].resize(width);
for (int j = 0; j < width; ++j)
array3D[i][j].resize(depth);
}
for (int i = 0; i < height; i++)
{
array3D[i][0][0] = h[i];
for (int j = 0; j < width; j++)
{
array3D[i][j][0] = h[i+j];
for (int k = 0; k < depth; k++)
{
array3D[i][j][k] = h[i+j+k];
}
}
}
正在打印:
for (vector<vector<vector<double>>>::const_iterator i = array3D.begin(); i != array3D.end(); ++i)
{
for (vector<vector<double>>::const_iterator j = i->begin(); j != i->end(); ++j)
{
for (vector<double>::const_iterator k = j->begin(); k != j->end(); ++k)
{
cout << *k << ' ';
}
}
}
所以我的问题是,如何正确地将矢量转换为 3D 数组?
我按照 Henri Menke 的建议使用 Eigen::Tensor 设法做到了这一点。我最终为初始 314x314x3 矩阵创建了一个数组,然后为 300x300x3 矩阵创建了另一个数组。它既不快也不漂亮,但现在这是我能想到的。看起来像这样。
澄清一下:margin
是在代码中进一步计算的,但在本例中,对于 314x314x3 矩阵,它是 margin=7
。 h
是一个包含 295788 个元素的向量。 nrh=314
、nch=314
和 nradii=3
。
Tensor<int, 3> t(nrh, nch, nradii);
int counter = 0;
for (int k = 0; k < nradii; k++)
{
for (int col = 0; col < nch; col++)
{
for (int row = 0; row < nrh; row++)
{
t(row, col, k) = h[counter];
counter += 1;
}
}
}
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> out(height, width, depth);
int count1 = 0, count2 = 0, count3 = 0;
for (int k = 0; k < depth; k++)
{
for (int j = margin; j < nch - margin; j++)
{
for (int i = margin; i < nrh - margin; i++)
{
out(count1, count2, count3) = t(i, j, k);
count1 += 1;
}
count1 = 0;
count2 += 1;
}
count2 = 0;
count3 += 1;
}
编辑:使用 Tensor.slice()
的解决方案 #2
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> tensor(height, width, depth);
DSizes<ptrdiff_t, 3> indices(margin, margin, 0);
DSizes<ptrdiff_t, 3> sizes(height, width, nradii);
tensor = t.slice(indices, sizes);
怎么样:
array3D[i][j][k] = h[i*(depth*width)+j*depth+k];
这可能会或可能不会以正确的顺序扫描矢量。
注意当索引 k
重置时索引 j
递增,因此您正好移动一个直到索引 j
重置,在这种情况下 i
递增并且相同的。很容易证明这个计算只读取每个元素一次。
我通常期望 width
、height
然后是 depth
,而您正在以相反的顺序扫描!
脚注: 根据应用程序的不同,仅使用此方法访问向量可能是值得的。一般来说,事实证明它比访问向量的向量更快。这在处理大量数组时可能很重要。
其实你的代码结构已经ok了,但是有两个错误:
行
array3D[i][0][0] = h[i];
和
array3D[i][j][0] = h[i+j];
毫无意义。您稍后将使用
行覆盖这些条目
array3D[i][j][k] = h[i+j+k];
h[]
的索引计算错误:在添加单元格索引之前,您必须将行索引乘以行的长度。作业应如下所示:
array3D[i][j][k] = h[(i*width+j)*depth+k];
否则,(i, j, k) == (3, 2, 1)
和 (i, j, k) == (1, 3, 2)
的结果是一样的,这显然是错误的。在上面的指数计算中,我假设 k
是变化最快的维度。如果这不是您的数据存储在 h
中的顺序,您需要更改 i
、j
和 k
的位置并相应地调整因子。
综合起来,你的赋值循环应该是:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
array3D[i][j][k] = h[(i*width+j)*depth+k];
}
}
}
有点跑题:
如果您使用的是 C 而不是 C++,您可以 "simply" 这样做:
size_t dataSize;
//Create a real 3D array with the dimensions (height, width, depth).
double (*array3D)[width][depth] = malloc(dataSize = height*sizeof(*array3D));
//Copy over the data from the file.
memcpy(array3D, h, dataSize);
//Print the array contents:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
printf("%d ", array3D[i][j][k]);
}
}
}
这使用了一个真正的 3D 数组,而不是指向双精度数组的指针数组的指针数组(这大致就是 vector<vector<vector<double>>>
的意思)。但是,这不能在 C++ 中完成,因为 C++ 不允许像 C 那样具有动态大小的数组类型。
编辑:我已将矢量作为文本文件上传到云端硬盘,以防有人想看一看:https://drive.google.com/file/d/0B0wsPU8YebRQbDUwNFYza3ljSnc/view?usp=sharing
我正在尝试将我的向量 h
重塑为 3D 数组。 h
包含 295788 个元素。在这种情况下 height = 314
、width = 314
和 depth = 3
。
基本上我想做的是 MATLAB 用它的 reshape 函数做的。
h = reshape(h, height, width, depth)
到目前为止,这是我的尝试,但是当我打印它时,我看到的都是零,这是不对的。我仔细检查了 h
是否包含我期望的数字。
vector<vector<vector<double> > > array3D;
int height = 314, width = 314, depth = 3;
// Set up sizes
array3D.resize(height);
for (int i = 0; i < height; ++i) {
array3D[i].resize(width);
for (int j = 0; j < width; ++j)
array3D[i][j].resize(depth);
}
for (int i = 0; i < height; i++)
{
array3D[i][0][0] = h[i];
for (int j = 0; j < width; j++)
{
array3D[i][j][0] = h[i+j];
for (int k = 0; k < depth; k++)
{
array3D[i][j][k] = h[i+j+k];
}
}
}
正在打印:
for (vector<vector<vector<double>>>::const_iterator i = array3D.begin(); i != array3D.end(); ++i)
{
for (vector<vector<double>>::const_iterator j = i->begin(); j != i->end(); ++j)
{
for (vector<double>::const_iterator k = j->begin(); k != j->end(); ++k)
{
cout << *k << ' ';
}
}
}
所以我的问题是,如何正确地将矢量转换为 3D 数组?
我按照 Henri Menke 的建议使用 Eigen::Tensor 设法做到了这一点。我最终为初始 314x314x3 矩阵创建了一个数组,然后为 300x300x3 矩阵创建了另一个数组。它既不快也不漂亮,但现在这是我能想到的。看起来像这样。
澄清一下:margin
是在代码中进一步计算的,但在本例中,对于 314x314x3 矩阵,它是 margin=7
。 h
是一个包含 295788 个元素的向量。 nrh=314
、nch=314
和 nradii=3
。
Tensor<int, 3> t(nrh, nch, nradii);
int counter = 0;
for (int k = 0; k < nradii; k++)
{
for (int col = 0; col < nch; col++)
{
for (int row = 0; row < nrh; row++)
{
t(row, col, k) = h[counter];
counter += 1;
}
}
}
int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> out(height, width, depth);
int count1 = 0, count2 = 0, count3 = 0;
for (int k = 0; k < depth; k++)
{
for (int j = margin; j < nch - margin; j++)
{
for (int i = margin; i < nrh - margin; i++)
{
out(count1, count2, count3) = t(i, j, k);
count1 += 1;
}
count1 = 0;
count2 += 1;
}
count2 = 0;
count3 += 1;
}
编辑:使用 Tensor.slice()
的解决方案 #2int height = nrh - margin * 2;
int width = nch - margin * 2;
int depth = nradii;
Tensor<int, 3> tensor(height, width, depth);
DSizes<ptrdiff_t, 3> indices(margin, margin, 0);
DSizes<ptrdiff_t, 3> sizes(height, width, nradii);
tensor = t.slice(indices, sizes);
怎么样:
array3D[i][j][k] = h[i*(depth*width)+j*depth+k];
这可能会或可能不会以正确的顺序扫描矢量。
注意当索引 k
重置时索引 j
递增,因此您正好移动一个直到索引 j
重置,在这种情况下 i
递增并且相同的。很容易证明这个计算只读取每个元素一次。
我通常期望 width
、height
然后是 depth
,而您正在以相反的顺序扫描!
脚注: 根据应用程序的不同,仅使用此方法访问向量可能是值得的。一般来说,事实证明它比访问向量的向量更快。这在处理大量数组时可能很重要。
其实你的代码结构已经ok了,但是有两个错误:
行
array3D[i][0][0] = h[i];
和
array3D[i][j][0] = h[i+j];
毫无意义。您稍后将使用
行覆盖这些条目array3D[i][j][k] = h[i+j+k];
h[]
的索引计算错误:在添加单元格索引之前,您必须将行索引乘以行的长度。作业应如下所示:array3D[i][j][k] = h[(i*width+j)*depth+k];
否则,
(i, j, k) == (3, 2, 1)
和(i, j, k) == (1, 3, 2)
的结果是一样的,这显然是错误的。在上面的指数计算中,我假设k
是变化最快的维度。如果这不是您的数据存储在h
中的顺序,您需要更改i
、j
和k
的位置并相应地调整因子。
综合起来,你的赋值循环应该是:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
array3D[i][j][k] = h[(i*width+j)*depth+k];
}
}
}
有点跑题:
如果您使用的是 C 而不是 C++,您可以 "simply" 这样做:
size_t dataSize;
//Create a real 3D array with the dimensions (height, width, depth).
double (*array3D)[width][depth] = malloc(dataSize = height*sizeof(*array3D));
//Copy over the data from the file.
memcpy(array3D, h, dataSize);
//Print the array contents:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
printf("%d ", array3D[i][j][k]);
}
}
}
这使用了一个真正的 3D 数组,而不是指向双精度数组的指针数组的指针数组(这大致就是 vector<vector<vector<double>>>
的意思)。但是,这不能在 C++ 中完成,因为 C++ 不允许像 C 那样具有动态大小的数组类型。