C ++: преобразовать вектор в трехмерный массив

Изменить: я загрузил вектор на диск в виде текстового файла, на случай, если кто-то захочет посмотреть: https://drive.google.com/file/d/0B0wsPU8YebRQbDUwNFYza3ljSnc/view?usp=sharing

Я пытаюсь изменить свой вектор h в 3D массив. h содержит 295788 элементов. В этом случае height = 314, width = 314 а также depth = 3,
По сути, я пытаюсь сделать то, что MATLAB делает со своей функцией изменения формы.

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

Итак, мой вопрос, как мне правильно преобразовать мой вектор в трехмерный массив?

1

Решение

Мне удалось сделать это, используя 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;
}

Изменить: Решение № 2 с Tensor.slice ()

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

Другие решения

Как насчет:

array3D[i][j][k] = h[i*(depth*width)+j*depth+k];

Это может или не может сканировать вектор в правильном порядке.

Обратите внимание, как, когда индекс k сбрасывает индекс j увеличивается, так что вы двигаетесь ровно на один, пока индекс j сбрасывает в этом случае i приращения и то же самое. Легко показать, что этот расчет читает каждый элемент ровно один раз.

Я обычно ожидаю width, height затем depth и вы сканируете в обратном порядке!

Сноска: В зависимости от приложения может оказаться целесообразным просто получить доступ к вектору с использованием этого подхода. В целом это оказывается быстрее, чем доступ к вектору векторов векторов. Это может быть актуально при работе с массивными массивами.

0

На самом деле, ваша структура вашего кода уже в порядке, однако есть две ошибки:

  • Линии

    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 ++, вы могли бы «просто» сделать это:

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

Это использует реальный трехмерный массив вместо массива указателей на массивы указателей на массивы двойников (что примерно vector<vector<vector<double>>> является). Однако это не может быть сделано в C ++, поскольку C ++ не допускает типы массивов с динамическими размерами, как в C.

0
По вопросам рекламы [email protected]