用于循环以将矩阵分割成相等大小的子矩阵

use*_*703 11 matlab loops octave

给定一个说大小的方阵400x400,如何将其拆分为20x20使用for-loop的组成子矩阵?我甚至不知道从哪里开始!

我想我想要的东西:

[x,y] = size(matrix)

for i = 1:20:x
    for j = 1:20:y
Run Code Online (Sandbox Code Playgroud)

但我不确定如何继续下去.思考?

A. *_*nda 23

嗯,我知道海报明确要求for循环,而杰夫马瑟的回答恰恰提供了.

但我仍然很好奇是否有可能在没有循环的情况下将矩阵分解为给定大小的瓦片(子矩阵).如果其他人也很好奇,这就是我想出的:

T = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3])
Run Code Online (Sandbox Code Playgroud)

将二维数组A转换为三维数组T,其中每个2d切片T(:, :, i)是大小为mx的切片之一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]);
Run Code Online (Sandbox Code Playgroud)

制作T一个四维数组,T(:, :, i, j)给出带有图块索引的2d切片i, j.

提出这些表达感觉有点像解决滑动拼图.;-)

  • @carandraug.你把我的回答称为"可怕的",这是一个非常强烈的词,你暗中称我为"大师",这仍然不是很好.说真的,这里有什么大不了的?路易斯·门多和其他大多数其他赞成者所意识到的是,这是一种极端矢量化的练习,对我而言,显然是对我来说很有趣和有趣. (4认同)
  • 如果您有图像处理工具箱,则可以使用`blockproc`迭代地将函数句柄应用于图像/矩阵的子部分.例如:`blockproc(M,[20 20],@ myAwesomeFunction)` (3认同)
  • 惊人的工作.+1我将你的答案扩展到3D矩阵.查看! (3认同)

Kla*_*CPH 14

对不起,我的回答也没有使用for循环,但这也可以解决问题:

cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)
Run Code Online (Sandbox Code Playgroud)

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

cellOf20x20matrices{i,j}(a,b)
Run Code Online (Sandbox Code Playgroud)

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

问候


Jef*_*her 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
Run Code Online (Sandbox Code Playgroud)

  • @ user3058703,如果这个答案符合您的要求,您应该接受它(点击勾勒出的复选标记,使其变为绿色). (2认同)

San*_*lai 8

虽然问题基本上是针对2D矩阵,但受到A. Donda的回答的启发,我想扩展他对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
Run Code Online (Sandbox Code Playgroud)

基本思路是在重塑时不使第3维度受影响,以免图像失真.为实现此目的,进行了额外的置换以交换第3维和第4维.完成该过程后,通过置换来恢复尺寸.

结果:

原始图像

在此输入图像描述

子图(分区/子矩阵)

在此输入图像描述


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

在此输入图像描述


car*_*aug 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
Run Code Online (Sandbox Code Playgroud)

请注意,Y轴是对数刻度

在2中拆分2D矩阵 在5中拆分2D矩阵 在10中拆分2D矩阵

性能

性能方面,对于较小的矩阵,使用嵌套的置换只会更快,相对性能的重大变化实际上是非常小的时间变化.请注意,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
Run Code Online (Sandbox Code Playgroud)

这确实减慢了一点但不足以考虑(线将以600x600而不是400x400交叉).

可读性

让你的头围绕使用嵌套的置换和重塑是非常困难的.使用它真是太疯狂了.它会增加很多维护时间(但是,嘿,这是Matlab语言,它不应该是优雅和可重用的).

未来

对置换的嵌套调用根本不能很好地扩展到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
Run Code Online (Sandbox Code Playgroud)

编辑(并在Matlab中测试)

对答案表示使用置换和重塑的答案的数量让我非常好奇,我决定在Matlab(R2010b)中进行测试.结果几乎相同,即它的表现非常糟糕.因此,除非这个操作将会进行很多次,总是很小(小于300x300)的矩阵,并且总会有一个Matlab大师来解释它的作用,不要使用它.