How can I speed up (or avoid) a comparison in for loop?

Hi Everyone,
I'm analysing porosity in volumetric image data from CT scans. The input data is logical. 0 indicates background or pores while 1 indicates material.
The code shows a simplified example with two pores. The smaller pore needs to be removed because it's smaller than the threshold. bwlabeln (from the Image Processing Toolbox) changes the zeros of the pores to an ID (look in L-array). After the labelling I can quickly identify the undersized pores (step #1 f-vector).
My problem is the performance of the for-loop (step #2). For large data sets as in my case (A is typically 1000x300x1000 with over 20,000 pores that need to be removed) this takes forever. How can I improve the performance of the for-loop? Or do you have another idea how to delete (change 0 to 1) the small pores from the data set?
Kind regards,
Max
%% create synthetic specimen
A=ones(10,10,10); % background = 0, material = 1
threshold = 10; % min. amount of elements for pore
A(3:5,3:5,3:5)=0; % pore elements = 27 > threshold -> must be kept
A(7:8,7:8,7:8)=0; % pore elements = 8 < threshold -> must be removed
%% preprocessing
r = 1; % rim size
s = size(A); % size of A
a = zeros(s+(r*2));
a(r+1:r+s(1),r+1:r+s(2),r+1:r+s(3)) = A;
A = imbinarize(a); % make logical
AA = imcomplement(A); % inverse image
[L,n] = bwlabeln(AA,6); % label pores
N = histcounts(L); % number of elements with certain value
%% #1. vector with too small pores (Voxel < threshold)
f = find(N<threshold); % find pores with too little elements
f = f-1;
%% #2. set critical values = 1
for i = 1:length(f)
A(L==f(i)) = 1; % A=0 background or pore, A=1 material
% disp(i) % shows that the loop takes forever if length(f) is large
end

 Accepted Answer

Jan
Jan on 17 Sep 2021
Edited: Jan on 17 Sep 2021
What about omitting the loop:
A(ismember(L, f)) = true;
Or:
LUT = [false, N < threshold];
A(LUT(L + 1)) = true;

6 Comments

I cannot test it due to the missing input data and I do not have the image processing toolbox. The lookup table method should be even faster, but might need some debugging.
Time for omiting loop on my test data set with about 25.000 pores (i'm not allowed to share this data):
Method #1: 0.13 sec
Method #2: 0.86 sec
old for-loop: 2600 sec
In my tests, this method is even slower than the original for loop, and certainly much slower than bwlareaopenn.
A=true(1000,300,1000);
N=numel(A);
A( randperm(N,2e4) )=false;
threshold = 10; % min. amount of elements for pore
A0=A;
A=A0;
tic;
AA = imcomplement(A); % inverse image
[L,n] = bwlabeln(AA,6); % label pores
N = histcounts(L); % number of elements with certain value
%% #1. vector with too small pores (Voxel < threshold)
f = find( N<threshold); % find pores with too little elements
f = f-1;
%% #2. set critical values = 1
A(ismember(L, f)) = true;
toc
Elapsed time is 8.438911 seconds.
res1=A;
Nf=numel(f)
Nf = 39993
A=A0;
tic
A=~bwlareaopenn(~A,threshold-1);
toc
Elapsed time is 1.724570 seconds.
res2=A;
isequal(res1,res2)
ans = logical
1
I think my posted example was misleading.
The problem was that the loop took forever because of the large length(f). In the given example with length(f)=1 there were no performance issues. In my data from the CT-scans (lenght(f) > 10000) the other issues of the code had a negligible impact on processing time.
@Matt J Thanks for your help
In my data from the CT-scans (lenght(f) > 10000) the other issues of the code had a negligible impact on processing time.
Maybe negligible compared to the original for-loop, but the use of bwlabeln and histcounts is unnecessary and quite inefficient. I've modified my example above with length(f)=40000 and you can still see that it is much slower than bwlareaopenn.

Sign in to comment.

Products

Release

R2019b

Asked:

on 17 Sep 2021

Commented:

on 17 Sep 2021

Community Treasure Hunt

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

Start Hunting!