How to "smear" a logical mask without looping
4 views (last 30 days)
Show older comments
Sonomatic Australia
on 21 Mar 2017
Commented: Greg Dionne
on 22 Mar 2017
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 :)
0 Comments
Accepted Answer
Greg Dionne
on 22 Mar 2017
Edited: Greg Dionne
on 22 Mar 2017
If you have a recent copy (R2016a) try:
a2 = movmax(a, [n 0]);
3 Comments
More Answers (3)
Stephen23
on 21 Mar 2017
Edited: Stephen23
on 21 Mar 2017
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.
Guillaume
on 21 Mar 2017
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
Guillaume
on 22 Mar 2017
Edited: Guillaume
on 22 Mar 2017
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.
See Also
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!