Для петли для разбиения матрицы на подматрицы равного размера

Учитывая квадратную матрицу с выраженным размером 400x400, как бы я мог разделить это на составные подматрицы 20x20 с помощью цикла for? Я даже не могу думать, с чего начать!

Я предполагаю, что хочу что-то вроде:

[x,y] = size(matrix)

for i = 1:20:x
    for j = 1:20:y

но я не уверен, как я продолжу. Мысли?

Ответ 1

Хорошо, я знаю, что на плакат явно просил цикл for, и ответ Джеффа Мазера предоставил именно это.

Но все же мне стало любопытно, можно ли разложить матрицу на плитки (подматрицы) заданного размера без цикла. В случае, если кому-то еще любопытно, вот, что я придумал:

T = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3])

преобразует двумерный массив A в трехмерный массив T, где каждый 2d-срез T(:, :, i) является одним из плит размером m x n. Третий индекс перечисляет плитки в стандартном линеаризованном порядке Matlab, сначала строит строки плитки.

Вариант

T = permute(reshape(A, size(A, 1), n, []), [2 1 3]);
T = permute(reshape(T, n, m, [], size(T, 3)), [2 1 3 4]);

делает T четырехмерным массивом, где T(:, :, i, j) дает 2d срез с индексами плитки i, j.

Выполнение этих выражений немного напоминает решение раздвижной головоломки.; -)

Ответ 2

Мне жаль, что в моем ответе тоже не используется цикл for, но это также может сделать трюк:

cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)

Затем вы можете получить доступ к отдельным ячейкам, например:

cellOf20x20matrices{i,j}(a,b)

где i, j - подматрица для выборки (и a, b - индексирование в эту матрицу, если необходимо)

Привет

Ответ 3

Ты выглядишь очень близко. Просто используя эту проблему, как вы ее описали (400-на-400, разделенная на 20-на-20 кусков), не будет ли это делать то, что вы хотите?

[x,y] = size(M);

for i = 1:20:x
  for j = 1:20:y
    tmp = M(i:(i+19), j:(j+19));
    % Do something interesting with "tmp" here.
  end
end

Ответ 4

Хотя вопрос в основном касается 2D-матриц, вдохновленных A. Donda answer Я хотел бы расширить свой ответ на 3D-матрицы, чтобы этот метод можно было использовать при обрезке True Color images (3D)

A = imread('peppers.png');       %// size(384x512x3)
nCol = 4;                        %// number of Col blocks
nRow = 2;                        %// number of Row blocks
m = size(A,1)/nRow;              %// Sub-matrix row size (Should be an integer)
n = size(A,2)/nCol;              %// Sub-matrix column size (Should be an integer)

imshow(A);                       %// show original image

out1 = reshape(permute(A,[2 1 4 3]),size(A,2),m,[],size(A,3));
out2 = permute(reshape(permute(out1,[2 1 3 4]),m,n,[],size(A,3)),[1 2 4 3]);

figure;
for i = 1:nCol*nRow
    subplot(nRow,nCol,i); imshow(out2(:,:,:,i));
end

Основная идея состоит в том, чтобы сделать третье измерение незатронутым при изменении формы, чтобы изображение не искажалось. Чтобы достичь этого, была сделана дополнительная перестановка для замены 3-го и 4-го измерений. Как только процесс будет завершен, размеры будут восстановлены, как было, путем перестановки назад.

Результаты:

Оригинальное изображение

enter image description here

Подзаголовки (разделы/подматрицы)

enter image description here


Преимущество этого метода заключается в том, что он хорошо работает и на 2D-изображениях. Вот пример изображения серого масштаба (2D). Например, здесь используется встроенное изображение MatLab 'cameraman.tif'

enter image description here

Ответ 5

С некоторыми подсказками для ответа, которые используют вложенные вызовы permute, я подумал о том, чтобы выбрать время и сравнить с другим ответом, который использует mat2cell.

Верно, что они не возвращают то же самое, но:

  • ячейку можно легко преобразовать в матрицу, как и другую (я приурочен к этому, см. ниже);
  • когда возникает эта проблема, желательно (по моему опыту) иметь данные в ячейке, так как позже вам часто захочется вернуть оригинал обратно;

Во всяком случае, я сравнил их как со следующим script. Код был запущен в Octave (версия 3.9.1) с отключенным JIT.

function T = split_by_reshape_permute (A, m, n)
  T = permute (reshape (permute (reshape (A, size (A, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
endfunction

function T = split_by_mat2cell (A, m, n)
  l = size (A) ./ [m n];
  T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1));
endfunction

function t = time_it (f, varargin)
  t = cputime ();
  for i = 1:100
    f(varargin{:});
  endfor
  t = cputime () - t;
endfunction

Asizes = [30 50 80 100 300 500 800 1000 3000 5000 8000 10000];
Tsides = [2 5 10];
As = arrayfun (@rand, Asizes, "UniformOutput", false);

for d = Tsides
  figure ();

  t1 = t2 = [];
  for A = As
    A = A{1};
    s = rows (A) /d;

    t1(end+1) = time_it (@split_by_reshape_permute, A, s, s);
    t2(end+1) = time_it (@split_by_mat2cell, A, s, s);

  endfor

  semilogy (Asizes, [t1(:) t2(:)]);
  title (sprintf ("Splitting in %i", d));
  legend ("reshape-permute", "mat2cell");
  xlabel ("Length of matrix side (all squares)");
  ylabel ("log (CPU time)");
endfor

Обратите внимание, что ось Y находится в масштабе шкалы

splitting 2D matrices in 2splitting 2D matrices in 5splitting 2D matrices in 10

Производительность

Производительность с использованием вложенной перестановки будет только быстрее для меньших матриц, где большие изменения относительной производительности на самом деле очень небольшие изменения во времени. Обратите внимание, что ось Y находится в масштабе шкалы, поэтому разница между двумя функциями для матрицы 100x100 составляет 0,02 секунды, а для матрицы 10000x10000 - 100 секунд.

Я также проверил следующее, которое преобразует ячейку в матрицу так, чтобы возвращаемые значения двух функций были одинаковыми:

function T = split_by_mat2cell (A, m, n)
  l = size (A) ./ [m n];
  T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1), 1);
  T = reshape (cell2mat (T(:)'), [m n numel(T)]);
endfunction

Это немного замедляет работу, но недостаточно, чтобы рассмотреть (линии будут пересекаться на 600x600 вместо 400x400).

читаемость

Намного сложнее обдумать использование вложенной перестановки и изменить ее. Это безумие, чтобы использовать его. Это увеличит время обслуживания на много (но эй, это язык Matlab, он не должен быть элегантным и многоразовым).

Future

Вложенные вызовы перестановки вообще не расширяются в N-измерениях. Думаю, для этого потребуется цикл for по размеру (что не помогло бы вообще совсем иному загадочному коду). С другой стороны, используя mat2cell:

function T = split_by_mat2cell (A, lengths)
  dl = arrayfun (@(l, s) repmat (l, s, 1), lengths, size (A) ./ lengths, "UniformOutput", false);
  T = mat2cell (A, dl{:});
endfunction

Изменить (и проверено в Matlab тоже)

Количество upvotes ответа, предлагающего использовать перестановку и изменение, вызвало у меня такое любопытство, что я решил проверить это в Matlab (R2010b). Результаты были почти такими же, т.е. Производительность была очень плохой. Поэтому, если эта операция не будет выполняться много раз, в матрицах, которые всегда будут маленькими (менее 300x300), и всегда будет существовать гуру Matlab, чтобы объяснить, что он делает, не используйте его.

Ответ 6

Если вы хотите использовать цикл for, вы можете сделать это:

[x,y] = size(matrix)

k=1; % counter

for i = 1:20:x
    for j = 1:20:y

        subMatrix=Matrix(i:i+19, j:j+19);

        subMatrixCell{k}=subMatrix;  % if you want to save all the
                                    % submatrices into a cell array
        k=k+1;

    end
end