Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MATLAB functions - let them import ROIs from TrackMate >= v7 #293

Merged
merged 7 commits into from
May 13, 2024
70 changes: 70 additions & 0 deletions scripts/ExampleScript_MATLABImportROIs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
%% Import spot ROIs from a TrackMate file.
%
% This example MATLAB script shows how to use the `trackmateSpot.m`
% function to open a TrackMate file that contains spots with ROIs (their
% shape as polygon). They are then painted in a common graph, colored by
% frame.
%
% The `trackmateSpot.m` does not return the track information, and we
% cannot retrieve the tracks solely with this function. See the other
% example `ExampleScript_MATLABImportROIs.m` in this folder for a more
% involved example that does this.
%
% Jean-Yves Tinevez - 2024

close all
clear
clc

% Where to store the files?
root_folder = '.';
% TrackMate file.
file_path = fullfile( root_folder, 'MAX_Merged.xml' );
if ~exist( file_path, 'file' )
% Download and uncompress the files.
url = 'https://samples.fiji.sc/tutorials/MATLABtuto.zip';
zip_file_path = fullfile( root_folder, 'MATLABtuto.zip' );
fprintf( 'Downloading tutorial files from %s\n', url )
websave( zip_file_path, url );
fprintf( 'Saved to %s\n', zip_file_path )
unzip( zip_file_path, root_folder )
end

% Read tracks.
[S, idmap, rois] = trackmateSpots( file_path );

n_frames = max(S.FRAME)+1;
colors = turbo(n_frames);

n_spots = height(S);

%% Plot the spot contours.

figure
hold on
axis square

for i = 1 : n_spots

% Spot center.
x = S.POSITION_X(i);
y = S.POSITION_Y(i);
% Spot contour (centered on 0).
roi = rois{i};
% Put the contours with respect to the spot center.
roi(:,1) = roi(:,1) + x;
roi(:,2) = roi(:,2) + y;

% Color by frame.
frame = S.FRAME(i)+1;
col = colors( frame, : );

patch( 'XData', roi(:,1), 'YData', roi(:,2), ...
'FaceColor', 'None', ...
'EdgeColor', col )
plot( x, y, 'Color', col, 'Marker', 'x' )

end
xlabel( 'X (um)' )
ylabel( 'Y (um)' )
set(gca, 'YDir', 'reverse' )
174 changes: 174 additions & 0 deletions scripts/ExampleScript_MATLABPlotTracksWithROIs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
%% Import the tracks of cells that divide from TrackMate and overlay them with their shape on a movie.
%
% This example MATLAB script opens a TrackMate file and an image file, and
% create a movie that shows the cells and their track over time. The cells
% are painted with their shape. The tracks have divisions, and are drawn
% over the movie.
%
% The movie that we use is one of C.elegans early embryo, following 2 cells
% divisions. It is a MIP of a 3D movie where the embryo is labeled with
% H2B-eGFP. The cells have been tracked and manually curated in TrackMate.
% There are 4 tracks: 2 for the AB and P cells, and 2 for the polar bodies.
%
% Jean-Yves Tinevez - 2024

close all
clear
clc

% Where to store the files?
root_folder = '.';
% Image file.
movie_path = fullfile( root_folder, 'MAX_Merged-1.tif' );
% TrackMate file.
file_path = fullfile( root_folder, 'MAX_Merged.xml' );

if ~exist( file_path, 'file' ) || ~exist( movie_path, 'file' )
% Download and uncompress the files.
url = 'https://samples.fiji.sc/tutorials/MATLABtuto.zip';
zip_file_path = fullfile( root_folder, 'MATLABtuto.zip' );
fprintf( 'Downloading tutorial files from %s\n', url )
websave( zip_file_path, url );
fprintf( 'Saved to %s\n', zip_file_path )
unzip( zip_file_path, root_folder )
end


%% Read the movie file.

% You can change the image used in this tutorial, but it must be a
% 1-channel, 2D over time, movie. I use the tiffreadVolume function, that
% can read ImageJ TIFFs with no issue.

fprintf( 'Reading image %s\n', movie_path )
I = tiffreadVolume( movie_path );
w = size(I, 1);
h = size(I, 2);
n_frames = size(I, 3);
fprintf( 'Image is %d x %d with %d frames.\n', w, h, n_frames )

% Auto adjust contrast
imin = prctile( I(:), 1 );
imax = prctile( I(:), 99 );

%% Read the TrackMate file.

% Read tracks as a directed graph in MATLAB.
fprintf( 'Reading TrackMate file %s\n', file_path )
[G, rois] = trackmateGraph( file_path );
% The 'rois' cell array contains the polygon of all cells, if they have
% one.

% Directed graph with opposite edge direction (we will need it to paint
% tracks from current time-point to the start).
Greversed = flipedge( G );

% The spot data is stored in the the nodes of the graph as a table.
S = G.Nodes;
n_spots = height(S);
fprintf( 'Found %d spots.\n', n_spots )

% Pixel size is stored in the TrackMate file.
cal = trackmateImageCalibration( file_path );
pixel_size = cal.x.value; % microns
fprintf( 'Pixel size is %.2f %s.\n', pixel_size, cal.x.units )


%% Rebuild the tracks.

% We don't have the individual track with this. We have to rebuild them
% from the connected component of the graph.
spot_track = conncomp( G, 'Type', 'weak' );
% This contains the index of the track for all spots.
n_tracks = max( spot_track );
fprintf( 'Found %d tracks.\n', n_tracks )

%% Display image and tracks, export to movie.

% To color the tracks.
col = jet( n_tracks );

% Structure used to store the frame of the MATLAB movie.
F( n_frames ) = struct('cdata',[],'colormap',[]);

% Make a file name for the video.
export_file = strrep( file_path, '.xml', '' );

% Display first frame to trigger proper axes limits. Zoom to 200%.
figure
If = I( :, :, 1 );
imshow( If, [ imin imax ], ...
'XData', [ 0 pixel_size * h ], ...
'YData', [ 0 pixel_size * w ], ...
'InitialMagnification', 200)
drawnow

% Prepare the writer for the MP4 file.
v = VideoWriter( export_file, 'MPEG-4' );
v.FrameRate = 10;
v.Quality = 100;
open(v);

for t = 1 : n_frames

% Clear axes.
cla

% Image data of current frame.
If = I( :, :, t );
imshow( If, [ imin imax ], ...
'XData', [ 0 pixel_size * h ], ...
'YData', [ 0 pixel_size * w ], ...
'InitialMagnification', 200)
hold on

% Spot data of current frame.
frame = t-1; % 0-indexed in Java.
log_index = S.FRAME == frame;
Sf = S(log_index, :);
index = find( log_index );

nsf = height( Sf );
for i = 1 : nsf

% What is the spot row in the main table?
spot_row = index( i );
track = spot_track( spot_row );
roi = rois{ spot_row };

% Track of the current spot, backward in time.
path = dfsearch( Greversed, spot_row );
track_x = S.POSITION_X( path );
track_y = S.POSITION_Y( path );

% Paint the track.
plot( track_x, track_y, ...
'Color', col(track, :), ...
'LineWidth', 2, ...
'Marker', '.')

% Spot polygon coordinates.
x = Sf.POSITION_X( i );
y = Sf.POSITION_Y( i );
roi(:,1) = roi(:,1) + x;
roi(:,2) = roi(:,2) + y;

% Paint current spot polygon, colored by track.
patch( 'XData', roi(:,1), 'YData', roi(:,2), ...
'FaceColor', 'None', ...
'EdgeColor', col( track, :), ...
'LineWidth', 4, ...
'Marker', 'none')

end
drawnow
frame = getframe(gca);
F(t) = frame;
writeVideo(v,frame);

end
close(v)

%% Replay the movie.

movie( F, 1, 5 )
20 changes: 17 additions & 3 deletions scripts/trackmateGraph.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function G = trackmateGraph(filePath, spotFeatureList, edgeFeatureList, verbose)
function [G, rois] = trackmateGraph(filePath, spotFeatureList, edgeFeatureList, verbose)
%%TRACKMATEGRAPH Import a TrackMate data file as a MATLAB directed graph.
%
% G = TRACKMATEGRAPH(file_path) imports the TrackMate data stored in the
Expand All @@ -13,6 +13,9 @@
% G = TRACKMATEGRAPH(file_path, sfl, efl, true) generates output in the
% command window that log the current import progress.
%
% [ G, rois ] = TRACKMATEGRAPH( ... ) also returns rois, a cell array
% containing the 2D polygons of each spot, if there is one.
%
% INPUT:
%
% file_path must be a path to a TrackMate file, containing the whole
Expand All @@ -38,6 +41,12 @@
% feature values. The G.Edges.EndNodes N x 2 matrix lists the source and
% target nodes row number in the G.Nodes table.
%
% The 'rois' output (2nd output) is a cell array. The ith element is a
% Nx2 array that contains the polygon vertices coordinates (X, Y) for the
% spot in the ith line of the Nodes table. These coordinates are
% respective to the (POSITION_X, POSITION_Y) spot center. If a spot does
% not have a ROI, the cell is empty.
%
% EXAMPLE:
%
% >> G = trackmateGraph(file_path, [], [], true);
Expand All @@ -49,7 +58,7 @@
% >> axis equal

% __
% Jean-Yves Tinevez - 2016
% Jean-Yves Tinevez - 2016 - 2024


%% Constants definition.
Expand All @@ -76,7 +85,12 @@
tic
end

[ spotTable, spotIDMap ] = trackmateSpots(filePath, spotFeatureList);
if nargout >= 2
[ spotTable, spotIDMap, rois ] = trackmateSpots(filePath, spotFeatureList);
else
[ spotTable, spotIDMap ] = trackmateSpots(filePath, spotFeatureList);
end


if verbose
fprintf('Done in %.1f s.\n', toc)
Expand Down
35 changes: 30 additions & 5 deletions scripts/trackmateSpots.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [ spotTable, spotIDMap ] = trackmateSpots(filePath, featureList)
function [ spotTable, spotIDMap, rois ] = trackmateSpots(filePath, featureList)
%%TRACKMATESPOTS Import spots from a TrackMate data file.
%
% S = TRACKMATESPOTS(file_path) imports the spots contained in the
Expand All @@ -13,6 +13,9 @@
% spot ID to row number in the table. idMap is such that idMap(10) the
% row at which the spot with ID 10 is listed.
%
% [ S, idMap, rois ] = TRACKMATESPOTS( ... ) also returns rois, a cell
% array containing the 2D polygons of each spot, if there is one.
%
% INPUT:
%
% file_path must be a path to a TrackMate file, containing the whole
Expand All @@ -29,9 +32,15 @@
%
% OUTPUT:
%
% The output is a MATLAB table with at least two columns, ID (the spot
% ID) and name (the spot name). Extra features listed in the specified
% feature_list input appear as supplemental column.
% The first output is a MATLAB table with at least two columns, ID (the
% spot ID) and name (the spot name). Extra features listed in the
% specified feature_list input appear as supplemental column.
%
% The 'rois' output (3rd output) is a cell array. The ith element is a
% Nx2 array that contains the polygon vertices coordinates (X, Y) for the
% spot in the ith line of the table S. These coordinates are respective
% to the (POSITION_X, POSITION_Y) spot center. If a spot does not have a
% ROI, the cell is empty.
%
% EXAMPLES:
%
Expand Down Expand Up @@ -71,7 +80,7 @@


% __
% Jean-Yves Tinevez - 2016
% Jean-Yves Tinevez - 2016 - 2024

%% Import the XPath classes.
import javax.xml.xpath.*
Expand All @@ -81,6 +90,7 @@
TRACKMATE_ELEMENT = 'TrackMate';
SPOT_ID_ATTRIBUTE = 'ID';
SPOT_NAME_ATTRIBUTE = 'name';
ROI_N_POINTS_ATTTRIBUTE = 'ROI_N_POINTS';

%% Open file.

Expand Down Expand Up @@ -123,6 +133,7 @@
ID = NaN( nSpots, 1 );
name = cell( nSpots, 1);
features = NaN( nSpots, n_features );
rois = cell( nSpots, 1);

% Read all spot nodes.
for i = 1 : nSpots
Expand All @@ -132,6 +143,17 @@
for j = 1 : n_features
features( i, j ) = str2double( node.getAttribute( featureList{ j } ) );
end

% Read ROI coords if it's there.
if nargout >= 3
coords_str = node.getTextContent();
if ~isempty( coords_str )
A = sscanf(string(coords_str),'%f');
n_points = numel(A) / 2;
A = reshape( A, 2, n_points )';
rois{i} = A;
end
end
end

% Create table.
Expand Down Expand Up @@ -159,6 +181,9 @@
elseif strcmp( SPOT_NAME_ATTRIBUTE, vn )
vDescriptions{ k } = 'Spot name';
vUnits{ k } = '';
elseif strcmp( ROI_N_POINTS_ATTTRIBUTE, vn )
vDescriptions{ k } = 'ROI N points';
vUnits{ k } = '';
else
vDescriptions{ k } = fs( vn ).name;
vUnits{ k } = fs( vn ).units;
Expand Down
Loading