-
git-svn-id: https://svn.code.sf.net/p/dct/code/trunk@945 4c865b51-4357-4376-afb4-474e03ccb993
git-svn-id: https://svn.code.sf.net/p/dct/code/trunk@945 4c865b51-4357-4376-afb4-474e03ccb993
gtTIFVolWriter.m 9.43 KiB
function gtTIFVolWriter(vol, filename, varargin)
% GTTIFVOLWRITER Writes volume data to TIFF file with compression modes.
% Either single file of multiple files stack can be produced.
%
% gtTIFVolWriter(vol, filename, varargin)
% -------------------------------------------------------------------------
%
% INPUT:
% vol = <3Dimage> Input 3D volume
% filename = <string> Path to TIFF file to write
% The path may be relative or absolute.
% If extension is missing, it will be append.
% In the case of stack output, this will be the
% stack filename prefix to which the slice
% number and the extension will be append.
%
% OPTIONAL INPUT (varargin as a list of pairs, see parse_pv_pairs.m):
% 'xrange' = <range> Index range of output in X direction
% 'yrange' = <range> " Y "
% 'zrange' = <range> " Z "
%
% 'type' = <string> Force type of data written in the TIFF file
% it can be 'uint8', 'uint16' or 'logical'
% default is 'uint8'
%
% 'compress' = <string> Compression mode, by default 'none', can be
% 'packbits', 'lzm', 'deflate', 'ccitt', 'fax3'
% or 'fax4'
%
% 'mode' = <string> Output type which is 'single' or 'stack'
% default is a single TIFF file
% 'digits' = <int> Number of digits in stack filenames
% 'startindex' = <int> Starting index for stack filenames
% 'filext' = <string> Output TIFF file extension ('tif' or 'tiff')
% default is 'tif'
% 'newMethod' = <bool> Use new TIFF writing method (faster)
%
% TODO :
% - RGB data output
%
% Version 003 30-10-2012 by YGuilhem, yoann.guilhem@esrf.fr
% Use tifflib for fast reading
% Add compression option
% Some bugfixes
%
% Version 002 19-07-2012 by YGuilhem, yoann.guilhem@esrf.fr
% Add the options to output the volume as a stack of multiple TIFF files.
%
% Version 001 15-02-2012 by YGuilhem, yoann.guilhem@esrf.fr
% Set default parameters and parse optional arguments
params.newMethod = true;
params.type = '';
params.xrange = 'all';
params.yrange = 'all';
params.zrange = 'all';
params.compress = 'none';
params.mode = 'single';
params.filext = 'tif';
params.digits = 4;
params.startindex = 1;
params = parse_pv_pairs(params, varargin);
% Check if tifflib is present, if not -> old reading method
if params.newMethod && ~exist('tifflib', 'file')
disp('Cannot use new TIFF writing method because ''tifflib'' not found!');
params.newMethod = false;
end
% Translating range parameters
if strcmp(params.xrange, 'all')
rangeX = 1:size(vol, 1);
else
rangeX = params.xrange;
end
if strcmp(params.yrange, 'all')
rangeY = 1:size(vol, 2);
else
rangeY = params.yrange;
end
if strcmp(params.zrange, 'all')
rangeZ = 1:size(vol, 3);
else
rangeZ = params.zrange;
end
outVolSizeX = length(rangeX);
outVolSizeY = length(rangeY);
% Checking input/output types and decide whether casting/rescaling operations
doCast = false;
rescale = 0;
inputType = class(vol);
if ~isempty(params.type) && ~any(strcmp(params.type, {'logical', 'uint8', 'uint16'}))
gtError('gtTIFVolWriter:wrong_output_type', ...
['Output type ''' params.type ''' is not supported!']);
elseif any(strcmp(inputType, {'logical', 'uint8', 'uint16'}))
if isempty(params.type)
params.type = class(vol);
elseif strcmp(params.type, inputType)
doCast = false;
elseif strcmp(params.type, 'uint8')
doCast = true;
rescale = 255;
else
doCast = true;
end
else
doCast = true;
switch params.type
case 'logical'
rescale = 0;
case 'uint8'
rescale = 255;
otherwise
rescale = 65535;
end
end
% Cast and rescale if needed
if doCast
if rescale
disp(['Rescaling input volume to [0 ' num2str(rescale) ...
'] and casting it to ' params.type ' ...']);
outVol = cast(mat2gray(vol) * rescale, params.type);
else
disp(['Casting input volume to ' params.type ' ...']);
outVol = cast(vol, params.type);
end
else
outVol = vol;
end
% Get Bit per sample
switch class(outVol)
case 'uint16'
tifTag.BitsPerSample = 16;
tifTag.SampleFormat = Tiff.SampleFormat.UInt;
tifTag.SamplesPerPixel = 1;
case 'uint8'
tifTag.BitsPerSample = 8;
tifTag.SampleFormat = Tiff.SampleFormat.UInt;
tifTag.SamplesPerPixel = 1;
case 'logical'
tifTag.BitsPerSample = 1;
tifTag.SampleFormat = Tiff.SampleFormat.UInt;
tifTag.SamplesPerPixel = 1;
end
% Check compression mode
if isempty(params.compress) || (islogical(params.compress) && ~params.compress)
params.compress = 'none';
elseif (islogical(params.compress) && params.compress)
if islogical(outVol)
params.compress = 'fax4';
else
params.compress = 'lzw';
end
elseif any(strcmp(params.compress, {'ccitt', 'fax3', 'fax4'}))
if ~islogical(outVol)
gtError('gtTIFVolWriter:wrong_compression_mode', ...
['Compression mode ''' params.compress ...
''' is only available for logical volumes!']);
end
elseif ~any(strcmp(params.compress, {'none', 'packbits', 'deflate', 'lzw', ...
'ccitt', 'fax3', 'fax4'}))
warning('gtTIFVolWriter:unknown_compression_mode', ...
['Unknown compression mode: ' params.compress ...
' -> Setting it to ''none''...']);
params.compress = 'none';
end
switch params.compress
case 'none' , tifTag.Compression = Tiff.Compression.None;
case 'lzw' , tifTag.Compression = Tiff.Compression.LZW;
case 'packbits', tifTag.Compression = Tiff.Compression.PackBits;
case 'deflate' , tifTag.Compression = Tiff.Compression.Deflate; % Slow but efficient
case 'ccitt' , tifTag.Compression = Tiff.Compression.CCITTRLE;
case 'fax3' , tifTag.Compression = Tiff.Compression.CCITTFax3;
case 'fax4' , tifTag.Compression = Tiff.Compression.CCITTFax4;
otherwise , tifTag.Compression = Tiff.Compression.None;
end
% Set TIFF file tags
tifTag.Photometric = Tiff.Photometric.MinIsBlack;
tifTag.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
tifTag.ImageWidth = outVolSizeX;
tifTag.ImageLength = outVolSizeY;
tifTag.Software = 'matlabDCT';
% Guessing output directory, filename and extension
[fpath, fname, fext] = fileparts(filename);
% Trick to handle ~ path in unix
if fpath(1)=='~' && isunix()
fpath(1) = '';
fpath = fullfile(getenv('HOME'), fpath);
end
if strcmpi(params.mode, 'single')
% Setting output filename
if isempty(fext)
filename = fullfile(fpath, [fname '.' params.filext]);
else
filename = fullfile(fpath, [fname fext]);
end
% Check existence of output file to delete it before writing
if exist(filename, 'file')
delete(filename);
end
% Writing volume in TIFF file
if params.newMethod
tif = Tiff(filename, 'a');
for iz=1:length(rangeZ)
tif.setTag(tifTag);
tif.write(outVol(rangeX, rangeY, rangeZ(iz))');
tif.writeDirectory();
end
tif.close();
else
% Old method
for iz=1:length(rangeZ)
imwrite(outVol(rangeX(1):rangeX(end), rangeY(1):rangeY(end), ...
rangeZ(iz))', ...
filename, 'tif', 'Compression', params.compress, ...
'writemode', 'append');
end
end
elseif strcmpi(params.mode, 'stack')
% Check stack starting index
if isnumeric(params.startindex)
if mod(params.startindex, 1) ~= 0
params.startindex = round(params.startindex);
disp(['Argument ''startindex'' convert to ' ...
num2str(params.startindex)]);
end
else
gtError('gtTIFVolWriter:wrong_argument_type', ...
'The argument ''startindex'' should be an integer!');
end
% Check stack number of digits
if isnumeric(params.digits)
if mod(params.digits, 1) ~= 0
params.digits = round(params.digits);
disp(['Argument ''digits'' convert to ' num2str(params.digits)]);
end
else
gtError('gtTIFVolWriter:wrong_argument_type', ...
'The argument ''digits'' should be an integer!');
end
% Create directory
if ~isempty(fpath) && ~exist(fpath, 'dir')
mkdir(fpath);
end
% Output file output format
fprefix = fullfile(fpath, fname);
filenameFMT = sprintf('%s%%0%dd.%s', fprefix, params.digits, params.filext);
% Set output index offset
offset = params.startindex - 1;
% Writing volume in TIFF stack files
if params.newMethod
for iz=1:length(rangeZ)
outFile = sprintf(filenameFMT, iz+offset);
tif = Tiff(outFile, 'w');
tif.setTag(tifTag);
tif.write(outVol(rangeX, rangeY, rangeZ(iz))');
tif.close();
end
else
% Old method
for iz=1:length(rangeZ)
outFile = sprintf(filenameFMT, iz+offset);
imwrite(outVol(rangeX, rangeY, rangeZ(iz))', outFile, 'tif', ...
'Compression', params.compress, 'writemode', 'overwrite');
end
end
end
end % end of function