5

我有个问题。我有一个整数值介于 0 和 5 之间的矩阵A。例如:

x=randi(5,10,10)

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

我尝试了 2 个解决方案:

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

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

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

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

4

2 回答 2

3

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

这是一个小函数,它试图概括 @Floris 所做的事情(该解决方案也返回一个向量而不是所需的矩阵)并实现你正在做的事情nlfilterand colfilt。它不要求输入具有特定的维度并用于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 倍以上。替换histhistc负责两倍加速的因素。当然没有输入检查,因此该函数假定a所有整数等。

最后,请注意randi(IMAX,N,N)返回 range 中的值1:IMAX,而不是0:IMAX您似乎所说的那样。

于 2013-06-01T21:13:54.473 回答
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最多可以有四个值,用于九个像素 - 即四个箱,每个箱有两个值)。

需要考虑的事情。

今天不能给你看一个mex例子(错误的电脑);但是在 Mathworks 网站(以及整个网络)上有很多很好的例子,很容易理解。参见例如http://www.shawnlankton.com/2008/03/getting-started-with-mex-a-short-tutorial/

于 2013-06-01T18:29:48.450 回答