Vectorization to store images in a 3D array?

I have a multitiff image which I want to store as a 3D array.
Here is the function I am using. However, I wanted to know if there is a way to vectorize the for loop at the end of the code to reduce processing time.
function Images = readMultiTiff(TifImage)
%Get the information in the multitiff image
info = imfinfo(TifImage);
%Get the number of images in the multitiff image
num_images = numel(info);
%Determine height and width
width = info.Width;
height = info.Height;
%Create an empty array the size of each image in the multitiff
BlankImage =zeros(width,height);
%Use that to build a 3D array to store all the tiff images in the multitiff
Images = uint16(zeros(size(BlankImage,2),size(BlankImage,1),num_images));
%Read and assign each image to SEMImages.
mywaitbar_handle = waitbar(0, 'Saving images...');
for k = 1:num_images
A = imread(TifImage, k);
Images(:,:,k) = A;
waitbar(k/num_images);
end
close(mywaitbar_handle)

 Accepted Answer

DGM
DGM on 18 Feb 2022
Edited: DGM on 18 Feb 2022
Depending on the image sizes, the waitbar itself is probably wasting the majority of the time. Consider the following test. Attached is an 11 frame TIFF (i added the padding .txt extension so that it could be uploaded. just omit it)
% original method
a = timeit(@() testA())
% using simplified mcode
b = timeit(@() testB())
% time ratio
a/b
function testA()
fname = 'multipage.tiff';
%Get the information in the multitiff image
info = imfinfo(fname);
%Get the number of images in the multitiff image
num_images = numel(info);
%Determine height and width
width = info.Width;
height = info.Height;
% guess output class
if all([info.BitDepth] == 8)
cl = 'uint8';
elseif all([info.BitDepth] == 8)
cl = 'uint16';
end
Af = zeros(height,width);
A = cast(zeros(size(Af,1),size(Af,2),num_images),cl); % right order
mywaitbar_handle = waitbar(0, 'Saving images...');
for k = 1:num_images
A(:,:,k) = imread(fname, k);
waitbar(k/num_images);
end
close(mywaitbar_handle)
end
function testB()
fname = 'multipage.tiff';
%Get the information in the multitiff image
info = imfinfo(fname);
%Get the number of images in the multitiff image
num_images = numel(info);
%Determine height and width
width = info.Width;
height = info.Height;
% guess output class
if all([info.BitDepth] == 8)
cl = 'uint8';
elseif all([info.BitDepth] == 8)
cl = 'uint16';
end
A = zeros(height,width,num_images,cl); % just create the output the right size
for k = 1:num_images
A(:,:,k) = imread(fname, k);
end
end
Of course, I still can't run it here, since the waitbar won't work.
The times I get for a 256x256x11 image are:
a =
0.2518
b =
0.0104
timeratio =
24.1287
So the waitbar (and the extraneous allocation) make the first method take roughly 24-25 times as long.
So if you want to use a waitbar, use it for things that will take a long time between updates. If you want to guess the input class for the array allocation, the above example is only suggestive. It obviously only accounts for two cases and makes no distinction between (e.g.) uint16 and int16.

3 Comments

Thanks DGM for the answer. I really appreciate your help. But I was looking for a way to vectorize the for loop.
If the TIFF file is structured as the example file is, then I don't think there is a way to do that in a single call to imread(). Similarly, there are other file formats which cannot be read/written completely in a single pass with imread/imwrite. If there is a way to do it with TIFF objects, I'm not familiar enough to be certain.
Thanks for the reply. I just wanted to be sure that I can speed up the code. This helps.

Sign in to comment.

More Answers (0)

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Products

Release

R2020a

Community Treasure Hunt

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

Start Hunting!