How to "smear" a logical mask without looping

4 Ansichten (letzte 30 Tage)
Sonomatic Australia
Sonomatic Australia am 21 Mär. 2017
Kommentiert: Greg Dionne am 22 Mär. 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 :)

Akzeptierte Antwort

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

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (3)

Stephen23
Stephen23 am 21 Mär. 2017
Bearbeitet: Stephen23 am 21 Mär. 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.
  1 Kommentar
Sonomatic Australia
Sonomatic Australia am 21 Mär. 2017
Thank you Stephen, that's pretty neat! I do need to handle columns with more than one non-zero value. Will keep trying!

Melden Sie sich an, um zu kommentieren.


Guillaume
Guillaume am 21 Mär. 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
  1 Kommentar
Sonomatic Australia
Sonomatic Australia am 22 Mär. 2017
Nice one Guillaume, thank you for that! I'll have to run some comparisons with larger arrays and post results.

Melden Sie sich an, um zu kommentieren.


Guillaume
Guillaume am 22 Mär. 2017
Bearbeitet: Guillaume am 22 Mär. 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.
  1 Kommentar
Sonomatic Australia
Sonomatic Australia am 22 Mär. 2017
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.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Loops and Conditional Statements finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by