function [ dataset, metadata, success, errMessage ] = loadGeneric( fileName, seriesNumber, metadataOnly ) % loadGeneric tries to recognize and load any supported file format % % You should call this function within a try ... catch block. % % SYNOPSIS dataset = loadGeneric( filename ) % % INPUT filename: String containing the full name with path % seriesNumber: (optional), default: []. In case of files with % more than one series, specify which one to read. % The first series has number = 1! % If seriesNumber is [], a dialog will pop up with % the choice of the series to pick. % metadataOnly: {0|1}, default: 0. If 1, only the metadata is % returned % % OUTPUT dataset : cell array dataset{ timepoints, channels } with % all stacks % metadata: structure containing selected metadata extracted % from the OME XML metadata % success : 1 if success, 0 otherwise. % errMessage: in case the bio-formats library fails reading % file, excMessage contains the text of the thrown % exception. % % Aaron Ponti, 2009/10/15 % 2013/01/24: Changes to be compatible with loci_tools 4.4.4 % Extended metadata reading %-------------------------------------------------------------------------- % % The contents of this file are subject to the Mozilla Public License % Version 1.1 (the "License"); you may not use this file except in % compliance with the License. You may obtain a copy of the License at % http://www.mozilla.org/MPL/ % % Software distributed under the License is distributed on an "AS IS" % basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the % License for the specific language governing rights and limitations % under the License. % % The Original Code is "Qu for MATLAB". % % The Initial Developer of the Original Code is Aaron Ponti. % All Rights Reserved. % %-------------------------------------------------------------------------- import loci.formats.*; import loci.formats.FormatTools; import loci.formats.MetadataTools.*; import ij.ImagePlus; % Initialize success to 0 success = 0; % Check inputs switch nargin case 1, seriesNumber = []; metadataOnly = 0; case 2, metadataOnly = 0; case 3, % All set otherwise error( '1, 2 or 3 input parameters expected.' ); end % Initialize output parameter dataset and metadata dataset = { }; metadata = [ ]; errMessage = ''; % Create the reader reader = loci.formats.ChannelSeparator( loci.formats.ChannelFiller( ) ); % Control the handling of files with similar names % reader = loci.formats.FileStitcher( reader ); % reader.setGroupFiles( false() ); % Add metadata container reader.setMetadataStore( loci.formats.MetadataTools.createOMEXMLMetadata( ) ); % Set the file name try reader.setId( fileName ); catch e errMessage = e.message; return; end % Which series to read? nSeries = reader.getSeriesCount( ); if nSeries == 1 seriesNumber = 1; else if isempty(seriesNumber) choices = cell(1, nSeries); for i = 1 : nSeries choices{i} = ['Series ',num2str(i)]; end [s, v] = listdlg('PromptString', 'Select the series to open:',... 'SelectionMode', 'single', 'ListString', choices); if v == 0 return; end seriesNumber = s; else if seriesNumber < 1 || seriesNumber > nSeries if nSeries == 1 errMessage = 'The file contains only one series!'; return; else errMessage = ['Please specify a series number between ', ... '1 and ', num2str(nSeries), '!']; return; end end end end % Make the seriesNumber index 0-based seriesNumber = seriesNumber - 1; % Set the reader onto the selected series reader.setSeries( seriesNumber ); % Get sizes X = reader.getSizeX( ); Y = reader.getSizeY( ); Z = 25; %reader.getSizeZ( ); C = reader.getSizeC( ); T = reader.getSizeT( ); N = reader.getImageCount( ); % Get the pixel type pixelType = reader.getPixelType( ); % Is the datatype signed? isSigned = loci.formats.FormatTools.isSigned( pixelType ); % Endianity isLittleEndian = reader.isLittleEndian( ); % Bytes per pixel BytesPerPixel = loci.formats.FormatTools.getBytesPerPixel( pixelType ); switch BytesPerPixel case 1, datatype = 'uint8'; case 2, datatype = 'uint16'; case 4, % This is 32-bit floating point datatype = 'single'; otherwise, errMessage = 'Unsupported data type.'; return end % ========================================================================= % % Get metadata % % ========================================================================= voxelX = reader.getMetadataStore.getPixelsPhysicalSizeX( 0 ); if isempty( voxelX ) voxelX = 0; else voxelX = voxelX.getValue(); end voxelY = reader.getMetadataStore.getPixelsPhysicalSizeY( 0 ); if isempty( voxelY ) voxelY = 0; else voxelY = voxelY.getValue(); end voxelZ = reader.getMetadataStore.getPixelsPhysicalSizeZ( 0 ); if isempty( voxelZ ) voxelZ = 0; else voxelZ = voxelZ.getValue(); end voxels = [ voxelX voxelY voxelZ ]; if all( voxels( voxels ~= 0 ) < 1 ) voxels = 1000 .* voxels; end metadata = struct( ... 'width', reader.getSizeX( ), ... 'height', reader.getSizeY( ), ... 'nPlanes', reader.getSizeZ( ), ... 'nChannels', reader.getSizeC( ), ... 'nTimepoints', reader.getSizeT( ), ... 'seriesNumber', seriesNumber + 1, ... % MATLAB 1-based array 'nImagesInSeries', reader.getImageCount( ), ... 'voxelX', voxels( 1 ), ... 'voxelY', voxels( 2 ), ... 'voxelZ', voxels( 3 ), ... 'datatype', datatype, ... 'stagePosition', [ ], ... 'acquisitionDate', ... reader.getMetadataStore( ).getImageAcquisitionDate( 0 ).getValue( ), ... 'timeInterval', ... double(reader.getMetadataStore( ).getPixelsTimeIncrement( 0 )), ... 'timestamps', getTimeStamps(), ... 'color', [ ] ); metadata.datatype = datatype; if metadataOnly == 1 %Close the reader and return here reader.close(); return end % ========================================================================= % % Get pixel data % % ========================================================================= % Initialize the dataset dataset = cell( T, C ); % Allocate space for the individual stacks stack = zeros( [ Y X Z ], datatype ); for t = 1 : T for c = 1 : C dataset{ t, c } = stack; end end % Global image counter n = 0; % Open a waitbar if N > 1 hWaitbar = waitbar( 0, 'Loading ...' ); end % Go over all images and arrange them by plane, channel and time index switch char( reader.getDimensionOrder( ) ) case 'XYZCT', for t = 1 : T for c = 1 : C for z = 1 : Z % Load the pixel data arr = loci.common.DataTools.makeDataArray( ... reader.openBytes( n ), ... BytesPerPixel, isSigned, isLittleEndian); % Java does not have explicitly unsigned datatypes if ~isSigned switch class(arr) case 'int8' arr = typecast(arr, 'uint8'); case 'int16' arr = typecast(arr, 'uint16'); case 'single', % Do nothing otherwise, errMessage = 'Unsupported datatype.'; dataset = { }; metadata = [ ]; return; end end % Reshape into 2D arr = reshape( arr, [ X Y ] )'; % Store the plane dataset{ t, c }( :, :, z ) = arr; % Update the global image counter n = n + 1; if N > 1 % Update waitbar waitbar( n / N, hWaitbar ); end end end end case 'XYCZT', for t = 1 : T for z = 1 : Z for c = 1 : C % Load the pixel data arr = loci.common.DataTools.makeDataArray( ... reader.openBytes( n ), ... BytesPerPixel, isSigned, isLittleEndian); % Java does not have explicitly unsigned datatypes if ~isSigned switch class(arr) case 'int8' arr = typecast(arr, 'uint8'); case 'int16' arr = typecast(arr, 'uint16'); otherwise, errMessage = 'Unsupported datatype.'; dataset = { }; metadata = [ ]; return; end end % Reshape into 2D arr = reshape( arr, [ X Y ] )'; % Store the plane dataset{ t, c }( :, :, z ) = arr; % Update the global image counter n = n + 1; if N > 1 % Update waitbar waitbar( n / N, hWaitbar ); end end end end case 'XYZTC', for c = 1 : C for t = 1 : T for z = 1 : Z % Load the pixel data arr = loci.common.DataTools.makeDataArray( ... reader.openBytes( n ), ... BytesPerPixel, isSigned, isLittleEndian); % Java does not have explicitly unsigned datatypes if ~isSigned switch class(arr) case 'int8' arr = typecast(arr, 'uint8'); case 'int16' arr = typecast(arr, 'uint16'); otherwise, errMessage = 'Unsupported datatype,'; dataset = { }; metadata = [ ]; return; end end % Reshape into 2D arr = reshape( arr, [ X Y ] )'; % Store the plane dataset{ t, c }( :, :, z ) = arr; % Update the global image counter n = n + 1; if N > 1 % Update waitbar waitbar( n / N, hWaitbar ); end end end end otherwise, errMessage = [ 'Dimension order (', ... char( reader.getDimensionOrder( ) ), ') not supported.' ]; dataset = { }; metadata = [ ]; return end if N > 1 % Close waitbar close( hWaitbar ); end % ========================================================================= % % Convert if necessary % % ========================================================================= if isa( dataset{ 1, 1 }, 'single' ) mx = -Inf; for i = 1 : T for j = C nmx = max( dataset{ T, C }( : ) ); if nmx > mx mx = nmx; end end end newDatatype = 'uint16'; msg = [ 'The dataset is in 32-bit floating format, which is not ', ... 'supported by Qu. '; ]; if nmx > 2 ^ 16 msg = [ msg, 'Since the maximum intensity is above 2^16, the ', ... 'highest intensities will saturate. ' ]; else if nmx < 255 newDatatype = 'uint8'; msg = [ msg, 'Since the maximum intensity falls into the 8 ', ... 'bit range, the dataset can be safely converted to 8 bit ', ... '(with just a minor loss of precision due to rounding). ' ]; else msg = [ msg, 'Since the maximum intensity falls into the 16 ', ... 'bit range, the dataset can be safely converted to 16 bit ', ... '(with just a minor loss of precision due to rounding). ' ]; end end msg = [ msg, 'Do you want to proceed?' ]; choice = questdlg( msg, 'Qu :: Question', 'Yes', 'No', 'Yes' ); switch choice, case 'Yes', for i = 1 : T for j = 1 : C dataset{ i, j } = cast( dataset{ i, j }, newDatatype ); end end otherwise, dataset = { }; metadata = [ ]; return; end % switch end % Close the reader reader.close(); % Set success to 1 success = 1; % Functions % Extract the time stamps for all timepoints function timestamps = getTimeStamps() % Get the series metadata (Java) hash table and its keys table = reader.getSeriesMetadata(); % Number of time stamps to retrieve nTimepoints = reader.getSizeT(); % Allocate space to store the time stamps timestamps = zeros(1, nTimepoints); % Iterate over the keys and get the values for tp = 1 : nTimepoints try timestamps(tp) = table.get(['timestamp ', num2str(tp - 1)]); catch e timestamps(tp) = NaN; end end end end