Для цикла, чтобы разделить матрицу на подматрицы одинакового размера

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

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

[x,y] = size(matrix)

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

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


person user3058703    schedule 02.12.2013    source источник
comment
Хотя у вас есть ответ, просто из любопытства, что заставило вас написать число 30, если вы собираетесь разбить матрицу на 20x20 подматрицы   -  person Autonomous    schedule 02.12.2013
comment
mat2cell подходит для разбиения матрицы на подматрицы. Ответ KlausCPH является хорошим примером. См. также здесь.   -  person chappjc    schedule 03.12.2013
comment
@Parag Просто ошибка, ха-ха!   -  person user3058703    schedule 03.12.2013
comment
связанный вопрос: stackoverflow.com/q/11238828/97160   -  person Amro    schedule 27.03.2016


Ответы (6)


Ну, я знаю, что постер явно просил цикл 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.

Придумывать эти выражения немного похоже на решение скользящей головоломки. ;-)

person A. Donda    schedule 02.12.2013
comment
Если у вас есть Image Processing Toolbox, вы можете использовать blockproc для итеративного применения дескриптора функции к подразделам изображения/матрицы. Например: blockproc(M, [20 20], @myAwesomeFunction) - person Jeff Mather; 03.12.2013
comment
Конечно. Но где в этом веселье? ;-) - person A. Donda; 03.12.2013
comment
+1 Мне было любопытно! На самом деле, я попробовал несколько минут и бросил :-) - person Luis Mendo; 03.12.2013
comment
@A.Donda A.Donda Я использовал вашу резку матрицы в этот ответ. Хотя я до сих пор не понимаю, как именно это работает... :-) - person Luis Mendo; 04.12.2013
comment
@A.Donda, не могли бы вы посмотреть здесь: stackoverflow.com/questions/25449279/ - person Royi; 22.08.2014
comment
Потрясающая работа. +1 Я расширил ваш ответ до 3D-матриц. проверить! - person Santhan Salai; 22.04.2015
comment
@LuisMendo, большое спасибо за эту награду, для меня большая честь! Думаю, я восприму это как стимул попытаться объяснить черную магию... - person A. Donda; 22.04.2015
comment
@A.Donda С другой стороны, это немного испортило бы его привлекательность! :-) - person Luis Mendo; 23.04.2015
comment
Это ужасный ответ. Он не только не отвечает на вопрос (который явно запросил цикл for), его производительность ужасна по сравнению с гораздо более простыми альтернативами, такими как ответ KlausCPH на использование cell2mat. - person carandraug; 24.04.2015
comment
@A.Donda Я измерил его размером от 30x30 до 10000x10000 (см. мой пост ниже). Да, это немного быстрее при небольших размерах матрицы, но конкретный размер 400x400 на самом деле не является точкой ответа, который ОП выбрал в качестве примера. А permute в зависимости от заказа создаст копию. - person carandraug; 24.04.2015
comment
@carandraug, вы только что посмотрели, что происходит с действительно большими матрицами, когда они разбиты на небольшое количество подматриц. Когда они разбиты на большое количество подматриц, мой метод снова работает быстрее. – Хотя насчет permute точно. Тем не менее, массивы ячеек представляют собой более сложную структуру данных. - person A. Donda; 24.04.2015
comment
@carandraug, что мне действительно интересно, так это то, почему награда побуждает вас прыгать и критиковать мой ответ за неэффективность (мой ответ не утверждает, что это так), за неиспользование циклов for (я сказал это, и мы оба знаем, что это плохая идея в Matlab большую часть времени). Затем вы пишете полный ответ, который на самом деле не отвечает на вопрос. - person A. Donda; 24.04.2015
comment
@карандрауг. Вы называете мой ответ ужасным, что довольно сильно сказано, и косвенно называете меня гуру, что все равно нехорошо. Серьезно, что тут такого? Луис Мендо и, вероятно, большинство других сторонников осознали, что это упражнение в экстремальной векторизации, которое (для меня и, по-видимому, для других) интересно и занимательно. - person A. Donda; 24.04.2015
comment
@carandraug, для протокола, я проголосовал за три других ответа, потому что все они хороши по-своему. - person A. Donda; 24.04.2015
comment
награда не мотивировала ответ, она просто привлекла внимание к вопросу, который иначе я бы даже не увидел. И я добавил ответ, потому что это было единственное место, где можно было добавить такой обширный комментарий (если вы не хотите, чтобы я отредактировал ваш ответ с анализом - я не возражаю, просто дайте мне знать). А чем гуру не мил? Это должно быть комплиментом. Дело в том, что векторизация хороша тем, что делает код проще и быстрее. Ваш не делает ни того, ни другого. Это упражнение в том, чтобы придумать сложный для сопровождения фрагмент кода. - person carandraug; 24.04.2015
comment
@carandraug, одно- или двухстрочный фрагмент кода не обязательно должен быть сразу прозрачным, если он четко задокументирован, что он делает. Здесь нечего поддерживать, кто-то использует код, либо нет. Что касается скорости, как я уже сказал, вы смотрели только в одном направлении для больших матриц. Я ценю, однако, что вы не редактировали мой ответ. – Я до сих пор не понимаю, почему вы идете так далеко, чтобы очернить мой ответ, который, как сказано, был сделан из любопытства. Но я предполагаю, что это обсуждение ни к чему не приведет, так что: раз и навсегда. - person A. Donda; 25.04.2015
comment
@carandraug Я, конечно, не согласен с тем, что этот ответ ужасен. Как сказал А.Донда, что мне понравилось, так это его экстремальная векторизация. Ваш ответ был интересным (я проголосовал за него), но я не думаю, что слово «ужасный» подходит для этого. - person Luis Mendo; 23.09.2015

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

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

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

cellOf20x20matrices{i,j}(a,b)

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

С уважением

person KlausCPH    schedule 02.12.2013

Ты кажешься очень близким. Просто используя проблему, как вы ее описали (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
person Jeff Mather    schedule 02.12.2013
comment
Спасибо, это было очень полезно. И спасибо всем остальным за другие ответы, но я хотел использовать цикл for в этом конкретном случае. Обсуждаются очень интересные идеи! - person user3058703; 03.12.2013
comment
@user3058703 user3058703, если этот ответ соответствует тому, что вы искали, вы должны принять его (щелкните обведенную галочку, чтобы она стала зеленой). - person A. Donda; 04.12.2013

Несмотря на то, что вопрос в основном касается 2D-матриц, вдохновленных A. Ответ Донды Я хотел бы расширить его ответ на 3D-матрицы, чтобы этот метод можно было использовать при кадрировании изображений True Color (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-е измерение, чтобы изображение не искажалось. Для этого была сделана дополнительная перестановка, чтобы поменять местами 3-е и 4-е измерения. Как только процесс завершен, размеры восстанавливаются как были путем перестановки обратно.

Результаты:

Исходное изображение

введите здесь описание изображения

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

введите здесь описание изображения


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

введите здесь описание изображения

person Santhan Salai    schedule 22.04.2015

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

Это правда, что они не возвращают одно и то же, но:

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

Во всяком случае, я сравнил их обоих со следующим сценарием. Код запускался в 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 находится в логарифмическом масштабе.

разделение 2D-матриц на 2разделение 2D-матриц на 5 разделение 2D-матриц на 10

Представление

С точки зрения производительности использование вложенной перестановки будет быстрее только для меньших матриц, где большие изменения относительной производительности на самом деле являются очень небольшими изменениями во времени. Обратите внимание, что ось Y представлена ​​в логарифмическом масштабе, поэтому разница между двумя функциями для матрицы 100 x 100 – 0,02 секунды, а для матрицы 10 000 x 10 000 – 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

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

Читабельность

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

Будущее

Вложенные вызовы permute вообще плохо расширяются в 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)

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

person carandraug    schedule 22.04.2015

Если вы хотите использовать цикл 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   
person Nerea González Vázquez    schedule 13.04.2015