高效实现`im2col`和`col2im`

9

im2colcol2im是MATLAB处理图像时矢量化的重要函数,但需要MATLAB的图像处理工具箱。

我的问题是,是否有一种高效(矢量化)的方式可以在不使用工具箱的情况下实现这些功能?
我需要使用“sliding”和“distinct”模式。

我不需要任何填充。

谢谢。


这可能会有所帮助:https://dev59.com/S2Ij5IYBdhLWcg3wYUGQ - Luis Mendo
嗨,不完全是,因为创建多维数组,而我需要的数组(在“滑动”选项中)是二维的。 - Royi
2个回答

18

我只希望Mathworks的人不会起诉你或我,甚至包括Stackoverflow,因为他们对IP工具箱功能设置了价格,试图创建向量化实现。但无论如何,请忘记这些问题,下面是实现方法。

替代使用'sliding'选项的im2col

在写Stackoverflow上另一个问题的解决方案之前,我无法将其向量化。因此,我强烈建议您也研究一下。

function out = im2col_sliding(A,blocksize)

nrows = blocksize(1);
ncols = blocksize(2);

%// Get sizes for later usages
[m,n] = size(A);

%// Start indices for each block
start_ind = reshape(bsxfun(@plus,[1:m-nrows+1]',[0:n-ncols]*m),[],1); %//'

%// Row indices
lin_row = permute(bsxfun(@plus,start_ind,[0:nrows-1])',[1 3 2]);  %//'

%// Get linear indices based on row and col indices and get desired output
out = A(reshape(bsxfun(@plus,lin_row,[0:ncols-1]*m),nrows*ncols,[]));

return;

替代带有 'distinct' 选项的 im2col。
function out = im2col_distinct(A,blocksize)

nrows = blocksize(1);
ncols = blocksize(2);
nele = nrows*ncols;

row_ext = mod(size(A,1),nrows);
col_ext = mod(size(A,2),ncols);

padrowlen = (row_ext~=0)*(nrows - row_ext);
padcollen = (col_ext~=0)*(ncols - col_ext);

A1 = zeros(size(A,1)+padrowlen,size(A,2)+padcollen);
A1(1:size(A,1),1:size(A,2)) = A;

t1 = reshape(A1,nrows,size(A1,1)/nrows,[]);
t2 = reshape(permute(t1,[1 3 2]),size(t1,1)*size(t1,3),[]);
t3 =  permute(reshape(t2,nele,size(t2,1)/nele,[]),[1 3 2]);
out = reshape(t3,nele,[]);

return;

一些快速测试表明,这两种实现尤其是滑动窗口用于小到相当大小的输入数据和所有数据大小的不同之处在运行时性能方面比内置的MATLAB函数实现表现要好得多。
如何使用
With in-built MATLAB function - 
B = im2col(A,[nrows ncols],'sliding')

With our custom function - 
B = im2col_sliding(A,[nrows ncols])

%// ------------------------------------

With in-built MATLAB function - 
B = im2col(A,[nrows ncols],'distinct')

With our custom function - 
B = im2col_distinct(A,[nrows ncols])

1
@Drazick,这里有两个MATLAB规则-1)并非每个for循环都可向量化2)并非每个可向量化的循环都保证比其for循环对应物更好。现在使用im2colsliding选项,它肯定看起来比此处呈现的更好,但正如解决方案中指出的那样,在没有访问IP工具箱时,请使用此选项。 - Divakar
1
嗨@Drazick,我按照你的评论进行了操作,但现在我认为你已经得到了所需的答案。对于“distinct”的向量化是“直截了当的”,就像Divakar在这里展示的那样。就我所看到的,'sliding'的向量化使用特别构造的索引矩阵-无论这是否使事情更快,我无法确定。不过,我希望Markus指出的Octave实现非常有效。 - A. Donda
1
@A.Donda 好了,最终我认为我们在编辑的代码中有向量化的解决方案了! :) - Divakar
@Divakar,太好了。我会尝试并报告结果。顺便问一下,对于大矩阵,它是否更快?谢谢。 - Royi
1
@Drazick bsxfun 的问题在于它需要大量资源。因此,我会猜测对于小型输入来说,使用 bsxfun 会更好,即使与去除了 im2col 版本的方法相比,我也会支持它。但是,如果你要处理更大的输入,你去除了版本可能会更胜一筹。如果你想发布基准测试结果,那会很有趣。 - Divakar
显示剩余14条评论

3
您可以使用GNU Octave的图像包image进行作弊。它实现了脚本语言中的im2col和col2im功能: 我看到最大的区别在于不同的注释风格(#而不是%)和不同的字符串风格(“而不是')。如果您更改这些并删除底部的断言测试,它可能已经可运行了。如果不行,请使用调试器进行调试。
此外,请注意许可证(GPLv3)。它是免费的,但您所做的更改也必须是免费的!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接