用于循环将matrix拆分为相等大小的子matrix

给定一个尺寸为400x400的矩形matrix,我将如何使用for循环将其分解为20x20组成子matrix? 我什至不能想从哪里开始!

我想我想要的东西是这样的:

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

但我不确定如何继续。 思考?

那么,我知道海报明确地要求一个for循环,而Jeff Mather的回答恰恰提供了这个。

但是我还是很好奇,是否有可能将一个matrix分解成给定大小的矩形(子matrix),而没有循环。 如果别人也好奇,我想到了:

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

将二维数组A转换成三维数组T ,其中每个二维片T(:, :, i)是大小为m × 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)给出了二维切片的瓦片索引i, j

提出这些expression式有点像解决一个滑动的谜题。 😉

我很抱歉,我的答案也没有使用for循环,但这也可以做到这一点:

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

然后你可以访问单个单元格,如:

 cellOf20x20matrices{i,j}(a,b) 

其中i,j是要获取的子matrix(如果需要,a,b是对该matrix的索引)

问候

你看起来真的很近 按照你所描述的问题来使用这个问题(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 

即使这个问题基本上是由A. Donda的答案所启发的2Dmatrix,我想扩展他对3Dmatrix的答案,以便这种技术可以用于裁剪真彩色图像(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维。 一旦这个过程完成,尺寸恢复原样,通过排列回来。

结果:

原始图像

在这里输入图像描述

子图(分区/子matrix)

在这里输入图像描述


这种方法的优点是,它也适用于2D图像。 这是一个灰度图像(2D)的例子。 此处使用的示例是MatLab内置图像'cameraman.tif'

在这里输入图像描述

对于使用嵌套调用进行permute的答案,我想到了计时,并与使用mat2cell的其他答案进行比较。

确实,他们没有回报完全一样的东西,但是:

  • 细胞可以很容易地转换成一个像另一个matrix(我定时了这一点,进一步看下去);
  • 当这个问题出现的时候,根据我的经验,把数据放在一个单元里是可取的,因为以后往往会把原来的数据放在一起。

无论如何,我已经将它们与以下脚本进行了比较。 代码运行在八度(版本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) ./ [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 

请注意,Y轴是对数刻度

2分裂二维矩阵在5分裂二维矩阵在10分裂二维矩阵

性能

性能方面,对于较小的matrix,使用嵌套排列只会更快,相对性能的巨大变化实际上是时间的微小变化。 请注意,Y轴是对数刻度 ,因此100x100matrix的两个函数之间的差异是0.02秒,而对于10000x10000matrix,则是100秒。

我也testing了下面这些将单元格转换成matrix,以便两个函数的返回值是相同的:

 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 

这确实减慢了一点,但还不足以考虑(这些行将以600×600而不是400×400交叉)。

可读性

要想使用嵌套排列和重塑是非常困难的。 这很疯狂使用它。 它会增加很多维护时间(但是,嘿,这是Matlab语言,它不应该是优雅的,可重用的)。

未来

嵌套调用置换不会很好地扩展到N维。 我想这将需要一个循环的维(这不会帮助所有已经相当神秘的代码)。 另一方面,利用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中testing)

build议使用排列和重塑的答案upvotes的数量让我如此好奇,我决定在Matlab(R2010b)得到这个testing。 那里的结果几乎是一样的,也就是说,performance真的很差。 所以除非这个操作要做很多次,在matrix中总是很小(小于300×300),总会有一个Matlab大师来解释它的作用,不要用它。

如果你想使用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