【问题标题】:Matlab fast neighborhood operationMatlab快速邻域运算
【发布时间】:2013-06-01 09:27:42
【问题描述】:

我有一个问题。我有一个 Matrix A,其整数值介于 0 和 5 之间。 例如:

x=randi(5,10,10)

现在我想调用一个过滤器,大小为 3x3,它给了我最常见的值

我尝试了两种解决方案:

fun = @(z) mode(z(:));
y1 = nlfilter(x,[3 3],fun);

这需要很长时间......

y2 = colfilt(x,[3 3],'sliding',@mode);

这也需要很长时间。 我有一些非常大的矩阵,两种解决方案都需要很长时间。 有没有更快的方法?

【问题讨论】:

  • 模式过滤器总是很慢,因为它必须对值进行直方图然后寻找最常见的值 - 所以你最终会多次通过我们的数据。在“vanilla matlab”中实现,速度非常慢。通过为自己编写一个小的mex 例程,您可能会快得多 - 这是一个很容易上手的问题。需要指点吗?
  • 嗯...我从来没有写过 mex 例程...你知道我可以拿一个简单的例子吗?我会更容易上手。

标签: matlab filter


【解决方案1】:

+1 给@Floris 以获得使用hist 的绝佳建议。它非常快。不过你可以做得更好一点。 hist 是基于histc 的,可以替代使用。 histc 是一个编译函数,即不是用 Matlab 编写的,这就是解决方案更快的原因。

这是一个小函数,它试图概括 @Floris 所做的事情(该解决方案也返回一个向量而不是所需的矩阵)并实现您使用 nlfiltercolfilt 所做的事情。它不要求输入具有特定的维度并使用im2col 来有效地重新排列数据。事实上,前三行和对im2col 的调用与colfit 在您的情况下所做的几乎相同。

function a=intmodefilt(a,nhood)
[ma,na] = size(a);
aa(ma+nhood(1)-1,na+nhood(2)-1) = 0;
aa(floor((nhood(1)-1)/2)+(1:ma),floor((nhood(2)-1)/2)+(1:na)) = a;
[~,a(:)] = max(histc(im2col(aa,nhood,'sliding'),min(a(:))-1:max(a(:))));
a = a-1;

用法:

x = randi(5,10,10);
y3 = intmodefilt(x,[3 3]);

对于大型阵列,这比我机器上的 colfilt 快 75 倍以上。将hist 替换为histc 可实现两倍的加速。当然没有输入检查,因此该函数假定a 是所有整数,等等。

最后,请注意randi(IMAX,N,N) 返回的值在1:IMAX 范围内,而不是您所说的0:IMAX

【讨论】:

  • 哇,这太棒了。我只需要将 a=a-1 更改为 a=a-2 什么的。现在它正是我想要的。它比 colfilt 快 50 倍 :) 明天我将尝试检查代码以提高我的技能
  • 函数的最后一行 a = a-1;max 的第二个输出参数从基于 1 的索引转换为基于 0 的索引。如果min(a(:)) = 1,这会将输出矩阵的边界设置为0,并且值的范围从1max(a(:))(在您的示例中为15)。在您的示例中,使用a = a-2; 会将矩阵的内部部分从0 转移到4
  • 是的,我明白了:)。这真的令人印象深刻。我今天学到了很多
  • @horchler 感谢您提供有趣的解决方案!我想知道如何根据圆形社区进行重新安排?例如,邻域现在由一个圆给出,你有它的半径吗?如何将每个滑动圆圈内的像素放入列中?我在这里发布了这个问题 => stackoverflow.com/questions/21750989/…
【解决方案2】:

一个建议是重塑您的数组,使每个 3x3 块成为一个列向量。如果您的初始数组尺寸可以被 3 整除,这很简单。如果他们不这样做,您需要更加努力地工作。你需要重复这九次,从矩阵的不同偏移量开始——我将把它作为练习。

这里有一些代码显示了基本思想(仅使用 FreeMat 中可用的功能 - 我家里的机器上没有 Matlab...):

N = 100;
A = randi(0,5*ones(3*N,3*N));
B = reshape(permute(reshape(A,[3 N 3 N]),[1 3 2 4]), [ 9 N*N]);
hh = hist(B, 0:5); % histogram of each 3x3 block: bin with largest value is the mode
[mm mi] = max(hh); % mi will contain bin with largest value
figure; hist(B(:),0:5); title 'histogram of B'; % flat, as expected
figure; hist(mi-1, 0:5); title 'histogram of mi' % not flat?...

下面是图:

奇怪的是,当您运行此代码时,mi 的分布并不平坦,而是偏向较小的值。当您检查直方图时,您会发现这是因为您经常会有多个包含“最大值”值的 bin。在这种情况下,您将获得第一个具有最大数量的 bin。这显然会严重扭曲您的结果;需要考虑的事情。更好的过滤器可能是中值过滤器 - 上下相邻像素数量相等的过滤器。这有一个独特的解决方案(而mode 最多可以有四个值,用于九个像素 - 即,四个 bin,每个 bin 有两个值)。

想一想。

今天无法向您展示mex 示例(计算机错误);但是在 Mathworks 网站(以及整个网络)上有很多很好的例子,很容易理解。参见例如http://www.shawnlankton.com/2008/03/getting-started-with-mex-a-short-tutorial/

【讨论】:

  • 感谢您的帮助。 resharp 数组的建议是我必须尝试看看它是否比 colfilt 更快...我也考虑过使用中值滤波器,但我认为这不是适合我的解决方案...我也尝试解决它如果不难的话,和mex一起。再次感谢:)
  • @Floris,感谢您的帖子!我们如何重塑数据,但现在基于圆形邻域?圆形社区由其radius 给出。我正在尝试解决此处发布的问题 => stackoverflow.com/questions/21750989/…
  • @Tin - 有趣的问题。我怀疑您可以一次创建一个“邻居偏移”向量;有关详细信息,请参阅我的回答 stackoverflow.com/questions/21462711/…。如果这无济于事,请发表其他评论,我会尝试看看。
猜你喜欢
  • 2013-06-15
  • 2012-10-25
  • 1970-01-01
  • 2013-05-26
  • 2019-11-15
  • 2015-04-27
  • 2012-03-18
  • 1970-01-01
  • 2013-09-02
相关资源
最近更新 更多