0

I can make a non-linear mask based on the two arrays containing lower and higher boundary of the mask. All values in between need to be set to 1. The way I do this now seems to take quite a lot of time and it is becoming a bottleneck. I was wondering if there is a way to do it more time efficient.

First, I was thinking to solve it using parfors to increase the speed. But since this is one of the inner loops in my code these seem highly inefficient since it's more feasible using parfor on the outer loop considering schedule overhead. So parallel techniques are not an option.

See here the creation of the mask:

mask = zeros(size(im));
n = length(bufLow);

for i=1:1:n                 
   mask(bufLow(i):bufHigh(i),i) = 1;
end    

im is an matrix of a certain size and bufLow and bufHigh are arrays in size equal to the horizontal size of im describing the higher and lower boundaries for each column of im. In between these values everything needs to be set to 1.

So the goal is to have something that reduces the execution time of this loop as much as possible. I was wondering if there is somebody with some the knowledge to enlight me.

Bests,

Matthijs

Whiteshift
  • 19
  • 6
  • Unfortunately, the code you provided is no [minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve). What is `im`, what does it look like? What do `bufLow` and `bufHigh` look like? And, there's a typo: `lenght` instead of `length`. For the future, please pay attention to such details when posting questions on Stack Overflow. – HansHirse Jun 06 '19 at 05:01

1 Answers1

1

I admit, that your question allows for some interpretation and guesswork, but from the code you provided, I have an idea, what you want to achieve: For the i-th column in your mask you want to set all pixels between a start index (that would be bufLow(i)) and an end index (bufHigh(i)) to 1. Is that correct?

So, my idea to "vectorize" your loop would be to translate the "per column" subscript (or array) indices in your bufxxx to "image" linear indices and then find all linear indices between the start and end indices. The latter is a (common) problem, which has already several significant answers, like this one from Divakar.

I incorporated his answer in my solution. Please, see the following code:

dim = 25;

bufLow = int32(10 * rand(1, dim) + 1);
bufHigh = int32(10 * rand(1, dim) + 15);

% Reference implementation from question
mask = zeros(dim);
n = length(bufLow);
for i=1:1:n                 
   mask(bufLow(i):bufHigh(i), i) = 1;
end  

% Show mask
figure(1);
imshow(mask);

% Implementation using Divakar's approach

% Translate subscript indices to linear indices
bufLow = bufLow + (dim .* (0:dim-1));
bufHigh = bufHigh + (dim .* (0:dim-1));

% Divakar's approach for finding all indices between two boundaries
lens = bufHigh - bufLow + 1;
shift_idx = cumsum(lens(1:end-1)) + 1;
id_arr = ones(1, sum(lens));
id_arr([1 shift_idx]) = [bufLow(1) bufLow(2:end) - bufHigh(1:end-1)];
out = cumsum(id_arr);

% Generating mask
mask2 = zeros(dim);
mask2(out) = 1;

% Show mask
figure(2);
imshow(mask2);

The resulting masks are identical and look like this:

Mask

To have a look on the performance, I set up a separate timing script using both approaches on increasing dimension dim from 25 to 2500 in steps of 25. The result looks like this:

Comparison

Hope that helps!

HansHirse
  • 18,010
  • 10
  • 38
  • 67