Set to zero values in matrix in between two lines

1 vue (au cours des 30 derniers jours)
Stephane
Stephane le 14 Avr 2022
Hello,
I would like to vectorize the following operation:
Given a 2D matrix/image and the slope and intercept of two lines (that don't cross each other within the matrix), I would like to put the values of the matrix (the pixels) in the band defined by the two lines to zero. I realize this is not clear but this exemple should illustrate well what I mean:
width=1000;
height=200;
A=rand(height,width); % create a random matrix/image
% slopes (s) and intersects (b) of two lines
s1=-0.1;
b1=130;
s2=-0.11;
b2=150;
% values of the matrix = 0 in between the two lines
for ii=1:width
for jj=floor(s1*ii+b1):floor(s2*ii+b2)
A(jj,ii)=0;
end
end
Then A looks like this (using imshow), where the boundaries of the dark triangle are the two lines define by s1,b1 and s2,b2
This works, but I didn't manage to vectorize this piece of code.
Thanks for the help.

Réponses (4)

Voss
Voss le 14 Avr 2022
Modifié(e) : Voss le 14 Avr 2022
width=1000;
height=200;
A=rand(height,width); % create a random matrix/image
subplot(3,1,1);
imshow(A)
% slopes (s) and y-intercepts (b) of two lines
s1=-0.1;
b1=130;
s2=-0.11;
b2=150;
A1 = A; % make copies for comparison at the end
A2 = A;
% values of the matrix = 0 in between the two lines
% 1) vectorized method
[x,y] = meshgrid(1:width,1:height);
A1(floor(s1*x+b1) <= y & floor(s2*x+b2) >= y) = 0;
subplot(3,1,2);
imshow(A1)
% 2) original method
for ii=1:width
for jj=floor(s1*ii+b1):floor(s2*ii+b2)
A2(jj,ii)=0;
end
end
subplot(3,1,3)
imshow(A2)
% check that the two methods give the same result
isequal(A1,A2)
ans = logical
1
  2 commentaires
Stephane
Stephane le 14 Avr 2022
Thank you!
This is slower than the previous answer with a single for loop, but I think this makes sense given that with this method you do more calculations on matrices. But still this made me think of a way of doing it faster (see my answer below) using linear indices, so thanks!
Matt J
Matt J le 14 Avr 2022
Modifié(e) : Matt J le 14 Avr 2022
Speed things up a bit more by avoiding meshgrid() and floor().
[x,y] =deal(1:width,(1:height).');
A1(s1*x+b1 <= y & s2*x+b2 >= y) = 0;

Connectez-vous pour commenter.


Scott MacKenzie
Scott MacKenzie le 14 Avr 2022
Modifié(e) : Scott MacKenzie le 14 Avr 2022
You can vectorize the inner loop:
% values of the matrix = 0 in between the two lines
for ii=1:width
A(floor(s1*ii+b1):floor(s2*ii+b2),ii) = 0;
end
Not sure if you can vectorize the entire sequence of assignments.
  1 commentaire
Stephane
Stephane le 14 Avr 2022
Yes that makes sense, it speeds things up a bit, thanks

Connectez-vous pour commenter.


Stephane
Stephane le 14 Avr 2022
Previous answers made me think of a way of doing this but using linear indices to limit the number of operations. What follow seems to be the fastest method so far.
ii=0:(width-1);
% id1 and id2 are the linear indices such that we want
% A(id1(1):id2(1))=0, ..., A(id1(end):id2(end))=0
id1 = floor(s1*ii+b1) + ii*height;
id2 = floor(s2*ii+b2) + ii*height;
% coloncatrld from https://blogs.mathworks.com/loren/2008/10/13/vectorizing-the-notion-of-colon/
% id=[id1(1):id2(1), ... , id1(end):id2(end)]
id=coloncatrld(id1, id2);
A(id)=0;

yanqi liu
yanqi liu le 15 Avr 2022
yes,sir,may be use mask to process,such as
width=1000;
height=200;
A=rand(height,width); % create a random matrix/image
figure; imshow(mat2gray(A));
% slopes (s) and intersects (b) of two lines
s1=-0.1;
b1=130;
s2=-0.11;
b2=150;
% vector
x = linspace(1, size(A, 2), 1e3);
y1 = s1*x + b1;
y2 = s2*x + b2;
pts = [x fliplr(x) x(1)
y1 fliplr(y2) y1(1)];
mk = roipoly(A,round(pts(1,:)), round(pts(2,:)));
A(mk) = 0;
figure; imshow(mat2gray(A));

Catégories

En savoir plus sur Logical dans Help Center et File Exchange

Produits


Version

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by