usar loop for como comandos ciclo matlab loops octave

matlab - loop - if octave



Para matriz de bucle para dividir submatrices de igual tamaƱo (6)

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?


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

Subtramas (Particiones / Sub Matrices)

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 ''cameraman.tif''


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 2d rebanada 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. ;-)


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

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

Actuación

En cuanto al rendimiento, usar el permute anidado 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 100x100 es de 0.02 segundos, mientras que para una matriz de 10000x10000 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) ./ [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

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

Legibilidad

Es mucho más difícil entender el uso del permute anidado 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 300x300), y siempre habrá un gurú de Matlab alrededor para explicar lo que hace, no lo use.


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


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