给定一个大小为400x400
的方阵,如何使用for循环将其拆分为20x20
的组成子矩阵?我甚至想不到从哪里开始!
我想我想要这样的东西:
[x,y] = size(matrix)
for i = 1:20:x
for j = 1:20:y
但我不确定如何继续。想法?
答案 0 :(得分:23)
嗯,我知道海报明确要求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 {{ 1}}。第三个索引以标准Matlab线性化顺序枚举切片,首先是切片行。
变体
n
使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
为第2个切片提供了瓦片索引T(:, :, i, j)
。
提出这些表达感觉有点像解决滑动拼图。 ; - )
答案 1 :(得分:14)
我很抱歉我的回答也没有使用for循环,但这也可以解决问题:
cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)
然后,您可以访问单个单元格,如:
cellOf20x20matrices{i,j}(a,b)
其中i,j是要获取的子矩阵(如果需要,a,b是索引到该矩阵中)
此致
答案 2 :(得分:10)
你似乎很亲密。只是按照你所描述的那样使用问题(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
答案 3 :(得分:8)
尽管问题基本上是针对2D矩阵的,但受A. Donda's answer的启发,我想扩展他对3D矩阵的回答,以便这种技术可用于裁剪真彩色图像(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'
答案 4 :(得分:6)
对于使用嵌套调用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轴是对数刻度,因此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语言,它不应该是优雅和可重用的。)
对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(R2010b)中进行测试。结果几乎相同,即它的表现非常糟糕。因此,除非此操作将在批次中完成,在矩阵中总是很小(小于300x300),并且总会有一位Matlab大师来解释它的作用,并且#39 ;使用它。
答案 5 :(得分:0)
如果你想使用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