How can I read an image file from disk asynchronously?

5 views (last 30 days)
I am working on a large number of 12MB image files. The time required to process each image file is split almost equally between Reading the input, Processing, and Writing the output. Reading and Writing speed is limited by disk, whereas Processing speed is limited by CPU/GPU. I am reading and writing to/from different disks.
When using imread and imwrite I have to wait for the function to complete before processing each image, so the disk or CPU/GPU is sitting idle ~2/3 of the time. Is there some way to call imread and imwrite asynchronously in order to accelerate the script?
Output from Example code:
>> readExample
Single worker:
Reading: 0.13
Processing: 1.10
Writing: 6.99
Total: 8.22
Three workers:
Reading: 0.17
Processing: 13.70
Writing: 0.60
Total: 8.23
Example Code:
% Make an example image
imwrite(uint16(rand(1080,1920,3)*65535),'example.tiff');
% Make an example convolution filter
X = gpuArray.colon(-300,300);
S = 100;
H = exp(-(X.*X)/(2*S*S));
H = H'*H;
H = H/sum(H(:));
% Go through the loop with a single worker
N=2;
Tread = zeros(N,1); Tprocess=zeros(N,1); Twrite=zeros(N,1);
Ttotal = tic;
for n=1:N
% Load the file
tic;
Im = single(imread('example.tiff'));
Im = gpuArray(Im);
Tread(n) = toc;
% Apply the convolution
tic;
Im(:,:,1) = conv2(Im(:,:,1), H, 'same');
Tprocess(n) = toc;
% Save the result
tic;
Im = gather(Im);
imwrite(uint16(Im),'output.tiff');
Twrite(n) = toc;
end
fprintf('Single worker:\n');
fprintf('Reading:\t\t%0.02f\n',sum(Tread));
fprintf('Processing:\t\t%0.02f\n',sum(Tprocess));
fprintf('Writing:\t\t%0.02f\n',sum(Twrite));
fprintf('Total:\t\t\t%0.02f\n',toc(Ttotal));
% Go through the loop again with three workers
if matlabpool('size') < 3
matlabpool('open',3);
end
Tread = zeros(N,1); Tprocess=zeros(N,1); Twrite=zeros(N,1);
Ttotal = tic;
parfor n=1:N
% Load the file
tic;
Im = single(imread('example.tiff'));
Im = gpuArray(Im);
Tread(n) = toc;
% Apply the convolution
tic;
Im(:,:,1) = conv2(Im(:,:,1), H, 'same');
Tprocess(n) = toc;
% Save the result
tic;
Im = gather(Im);
imwrite(uint16(Im),'output.tiff');
Twrite(n) = toc;
end
fprintf('\nThree workers:\n');
fprintf('Reading:\t\t%0.02f\n',sum(Tread));
fprintf('Processing:\t\t%0.02f\n',sum(Tprocess));
fprintf('Writing:\t\t%0.02f\n',sum(Twrite));
fprintf('Total:\t\t\t%0.02f\n',toc(Ttotal));
  2 Comments
Ashish Uthama
Ashish Uthama on 14 Oct 2013
Could you update the question with some sample code so we understand the pattern? If you are processing files in a loop, subsequent imread ought to happen while the GPU is processing, most (if not all) GPU calls are async.
Robin Atkins
Robin Atkins on 14 Oct 2013
Hi, I added some code as an example. It's obviously not efficient (H is seperable) but it works as an example. On my system it actually runs slower when using PCT, I think because of the higher memory use on the GPU.

Sign in to comment.

Accepted Answer

Robin Atkins
Robin Atkins on 8 Sep 2021
Edited: Robin Atkins on 8 Sep 2021
Using parfeval gives approximately 10% speed increase
p = gcp();
imgWriteFcn = @(img, name) imwrite( img, name, 'Compression' ,'none')
imgReadFcn = @(name) imread( name );
% Read the first image
img = imgReadFcn( filename(1) );
% Loop through the rest
for i = 2:numImg
% start reading the next frame while processing current frame
f = parfeval( p, imrReaFcn, 1, filename(i) );
% process some frame
img = imgaussfilt( img, 20 );
% write the result without blocking
parfeval( p, imgWriteFcn, 0, img, outputfilename(i) );
% wait if the next frame has been read
img = fetchOutputs( f );
end

More Answers (2)

Image Analyst
Image Analyst on 11 Oct 2013
Edited: Image Analyst on 11 Oct 2013
Perhaps get the Parallel Computing Toolbox?
  2 Comments
Robin Atkins
Robin Atkins on 11 Oct 2013
Hi, using a parfor loop with three workers helps a bit. Is this what you meant? This isn't an ideal solution for me because: a) Each worker reads random frames, so they are not in order, so it doesn't maximize disk read speed b) I'm using the GPU for the image processing, and it runs out of memory with each worker trying to use the same GPU.
I was really just hoping for a version of imread and imwrite that can fill/empty memory buffers as fast as they can, while updating some flag indicating which buffer is ready.
Image Analyst
Image Analyst on 11 Oct 2013
I think it probably already does things as fast as it can. I doubt they programmed in delays on purpose.
You can set the CPU priority higher. Right click MATLAB in the process list (Windows OS, control-shift-Escape) and do Set Priority->High. DO NOT USE REALTIME or you won't be able to do anything else.
Or try using a solid state drive to speed things up.

Sign in to comment.


Jan
Jan on 11 Oct 2013
Edited: Jan on 11 Oct 2013
A less compact idea than the Parallel Computing Toolbox is starting three Matlab session and let them communicate through http://www.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrix . But then the control of the inter-process communication is not trivial. But you would not transport the image data through the SharedMatrix, but control, which session processes which file.
Which kind of file type do the images have? Most of the formats are read using standard libraries, such that a C-Mex function could read and write the file asynchronously. You can easily start two threads for this job as long as they do not call any Matlab commands (mx... and mex... functions).
  2 Comments
Robin Atkins
Robin Atkins on 11 Oct 2013
I am mostly using TIFFs. Can you provide any more details on how a C mex function could be used to read/write asynchronously from within Matlab?
Robin Atkins
Robin Atkins on 8 Sep 2021
This pointed in the right direction, thanks.
One implementation of this below (courtesy of Jan Froelich)

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!