【问题标题】:Average a subset of a matrix in a loop in matlab在matlab中的循环中平均矩阵的子集
【发布时间】:2015-07-27 14:51:21
【问题描述】:

我使用我认为是矩阵的图像。

我想将 800 x 800 矩阵 (A) 转换为 400 x 400 矩阵 (B),其中 A 矩阵的 4 个单元格的平均值 = B 矩阵的 1 个单元格(我知道这不是正确的代码行) :

B[1,1] =mean2(A[1,1 + 1,2 + 2,1 + 2,2]) 

整个矩阵以此类推...

B [1,2]=mean2(A[1,3 + 1,4 + 2,3 + 2,4 ])

我想:

1) 将 A 矩阵重塑为 2 x 320 000 矩阵,这样我就可以得到需要平均的四个单元格,并且之后更容易处理行号。

Im4bis=reshape(permute(reshape(Im4,size(Im4,2),2,[]),[2,3,1]),2,[]);

2) 创建一个包含我需要平均(子集)的 4 个单元格的单元格数组并计算它的平均值。这就是它不起作用的地方

I{1,160000}=ones,
for k=drange(1:2:319999)
    for n=1:160000
        I{n}=mean2(Im4bis(1:2,k:k+1));
    end
end

我创建了一个 400 x 400 单元格的空矩阵(实际上是一个 1 x 160000 的向量),我想用平均值填充它,但我得到了一个 1 x 319 999 单元格的矩阵,其中 2 个单元格中有一个是空的。

寻找光明

我的输入图像:

【问题讨论】:

    标签: matlab image-processing matrix mean subset


    【解决方案1】:

    方法一

    使用mat2cellcellfun

    AC = mat2cell(A, repmat(2,size(A,1)/2,1), repmat(2,size(A,2)/2,1));
    
    out = cellfun(@(x) mean(x(:)), AC);
    

    方法二

    使用im2col

    out = reshape(mean(im2col(A,[2 2],'distinct')),size(A)./2);
    

    方法三

    使用简单 for循环

    out(size(A,1)/2,size(A,2)/2) = 0;
    k = 1;
    for i = 1:2:size(A,1)
        l = 1;
        for j = 1:2:size(A,2)
            out(k,l) = mean(mean(A(i:i+1,j:j+1)));
            l = l+1;
        end
        k = k+1;
    end
    

    输入图像测试:

    A = rgb2gray(imread('inputImage.png'));
    
    %// Here, You could use any of the method from any answers 
    %// or you could use the best method from the bench-marking tests done by Divakar
    out = reshape(mean(im2col(A,[2 2],'distinct')),size(A)./2);  
    
    imshow(uint8(out));  
    
    imwrite(uint8(out),'outputImage.bmp');
    

    输出图像:

    通过读取已经写入的图像进行最终检查

    B = imread('outputImage.bmp');
    
    >> whos B
    
    Name        Size              Bytes  Class    Attributes
    
    B         400x400            160000  uint8              
    

    【讨论】:

    • 不错的方法,很干净
    • 谢谢,你也照常 :) @LuisMendo
    • 所有 3 种方法都给了我相同的结果,matlab 工作区中的一个 400 x 400 矩阵,但是当我将它作为 BMP 时,它是一个 574 x 495 像素的图像。因此,这与@Luis Mendo 提出的方法相同。我不知道矩阵大小和图像大小有什么区别??我知道我需要 400 x 400 像素/单元,因为我会计算这个图像。
    • @Sarahdata 当输入 A 是输出574 x 495 作为输出图像大小的位图图像时,给我们“whos(A)”信息?
    • @Sarahdata 您可以添加原始图像(可能是对问题的编辑)吗?我猜你有足够的代表上传图片
    【解决方案2】:

    A 表示您的矩阵和

    m = 2; %// block size: rows
    n = 2; %// block size: columns
    

    方法一

    使用blockproc:

    B = blockproc(A, [m n], @(x) mean(x.data(:)));
    

    例子:

    >> A = magic(6)
    A =
        35     1     6    26    19    24
         3    32     7    21    23    25
        31     9     2    22    27    20
         8    28    33    17    10    15
        30     5    34    12    14    16
         4    36    29    13    18    11
    >> B = blockproc(A, [m n], @(x) mean(x.data(:)))
    B =
       17.7500   15.0000   22.7500
       19.0000   18.5000   18.0000
       18.7500   22.0000   14.7500
    

    方法二

    如果您更喜欢重塑方式(可能更快),请使用this great answer 将矩阵组织成沿第三维平铺的 2x2 块,沿前两个维度平均,然后重塑结果:

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

    方法3

    应用二维卷积 (conv2),然后进行下采样。卷积计算的条目比实际需要的多(因此需要下采样),但另一方面,它可以在 separably 完成,这有助于加快速度:

    B = conv2(ones(m,1)/m, ones(1,n)/n ,A,'same');
    B = B(m-1:m:end ,n-1:n:end);
    

    【讨论】:

    • 方法 1 和方法 2 给我相同的结果,matlab 工作区中的 400 x 400 变量,但我将其保存为 BMP 的 1366 x 652 像素图像。我最初的愿望是获得 400 x 400 像素的图像……我不明白。在方法2中,为什么要两次申请mean?因为我们是二维的?
    • 当我使用 800x800 输入时,我的三种方法(以及其他答案)给了我 400x400 的输出。是的,mean 应用了两次以沿每个块的两个维度进行平均
    【解决方案3】:

    一种基于this solution 的方法,使用reshapesumsqueeze -

    sublen = 2; %// subset length
    part1 = reshape(sum(reshape(A,sublen,[])),size(A,1)/sublen,sublen,[]);
    out = squeeze(sum(part1,2))/sublen^2;
    

    基准测试

    设置 #1

    这是迄今为止列出的方法的运行时比较,输入数据大小为800x 800 -

    %// Input
    A = rand(800,800);
    
    %// Warm up tic/toc.
    for k = 1:50000
        tic(); elapsed = toc();
    end
    
    disp('----------------------- With  RESHAPE + SUM + SQUEEZE')
    tic
    sublen = 2; %// subset length
    part1 = reshape(sum(reshape(A,sublen,[])),size(A,1)/sublen,sublen,[]);
    out = squeeze(sum(part1,2))/sublen^2;
    toc, clear sublen part1 out
    
    disp('----------------------- With  BLOCKPROC')
    tic
    B = blockproc(A, [2 2], @(x) mean(x.data(:))); %// [m n]
    toc, clear B
    
    disp('----------------------- With  PERMUTE + MEAN + RESHAPE')
    tic
    m = 2;n = 2;
    T = permute(reshape(permute(reshape(A, size(A, 1), n, []),...
          [2 1 3]), n, m, []), [2 1 3]);
    B = reshape(mean(mean(T,1),2), size(A,1)/m, size(A,2)/m);
    toc, clear B T m n
    
    disp('----------------------- With  CONVOLUTION')
    tic
    m = 2;n = 2;
    B = conv2(ones(m,1)/m, ones(1,n)/n ,A,'same');
    B = B(m-1:m:end ,n-1:n:end);
    toc, clear m n B
    
    disp('----------------------- With  MAT2CELL')
    tic
    AC = mat2cell(A, repmat(2,size(A,1)/2,1), repmat(2,size(A,2)/2,1));
    out = cellfun(@(x) mean(x(:)), AC);
    toc
    
    disp('----------------------- With  IM2COL')
    tic
    out = reshape(mean(im2col(A,[2 2],'distinct')),size(A)./2);
    toc
    

    运行时结果 -

    ----------------------- With  RESHAPE + SUM + SQUEEZE
    Elapsed time is 0.004702 seconds.
    ----------------------- With  BLOCKPROC
    Elapsed time is 6.039851 seconds.
    ----------------------- With  PERMUTE + MEAN + RESHAPE
    Elapsed time is 0.006015 seconds.
    ----------------------- With  CONVOLUTION
    Elapsed time is 0.002174 seconds.
    ----------------------- With  MAT2CELL
    Elapsed time is 2.362291 seconds.
    ----------------------- With  IM2COL
    Elapsed time is 0.239218 seconds.
    

    为了使运行时更加公平,我们可以在最快的三种方法的基础上使用1000 的多个试验,以获得相同的输入数据大小800 x 800,给我们 -

    ----------------------- With  RESHAPE + SUM + SQUEEZE
    Elapsed time is 1.264722 seconds.
    ----------------------- With  PERMUTE + MEAN + RESHAPE
    Elapsed time is 3.986038 seconds.
    ----------------------- With  CONVOLUTION
    Elapsed time is 1.992030 seconds.
    

    设置 #2

    这是10000x 10000 的较大输入数据大小的运行时比较,用于最快的三种方法 -

    ----------------------- With  RESHAPE + SUM + SQUEEZE
    Elapsed time is 0.158483 seconds.
    ----------------------- With  PERMUTE + MEAN + RESHAPE
    Elapsed time is 0.589322 seconds.
    ----------------------- With  CONVOLUTION
    Elapsed time is 0.307836 seconds.
    

    【讨论】:

    • 不错!并且可以很容易地推广到矩形块
    • 感谢运行时结果 :)。只认为左边是一个简单的for 循环。
    • 为什么?有没有相关的帖子?
    • @SanthanSalai 好吧,2 x 2,我的直觉是 JIT 会厌倦索引(那时会有很多!)并会放弃 :)
    • @SanthanSalai 试过了,结果对 JIT 来说太糟糕了,真的太糟糕了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 2011-10-21
    • 2016-02-17
    • 2013-09-23
    • 1970-01-01
    相关资源
    最近更新 更多