Matlab/Octave: как написать n-мерный алгоритм заполнения нулями без eval
Я хотел бы написать "синтаксическую сахарную" функцию Octave или Matlab с нулевым заполнением, в которую пользователь отправляет n-мерный объект и вектор из <= n записей. Вектор содержит новые, равные или большие измерения для объекта, и объект дополняется нулями, чтобы соответствовать этим измерениям. Любые размеры, не указанные, остаются одни. Я могу назвать одно ожидаемое использование, например, для 5-го блока X трехмерных медицинских изображений.
y = simplepad(X, [128 128 128]);
и, таким образом, дополняем первые три измерения степенью двойки для вейвлет-анализа (на самом деле я использую отдельную функцию nextpwr2, чтобы найти эти измерения), оставляя остальные.
Я ломал голову над тем, как написать этот метод, избегая страшного eval, но пока не могу найти способ. Кто-нибудь может предложить решение? Вот более или менее то, что у меня есть:
function y = simplepad(x, pad)
szx = size(x);
n_pad = numel(pad);
szy = [pad szx(n_pad+1:end)];
y = zeros(szy);
indices_string = '(';
for n = 1:numel(szx)
indices_string = [indices_string, '1:', num2str(szx(n))];
if n < numel(szx)
indices_string = [indices_string, ','];
else
indices_string = [indices_string, ')'];
end
end
command = ['y',indices_string,'=x;'];
eval(command);
end
2 ответа
Как я понимаю, вы хотите просто передать некоторые динамические аргументы в функцию. Вы можете сделать это, преобразовав эти аргументы в ячейку и вызвав вашу функцию с передачей содержимого ячейки. Итак, ваша функция будет выглядеть так:
function y = simplepad(x, pad)
szx = size(x);
n_pad = numel(pad);
szy = [pad szx(n_pad+1:end)];
y = x;
szyc = num2cell(szy);
y(szyc{:}) = 0; % warning: assume x array only grows
end
Вот решение, которое должно обрабатывать все маленькие угловые случаи:
function A = simplepad(A, pad)
% Add singleton dimensions (i.e. ones) to the ends of the old size of A
% or pad as needed so they can be compared directly to one another:
oldSize = size(A);
dimChange = numel(pad)-numel(oldSize);
oldSize = [oldSize ones(1, dimChange)];
pad = [pad ones(1, -dimChange)];
% If all of the sizes in pad are less than or equal to the sizes in
% oldSize, there is no padding done:
if all(pad <= oldSize)
return
end
% Use implicit zero expansion to pad:
pad = num2cell(pad);
A(pad{:}) = 0;
end
И несколько тестовых случаев:
>> M = magic(3)
M =
8 1 6
3 5 7
4 9 2
>> simplepad(M, [1 1]) % No change, since the all values are smaller
ans =
8 1 6
3 5 7
4 9 2
>> simplepad(M, [1 4]) % Ignore the 1, pad the rows
ans =
8 1 6 0
3 5 7 0
4 9 2 0
>> simplepad(M, [4 4]) % Pad rows and columns
ans =
8 1 6 0
3 5 7 0
4 9 2 0
0 0 0 0
>> simplepad(M, [4 4 2]) % Pad rows and columns and add a third dimension
ans(:,:,1) =
8 1 6 0
3 5 7 0
4 9 2 0
0 0 0 0
ans(:,:,2) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0