How to "smear" a logical mask without looping

1 次查看(过去 30 天)
I would like to "smear" a logical mask - fast. There may be a proper term and even standard operation for this but I haven't been able to find them. The following code and image help describe the requirement:
r=20;
c=25;
a=false(r,c);
a(10,3)=true;
a(4,15)=true;
a(18,18)=true;
a2=a;
n=5; %length to "smear"
for j=1:c
i=1;
while i<=r
if a2(i,j);
a2(i:(i+n),j)=true;
i=i+n;
end
i=i+1;
end
end
a2=a2(1:r,:);
figure(1)
colormap(flipud(gray))
subplot(1,2,1)
imagesc(a)
title('Input')
subplot(1,2,2)
imagesc(a2)
title('Desired Output')
This is easy in a loop but very slow for large arrays. I've managed a few approaches without loops, some are faster but still messy and I'm sure there is a better way! Hence posting it here for the Gurus :)

采纳的回答

Greg Dionne
Greg Dionne 2017-3-22
编辑:Greg Dionne 2017-3-22
If you have a recent copy (R2016a) try:
a2 = movmax(a, [n 0]);
  3 个评论
Sonomatic Australia
Wow how good is that!? Time to update my Matlab then!
Greg Dionne
Greg Dionne 2017-3-22
Thanks Guillaume,
I've updated the answer accordingly.
-G

请先登录,再进行评论。

更多回答(3 个)

Stephen23
Stephen23 2017-3-21
编辑:Stephen23 2017-3-21
I have no idea how fast this is, but it is relatively compact:
>> idx = cumsum(cumsum(a,1),1);
>> out = 0<idx & idx<=n
out =
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
Note that this method will not work if there are more than one non-zero value in a column. It could be adapted for that situation though.
  1 个评论
Sonomatic Australia
Thank you Stephen, that's pretty neat! I do need to handle columns with more than one non-zero value. Will keep trying!

请先登录,再进行评论。


Guillaume
Guillaume 2017-3-21
This would work regardless of the numbers of non-zero values in each column. The loop is only over the length of the smear, so should be fairly fast:
a2 = a;
smearlength = 5;
for s = 1 : smearlength
a2 = a2 | [zeros(s, size(a, 2)); a(1:end-s, :)];
end
  1 个评论
Sonomatic Australia
Nice one Guillaume, thank you for that! I'll have to run some comparisons with larger arrays and post results.

请先登录,再进行评论。


Guillaume
Guillaume 2017-3-22
编辑:Guillaume 2017-3-22
And here is a one liner that also works regardless of the numbers of ones in each column:
%a: logical matrix
%n: number of 1s to add to each smear
a2 = any(a(permute(toeplitz(1:size(a, 1), ones(1, n+1)), [1 3 2]) + (0:size(a, 1):numel(a)-1)), 3);
Requires R2016b or later (otherwise use bsxfun for the +) and is probably not faster than my loop answer.
edit: actually, it is faster than the loop on my machine. But not as fast as Stephen's answer.
  1 个评论
Sonomatic Australia
Thank you Guillaume, I need some time to understand that one! For interest, I setup the following and did a quick test:
r=50000;
c=10000;
a=false(r,c);
ntrue=round(r*c*0.3);
b=round(rand(20,1)*numel(a));
a(b)=true;
n=30; %length to "smear"
Your method which loops for "n" took 183.267894 s. The method in the original question took 6.552720 s which surprised me.

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Creating and Concatenating Matrices 的更多信息

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by