How to Pre-allocate a 4D photo array

26 views (last 30 days)
Carter on 16 Aug 2023
Edited: DGM on 16 Aug 2023
I am trying ot pre-allocate a photo array in matlab with a zeros. I am using the matlab command zeros to create a 1920x1080x3 by 1800 frames long zeros matrix. I am then using a for loop to populate this matrix with each of the photos in a for loop. I am trying to speed this process up using a preallocated zeros matrix but this is distorting my images alot. I am not sure if the original format of the zeros matrix is a double and the values in the photos are a uint8.
Im_length = 1080*Im_SCale;
Im_width = 1920*Im_SCale;
Im_size = zeros(Im_length, Im_width);
Frames = 1800;
Photos = repmat(Im_size, 1, 1, 3, Frames);
Photos_Smol = repmat(Im_size, 1, 1, 3, Frames);
for i = 1:length(filename)
Photos(:,:,:,i) = imread(strcat(readpath,'\',filename{i}));

Answers (2)

DGM on 16 Aug 2023
Edited: DGM on 16 Aug 2023
There are multiple problems here, but without the rest of the information, I'm going to have to assume some things.
As @Chunru points out, your distortion is because you're preallocating the array to the wrong class. Your incoming images are likely JPG, and so are almost certainly uint8 class. You should specify the array class when creating it. This does two things, It fixes the truncation problem, and it also avoids the unnecessary expansion step using repmat().
sz = [1000 1000 3 1000]; % ~3GB in uint8
% preallocate one page, expand
A = zeros(sz(1:2),'uint8');
A = repmat(A,[1 1 sz(3:4)]);
Elapsed time is 0.595446 seconds.
% just preallocate to the intended size
B = zeros(sz,'uint8');
Elapsed time is 0.001514 seconds.
On this server, the times are off by about a factor of 400. On my system, they're off by a factor of about 6000.
The next problem is that you appear to be creating two image stacks -- one for the incoming frames, and one for resized frames. That said, you're preallocating both arrays to the same size, which appears to be the output size. Either way, it seems like it should be causing problems unless Im_SCale is always 1. If the goal is to resize the frames, then preallocation shouldn't be necessary.
% imresize() will handle 4D stacks, so preallocation isn't needed
sz = [100 100 3 100];
A = im2uint8(rand(sz)); % a 4D image stack
B = imresize(A,0.5); % just resize the entire stack
That said, if you're trying to do something else where preallocation is needed for the output, then be aware that
%Im_length = 1080*Im_SCale;
%Im_width = 1920*Im_SCale;
are likely non-integer values for any non-integer value of Im_SCale. That would cause errors unless it's dealt with.
The last problem, and the one that should be pretty obvious, is that you're going to run into memory problems. Even if you don't, this sort of workflow tends to be expensive in terms of time spent on allocating large contiguous blocks of memory. Let's assume you only need one 1920x1080x3x1800 uint8 array. That's going to occupy ~11GB of memory. If allocated in double (or recast to double for processing purposes), the array would be 90GB. Assuming you'll need at least two copies of the array, this is going to be an obstacle.
Processing multiframe imagesets as monolithic 4D stacks can be convenient, but it doesn't scale well. At some point, it may make more sense to store the frames in a cell array so that the allocated memory does not need to be one giant contiguous block. As the volume of data increases further, it simply becomes impractical to deal with the entire imageset in memory either way. If your task can allow it, it would probably be faster to process the frames one at a time in a loop. There are also things like imageDatastore, but I am not at all familiar with using that.

Chunru on 16 Aug 2023
%Photos = zeros(1920, 1080, 3, 1800, 'uint8');
Photos = zeros(100, 50, 3, 10, 'uint8');
Name Size Bytes Class Attributes Photos 100x50x3x10 150000 uint8 cmdout 1x33 66 char




Community Treasure Hunt

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

Start Hunting!