function [tracks, metadata] = importTrackMateTracks(file, clipz, scalet) %%IMPORTTRACKMATETRACKS Import linear tracks from TrackMate % % This function reads a XML file that contains linear tracks generated by % TrackMate (http://fiji.sc/TrackMate). Careful: it does not open the XML % TrackMate session file, but the track file exported in TrackMate using % the action 'Export tracks to XML file'. This file format contains less % information than the whole session file, but is enough for linear tracks % (tracks that do not branch nor fuse). % % SYNTAX % % tracks = IMPORTTRACKMATETRACKS(file) opens the track file 'file' and % returns the tracks in the variable 'tracks'. 'tracks' is a cell array, % one cell per track. Each cell is made of 4xN double array, where N is the % number of spots in the track. The double array is organized as follow: % [ Ti, Xi, Yi, Zi ; ...] where T is the index of the frame the spot has been % detected in. T is always an integer. X, Y, Z are the spot spatial % coordinates in physical units. % % [tracks, metadata] = IMPORTTRACKMATETRACKS(file) also returns 'metadata', % a struct that contains the metadata that could be retrieved from the XML % file. It is made of the following fields: % - 'spaceUnits': a string containing the name of the physical spatial unit. % - 'timeUnits': a string containing the name of the physical temporal unit. % - 'frameInterval': a double whose value is the frame interval. % - 'date': a string representation of the date the XML file has been generated. % - 'source': a string representation of the TrackMate version this file % has been generated with. % % OUTPUT % % The function offers two flags to change how the output is returned. As % stated above, by default, it is returned as [ Ti, Xi, Yi, Zi ; ...] where % T is the frame as an integer. % % tracks = IMPORTTRACKMATETRACKS(file, clipZ) allows specifying whether to % remove the Z coordinate entirely or not. TrackMate always return 3D % coordinates, even for 2D motion. In the latter case, the Z coordinate is % always 0. If 'clipZ' is set to true AND if all the particles have their % Z coordinate to 0, then 'tracks' will be made of [ Ti, Xi, Yi ] arrays. % % tracks = IMPORTTRACKMATETRACKS(file, clipZ, scaleT) allows specifying % whether to scale the T coordinate by physical units. If scaleT is set to % true AND if the frame interval metadata value could be retrieved, then % the time will be returned in physical units, not in integer frame % number. % % % FILE FORMAT % % The XML file is expected to be formatted as follow: % % % % % % % ... etc... % % % ... % % ... % % % % Jean-Yves Tinevez - 2013 %% Input if nargin < 2 clipz = false; end if nargin < 3 scalet = false; end %% Load and Test compliance try doc = xmlread(file); catch %#ok error('Failed to read XML file %s.',file); end root = doc.getDocumentElement; if ~strcmp(root.getTagName, 'Tracks') error('MATLAB:importTrackMateTracks:BadXMLFile', ... 'File does not seem to be a proper track file.') end %% Get metadata metadata.spaceUnits = char( root.getAttribute('spaceUnits') ); metadata.timeUnits = char( root.getAttribute('timeUnits') ); metadata.frameInterval = str2double( root.getAttribute('frameInterval') ); metadata.date = char( root.getAttribute('generationDateTime') ); metadata.source = char( root.getAttribute('from') ); %% Parse nTracks = str2double( root.getAttribute('nTracks') ); tracks = cell(nTracks, 1); trackNodes = root.getElementsByTagName('particle'); for i = 1 : nTracks trackNode = trackNodes.item(i-1); nSpots = str2double( trackNode.getAttribute('nSpots') ); A = NaN( nSpots, 4); % T, X, Y, Z detectionNodes = trackNode.getElementsByTagName('detection'); for j = 1 : nSpots detectionNode = detectionNodes.item(j-1); t = str2double(detectionNode.getAttribute('t')); x = str2double(detectionNode.getAttribute('x')); y = str2double(detectionNode.getAttribute('y')); z = str2double(detectionNode.getAttribute('z')); A(j, :) = [ t x y z ]; end tracks{i} = A; end %% Clip Z dimension if possible and asked if clipz if all(cellfun(@(X) all( X(:,4) == 0), tracks)) % Remove the z coordinates since it is 0 everywhere for i = 1 : nTracks tracks{i} = tracks{i}(:, 1:3); end end end %% Scale time using physical units if required if scalet if ~isnan(metadata.frameInterval) && metadata.frameInterval > 0 % Scale time so that it is in physical units for i = 1 : nTracks tracks{i}(:, 1) = tracks{i}(:, 1) * metadata.frameInterval; end end end end