Set to zero values in matrix in between two lines

2 views (last 30 days)
p
p on 14 Apr 2022
Answered: yanqi liu on 15 Apr 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.

Answers (4)

Voss
Voss on 14 Apr 2022
Edited: Voss on 14 Apr 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 Comments
Matt J
Matt J on 14 Apr 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;

Sign in to comment.


Scott MacKenzie
Scott MacKenzie on 14 Apr 2022
Edited: Scott MacKenzie on 14 Apr 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 Comment
p
p on 14 Apr 2022
Yes that makes sense, it speeds things up a bit, thanks

Sign in to comment.


p
p on 14 Apr 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 on 15 Apr 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));

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by