Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
b2faf8451a
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
272 lines (223 sloc) 9.68 KB
classdef TiffReader < imageIO.ImageIO
%TIFFREADER Wrapper for Tiff interface, based on Matlab TIFF class
% This class is just a simple wrapper around Matlab Tiff class, adapted
% to conform to the structure of the imageIO library. Unlike
% TiffWriter, this class does not interface directly with the Tiff
% library, since no speed-ups are expected compared to the Matlab
% version.
% Author: Stefano.Masneri@brain.mpg.de
% Date: 29.07.2016
% SEE ALSO: imageIO.TiffWriter, Tiff
properties
tiffPtr; % pointer to a Matlab Tiff class
filePtr; % pointer to a file. Used in some special cases
% Other properties. Assuming that for multistack images they remain
% constant over the stack
XResolution; % resolution on horizontal axis
YResolution; % resolution on vertical haxis
resolutionUnit; % unit of measurement for resolution (none, inch, centimeter)
bps; % bits per sample used
colormap; % colormap used. Empty array if none
compression; % compression scheme used
tagNames; % Cell of available tags. Useful if the user wants to access
% additonal metadata
isImageJFmt = false; % true if the Tiff is non-standard and was created via imageJ
isSutterMOM1 = false; % true if the Tiff is non-standard and from SutterMOM v1
isSutterMOM2 = false; % true if the Tiff is non-standard and from SutterMOM v2
endianness='l'; % specify if data is stored as little-endian or big-endian
% used only if 'isImageJFmt' is true. Can be either 'l'
% or 'b'
offsetToImg; % offset to first image in the stack. Used only if isImageJFmt is true
stripByteCounts; % number of bytes to reads per strip. Used only if isImageJFmt is true
end
methods
function obj = TiffReader(filename)
%TIFFREADER Constructor of the class
%The constructor calls the constructor of the superclass, and then
%tries to parse the Tiff tags to extract as much information as
%possible from the file. No actual data is read in the constructor
%SEE ALSO imageIO.ImageIO.ImageIO
% Must call explicitly because we pass one argument
obj = obj@imageIO.ImageIO(filename);
% Use Matlab interface
obj.tiffPtr = Tiff(obj.fileFullPath, 'r');
% Set as many properties from the superclass as possible
obj = obj.readMetadata();
if obj.isImageJFmt % handle file differently
obj.filePtr = fopen(obj.fileFullPath);
endianness = fread(obj.filePtr, 2, '*char')';
if strcmpi(endianness, 'MM')
obj.endianness = 'b';
else %'II'
obj.endianness = 'l';
end
%fseek(obj.filePtr, obj.offsetToImg, 'bof');
end
end
function data = read(obj, varargin)
%READ read all the image data
%This function reads all the planes of the image. If the file has
%only one plane just returns that.
% INPUT
% obj: the TiffReader instance
% NAME-VALUE ARGUMENTS
% 'Cols': Specify which columns to extract
% 'Rows': Specify which rows to extract
% 'C': Specify which channels to extract
% 'Z': Specify which planes to extract
% 'T': Specify which timeseries to extract
% OUTPUT
% data: the whole image content
p = inputParser();
p.KeepUnmatched = true;
p.addParameter('Cols', 1:obj.width, @(x) isvector(x) && all(x > 0) && max(x) <= obj.pixPerTileCol);
p.addParameter('Rows', 1:obj.height, @(x) isvector(x) && all(x > 0) && max(x) <= obj.pixPerTileRow);
p.addParameter('C', 1:obj.channels, @(x) isvector(x) && all(x > 0) && max(x) <= obj.channels);
p.addParameter('Z', 1:obj.stacks, @(x) isvector(x) && all(x > 0) && max(x) <= obj.stacks);
p.addParameter('T', 1:obj.time, @(x) isvector(x) && all(x > 0) && max(x) <= obj.time);
p.parse(varargin{:});
rows = p.Results.Rows;
cols = p.Results.Cols;
channels = p.Results.C;
stacks = p.Results.Z;
timeseries = p.Results.T;
if obj.isImageJFmt
data = readTifImageJ(obj, cols, rows, channels, stacks);
elseif obj.isSutterMOM1 || obj.isSutterMOM2
data = readSutter(obj, cols, rows, channels, stacks, timeseries );
else % normal tif
data = zeros(length(rows), length(cols), length(channels), ...
length(stacks), obj.datatype);
idx = 1;
progBar = TextProgressBar('TiffReader --> Extracting data: ', 30);
for k = stacks
progBar.update(idx/(length(stacks)) * 100);
img = obj.readImage(k);
data(:, :, :, idx) = img(rows, cols, channels);
idx = idx + 1;
end
end
data = squeeze(data);
end
function img = readImage( obj, n )
%READIMAGE read one image plane
%This function reads one single plane of the image. If the file has
%only one plane just returns that.
% INPUT
% n the directory (aka the plane) to read. If bigger than the number
% of stacks, issue a warning and return an empty array. If not
% specified, return the image in the current directory
% OUTPUT
% img the image just read
if obj.isImageJFmt
imageSize = obj.height * obj.width * obj.channels;
precision = [ obj.datatype '=>' obj.datatype ];
if n > obj.stacks
warning('TiffReader.readImage: Cannot read image. n is bigger than the number of stacks')
img = [];
else
if nargin > 1 % n specified
fseek(obj.filePtr, obj.offsetToImg + (n-1)*imageSize*obj.bps/8, 'bof');
end
img = fread(obj.filePtr, imageSize, precision);
img = reshape(img, [obj.width, obj.height, obj.channels]);
img = img';
end
else
if 1 == nargin % n not specified
img = obj.tiffPtr.read();
elseif ~obj.isSutterMOM1 && ~obj.isSutterMOM2 && n > obj.stacks
warning('TiffReader.readImage: Cannot read image. n is bigger than the number of stacks')
img = [];
else % valid n
obj.tiffPtr.setDirectory(n);
img = obj.tiffPtr.read();
end
end
end
function delete(obj)
%DELETE Close object instances.
%Close performs the cleanup and release of the instantiated object
obj.tiffPtr.close();
if obj.filePtr > 0
fclose(obj.filePtr);
end
end
end
methods (Access = protected)
function obj = readMetadata(obj)
%First get usual info with imfinfo
try
imgInfo = imfinfo(obj.fileFullPath);
% Dimensions
obj.width = imgInfo(1).Width;
obj.height = imgInfo(1).Height;
obj.channels = imgInfo(1).SamplesPerPixel;
iconIndex = cat(1, imgInfo.NewSubFileType);
obj.stacks = sum(~iconIndex);
obj.time = 1;
obj.bps = imgInfo(1).BitsPerSample(1);
obj.resolutionUnit = imgInfo(1).ResolutionUnit;
obj.compression = imgInfo(1).Compression;
stripOffset = cat(1,imgInfo(iconIndex == 0).StripOffsets);
obj.offsetToImg = stripOffset(1);
% Standard TIFF does not have multitiled images
obj.tile = 1;
obj.numTilesRow = 1;
obj.numTilesCol = 1;
obj.rowTilePos = 0;
obj.colTilePos = 0;
obj.pixPerTileRow = obj.height;
obj.pixPerTileCol = obj.width;
obj.tileOverlap = 0;
% Other info available in imfinfo
obj.XResolution = imgInfo(1).XResolution;
obj.YResolution = imgInfo(1).YResolution;
obj.colormap = imgInfo(1).Colormap;
catch ME
error('TiffReader.TiffReader: Cannot read metadata. %s', ME.message)
end
% now use the Tiff pointer
obj.tagNames = obj.tiffPtr.getTagNames;
% retrieve datatype
sampleFormat = obj.tiffPtr.getTag('SampleFormat');
switch sampleFormat
case 1 % UInt
obj.datatype = ['uint' num2str(obj.bps)];
case 2 % Int
obj.datatype = ['int' num2str(obj.bps)];
case 3 % IEEEFP
if 64 == obj.bps
obj.datatype = 'double';
elseif 32 == obj.bps
obj.datatype = 'float';
else
warning('TiffReader.readMetadata: unrecognized BitsPerSample value')
end
otherwise % Void or complex types are unsupported
warning('TiffReader.readMetadata: unsupported sample format')
end
% check custom multitiff formats -_-'
try
imageDescription = obj.tiffPtr.getTag('ImageDescription');
% check between formats
if strncmpi('ImageJ', imageDescription, 6)
obj.isImageJFmt = true;
obj.parseMetadataImageJ(imageDescription);
elseif any(strfind('MOMconfig', imageDescription))
obj.isSutterMOM1 = true;
obj.pareMetadataSutter(imageDescription);
elseif any(strfind('scanimage.SI.', imageDescription))
obj.isSutterMOM2 = true;
obj.parseMetadataSutter(imageDescription);
end
catch
% could not retrieve ImageDescription tag
warning('TiffReader::readMetadata:: Tiff.Tag.ImageDescription is missing!');
end
end
%% decleare external methods
obj = parseMetadataImageJ(obj, imageDescription);
obj = parseMetadataSutter(obj, imageDescription);
end
end