Для петли для разбиения матрицы на подматрицы равного размера
Учитывая квадратную матрицу с выраженным размером 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 2]()
![splitting 2D matrices in 5]()
![splitting 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