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
Другие вопросы по тегам