ParaMonte MATLAB 3.0.0
Parallel Monte Carlo and Machine Learning Library
See the latest version documentation.
im2gif.m
Go to the documentation of this file.
1%IM2GIF Convert a multiframe image to an animated GIF file
2%
3% Examples:
4% im2gif infile
5% im2gif infile outfile
6% im2gif(A, outfile)
7% im2gif(..., '-nocrop')
8% im2gif(..., '-nodither')
9% im2gif(..., '-ncolors', n)
10% im2gif(..., '-loops', n)
11% im2gif(..., '-delay', n)
12%
13% This function converts a multiframe image to an animated GIF.
14%
15% To create an animation from a series of figures, export to a multiframe
16% TIFF file using export_fig, then convert to a GIF, as follows:
17%
18% for a = 2 .^ (3:6)
19% peaks(a);
20% export_fig test.tif -nocrop -append
21% end
22% im2gif('test.tif', '-delay', 0.5);
23%
24%IN:
25% infile - string containing the name of the input image.
26% outfile - string containing the name of the output image (must have the
27% .gif extension). Default: infile, with .gif extension.
28% A - HxWxCxN array of input images, stacked along fourth dimension, to
29% be converted to gif.
30% -nocrop - option indicating that the borders of the output are not to
31% be cropped.
32% -nodither - option indicating that dithering is not to be used when
33% converting the image.
34% -ncolors - option pair, the value of which indicates the maximum number
35% of colors the GIF can have. This can also be a quantization
36% tolerance, between 0 and 1. Default/maximum: 256.
37% -loops - option pair, the value of which gives the number of times the
38% animation is to be looped. Default: 65535.
39% -delay - option pair, the value of which gives the time, in seconds,
40% between frames. Default: 1/15.
41
42% Copyright (C) Oliver Woodford 2011
43
44%{
45% 14/02/18: Merged issue #235: reduced memory usage, improved performance (thanks to @numb7rs)
46% 30/11/19: Merged issue #288: Fix im2gif.m for greyscale TIFF images (thanks @Blackbelt1221)
47%}
48
49function im2gif(A, varargin)
50
51 % Parse the input arguments
52 [A, options] = parse_args(A, varargin{:});
53
54 if options.crop ~= 0
55 % Crop
56 A = crop_borders(A, A(ceil(end/2),1,:,1));
57 end
58
59 % Convert to indexed image
60 [h, w, c, n] = size(A);
61
62 % Issue #235: Using unique(A,'rows') on the whole image stack at once causes
63 % massive memory usage when dealing with large images (at least on Matlab 2017b).
64 % Running unique(...) on individual frames, then again on the results drastically
65 % reduces the memory usage & slightly improves the execution time (@numb7rs).
66 uns = cell(1,size(A,4));
67 for nn=1:size(A,4)
68 uns{nn}=unique(reshape(A(:,:,:,nn), h*w, c),'rows');
69 end
70 map=unique(cell2mat(uns'),'rows');
71
72 A = reshape(permute(A, [1 2 4 3]), h, w*n, c);
73
74 if size(map, 1) > 256
75 dither_str = {'dither', 'nodither'};
76 dither_str = dither_str{1+(options.dither==0)};
77 if options.ncolors <= 1
78 [B, map] = rgb2ind(A, options.ncolors, dither_str);
79 if size(map, 1) > 256
80 [B, map] = rgb2ind(A, 256, dither_str);
81 end
82 else
83 [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str);
84 end
85 else
86 if max(map(:)) > 1
87 map = double(map) / 255;
88 A = double(A) / 255;
89 end
90 B = rgb2ind(im2double(A), map);
91 end
92 B = reshape(B, h, w, 1, n);
93
94 % Bug fix to rgb2ind
95 map(B(1)+1,:) = im2double(A(1,1,:));
96
97 % Save as a gif
98 imwrite(B, map, options.outfile, 'LoopCount', round(options.loops(1)), 'DelayTime', options.delay);
99end
100
101%% Parse the input arguments
102function [A, options] = parse_args(A, varargin)
103 % Set the defaults
104 options = struct('outfile', '', ...
105 'dither', true, ...
106 'crop', true, ...
107 'ncolors', 256, ...
108 'loops', 65535, ...
109 'delay', 1/15);
110
111 % Go through the arguments
112 a = 0;
113 n = numel(varargin);
114 while a < n
115 a = a + 1;
116 if ischar(varargin{a}) && ~isempty(varargin{a})
117 if varargin{a}(1) == '-'
118 opt = lower(varargin{a}(2:end));
119 switch opt
120 case 'nocrop'
121 options.crop = false;
122 case 'nodither'
123 options.dither = false;
124 otherwise
125 if ~isfield(options, opt)
126 error('Option %s not recognized', varargin{a});
127 end
128 a = a + 1;
129 if ischar(varargin{a}) && ~ischar(options.(opt))
130 options.(opt) = str2double(varargin{a});
131 else
132 options.(opt) = varargin{a};
133 end
134 end
135 else
136 options.outfile = varargin{a};
137 end
138 end
139 end
140
141 if isempty(options.outfile)
142 if ~ischar(A)
143 error('No output filename given.');
144 end
145 % Generate the output filename from the input filename
146 [path, outfile] = fileparts(A);
147 options.outfile = fullfile(path, [outfile '.gif']);
148 end
149
150 if ischar(A)
151 % Read in the image
152 A = imread_rgb(A);
153 end
154end
155
156%% Read image to uint8 rgb array
157function [A, alpha] = imread_rgb(name)
158 % Get file info
159 info = imfinfo(name);
160 % Special case formats
161 switch lower(info(1).Format)
162 case 'gif'
163 [A, map] = imread(name, 'frames', 'all');
164 if ~isempty(map)
165 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
166 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
167 A = permute(A, [1 2 5 4 3]);
168 end
169 case {'tif', 'tiff'}
170 A = cell(numel(info), 1);
171 for a = 1:numel(A)
172 [A{a}, map] = imread(name, 'Index', a, 'Info', info);
173 if ~isempty(map)
174 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
175 A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
176 end
177 if size(A{a}, 3) == 4
178 % TIFF in CMYK colourspace - convert to RGB
179 if isfloat(A{a})
180 A{a} = A{a} * 255;
181 else
182 A{a} = single(A{a});
183 end
184 A{a} = 255 - A{a};
185 A{a}(:,:,4) = A{a}(:,:,4) / 255;
186 A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
187 elseif size(A{a}, 3) < 3 %Check whether TIFF has been read in as greyscale
188 %Convert from greyscale to RGB colorspace (issue #288)
189 A{a} = cat(3, A{a}, A{a}, A{a});
190 end
191 end
192 A = cat(4, A{:});
193 otherwise
194 [A, map, alpha] = imread(name);
195 A = A(:,:,:,1); % Keep only first frame of multi-frame files
196 if ~isempty(map)
197 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
198 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
199 elseif size(A, 3) == 4
200 % Assume 4th channel is an alpha matte
201 alpha = A(:,:,4);
202 A = A(:,:,1:3);
203 end
204 end
205end
function name(in vendor)
Return the MPI library name as used in naming the ParaMonte MATLAB shared libraries.
function crop_borders(in A, in bcol, in padding, in crop_amounts)
function parse_args(in A, in varargin)
function imread_rgb(in name)
function im2gif(in A, in varargin)
function map()
Return a scalar MATLAB logical that is true if and only if the current installation of MATLAB contain...
function which(in vendor)
Return the a MATLAB string containing the path to the first mpiexec executable binary found in system...