Para matriz de bucle para dividir submatrices de igual tamaño

Dada una matriz cuadrada de, digamos, tamaño 400x400 , ¿cómo podría dividir esto en 400x400 constituyentes de 20x20 usando un for-loop? ¡Ni siquiera puedo pensar por dónde empezar!

Imagino que quiero algo como:

 [x,y] = size(matrix) for i = 1:20:x for j = 1:20:y 

pero no estoy seguro de cómo procedería. ¿Pensamientos?

    Bueno, sé que el cartel pidió explícitamente un ciclo, y la respuesta de Jeff Mather me proporcionó exactamente eso.

    Pero todavía tengo curiosidad de si es posible descomponer una matriz en mosaicos (submatrices) de un tamaño dado sin un bucle. En caso de que alguien más tenga curiosidad, también, esto es lo que se me ocurrió:

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

    transforma una matriz bidimensional A en una matriz tridimensional T , donde cada rebanada 2d T(:, :, i) es una de las fichas de tamaño m x n . El tercer índice enumera las teselas en el orden linearizado Matlab estándar, primero las filas de teselas.

    La variante

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

    convierte a T una matriz tetradimensional en la que T(:, :, i, j) da la 2d división con índices de mosaico i, j .

    Venir con estas expresiones se parece un poco a la resolución de un rompecabezas deslizante. 😉

    Lamento que mi respuesta tampoco use un bucle for, pero esto también funcionaría:

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

    A continuación, puede acceder a las celdas individuales como:

     cellOf20x20matrices{i,j}(a,b) 

    donde i, j es la submatriz a buscar (y a, b es la indexación en esa matriz si es necesario)

    Saludos

    Pareces muy cerca. Simplemente usando el problema como lo describió (400 por 400, dividido en fragmentos de 20 por 20), ¿no haría esto lo que usted quiere?

     [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 

    Aunque la pregunta es básicamente para matrices 2D, inspirada por la respuesta de A. Donda, me gustaría ampliar su respuesta a las matrices 3D para que esta técnica se pueda utilizar en el recorte de imágenes de color verdadero (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 

    La idea básica es hacer que la tercera dimensión no se vea afectada mientras se cambia la forma para que la imagen no se distorsione. Para lograr esto, se realizó permuta adicional para intercambiar las dimensiones 3 y 4. Una vez que se realiza el proceso, las dimensiones se restauran tal como estaban, permutando hacia atrás.

    Resultados:

    Imagen original

    enter image description here

    Subttwigs (Particiones / Sub Matrices)

    enter image description here


    La ventaja de este método es que también funciona bien en imágenes 2D. Aquí hay un ejemplo de una imagen de escala de grises (2D). Ejemplo utilizado aquí es la imagen incorporada de MatLab 'cametwign.tif'

    enter image description here

    Con algunos muchos upvotes para la respuesta que hace que las llamadas anidadas se permute , pensé en sincronizarla y compararla con la otra respuesta que hace uso de mat2cell .

    Es cierto que no devuelven exactamente lo mismo, pero:

    • la célula se puede convertir fácilmente en una matriz como la otra (cronometré esto, mire más abajo);
    • cuando surge este problema, es preferible (en mi experiencia) tener los datos en una celda, ya que más adelante uno querrá volver a juntar el original;

    De todos modos, los he comparado con el siguiente guión. El código se ejecutó en Octave (versión 3.9.1) con JIT deshabilitado.

     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) ./ [mn]; 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 

    Tenga en cuenta que el eje Y está en escala de registro

    dividiendo matrices 2D en 2dividir matrices 2D en 5dividir matrices 2D en 10

    Actuación

    En cuanto al rendimiento, usar el permute nested solo será más rápido para matrices más pequeñas donde los grandes cambios en el rendimiento relativo son en realidad cambios muy pequeños en el tiempo. Tenga en cuenta que el eje Y está en escala logarítmica , por lo que la diferencia entre las dos funciones para una matriz de 100×100 es de 0.02 segundos, mientras que para una matriz de 10000×10000 es de 100 segundos.

    También he probado lo siguiente que convertirá la celda en una matriz para que los valores de retorno de las dos funciones sean los mismos:

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

    Esto ralentiza un poco, pero no lo suficiente como para considerar (las líneas se cruzarán a 600×600 en lugar de 400×400).

    Legibilidad

    Es mucho más difícil entender el uso del permute nested y la remodelación. Es una locura usarlo. Aumentará mucho el tiempo de mantenimiento (pero bueno, este es el lenguaje de Matlab, no se supone que sea elegante y reutilizable).

    Futuro

    Las llamadas anidadas para permutar no se expanden correctamente en N dimensiones. Supongo que requeriría un for loop por dimensión (lo que no ayudaría en absoluto al código ya bastante críptico). Por otro lado, haciendo uso de 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 

    Editar (y probado en Matlab también)

    La cantidad de votos ascendentes en la respuesta que sugiere usar permute y remodelar me dio tanta curiosidad que decidí hacer esto en Matlab (R2010b). Los resultados fueron más o menos los mismos, es decir, su rendimiento es realmente pobre. Entonces, a menos que esta operación se realice muchas veces, en matrices que siempre serán pequeñas (menos de 300×300), y siempre habrá un gurú de Matlab alrededor para explicar lo que hace, no lo use.

    Si desea usar un ciclo for, puede hacer esto:

     [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