Scripting TrackMate

Revision as of 08:15, 7 August 2013 by JeanYvesTinevez (talk | contribs) (A new example using the process() method)

The code listed here does not work: it belong to TrackMate version 1.x. A new version of this page is under construction. 07/2013



TrackMate scripting principle

TrackMate_ can be used out of the GUI, using a scripting language that allows making calls to Java. The most simple way to get started is to use the Script Editor of Fiji, which takes care of the difficult & boring part for you (such as path). The examples proposed on this page all use Jython, but can be adapted to anything.

Since we are calling the internals of TrackMate, we must get to know a bit of its guts. I have tried to come up with a rational design; though not always successfully. There is 3 main classes to interact with in a script:

  • Model (fiji.plugin.trackmate.TrackMateModel) is the class in charge of storing the data. It cannot do anything to create it. It can help you follow manual modifications you would made in the manual editing mode, interrogate it, ... but it is conceptually just a data recipient.
  • Settings (fiji.plugin.trackmate.Settings) is a part of the model. It is a class storing the fields that will configure TrackMate and pilot how the data is created. As you can see, it is mainly make of public fields.
  • TrackMate (fiji.plugin.trackmate.TrackMate_) is the actual Fiji plugin. When called from the Fiji menu, it launches the GUI. In scripts, we use it to actually perform the analysis tasks, such as generating spots from images, linking them into track, etc... It reads configuration information in the Settings object mentioned above and put the resulting data in the model.

So getting a working script is all about configuring a proper Settings object and calling exec* methods on a TrackMate_ object.


A full example

Here is an example of full tracking process, using the easy image found in the first tutorial. The following (Jython) script works as following:

  • It fetches the image from the web
  • It configures settings for segmentation and tracking
  • The model is instantiated, with the settings and imp objects
  • The TrackMate plugin is instantiated with the model object
  • Then the TrackMate object performs all the steps needed.
  • The final results is displayed as an overlay.


import fiji.plugin.trackmate.Settings as Settings
import fiji.plugin.trackmate.Model as Model
import fiji.plugin.trackmate.SelectionModel as SelectionModel
import fiji.plugin.trackmate.TrackMate as TrackMate
import fiji.plugin.trackmate.Logger as Logger
import fiji.plugin.trackmate.detection.DetectorKeys as DetectorKeys
import fiji.plugin.trackmate.detection.DogDetectorFactory as DogDetectorFactory
import fiji.plugin.trackmate.tracking.SimpleFastLAPTracker as SimpleFastLAPTracker
import fiji.plugin.trackmate.tracking.LAPUtils as LAPUtils
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer as HyperStackDisplayer
import fiji.plugin.trackmate.features.FeatureFilter as FeatureFilter

# Get currently selected image
imp = WindowManager.getCurrentImage()
#imp = IJ.openImage('http://fiji.sc/samples/FakeTracks.tif')
imp.show()
  
#------------------------
# Prepare settings object
#------------------------
  
settings = Settings()
settings.setFrom(imp)
  
# Configure detector
settings.detectorFactory = DogDetectorFactory()
settings.detectorSettings = { 
	DetectorKeys.KEY_DO_SUBPIXEL_LOCALIZATION : True,
	DetectorKeys.KEY_RADIUS : 2.5,
	DetectorKeys.KEY_TARGET_CHANNEL : 1,
	DetectorKeys.KEY_THRESHOLD : 0.,
	DetectorKeys.KEY_DO_MEDIAN_FILTERING : False,
}  

# Configure tracker
settings.tracker = SimpleFastLAPTracker()
settings.trackerSettings = LAPUtils.getDefaultLAPSettingsMap()

print(str(settings))
  
#-----------------------------
# Instantiate model and plugin
#-----------------------------
  
model = Model()
trackmate = TrackMate(model, settings)
  
#---------------------
# Execute segmentation
#---------------------
  
print('Segmenting with parameters:')
print(str(settings.detectorFactory))
print(str(settings.detectorSettings))
  
trackmate.execDetection()
  
print(str(model.getSpots()))
  
#--------------------------
# Execute initial filtering
#--------------------------
  
settings.initialSpotFilterValue = 3.6
  
print('Initial spot filtering with quality above ' + str(settings.initialSpotFilterValue))
  
trackmate.execInitialSpotFiltering()
  
print(str(model.getSpots()))
  
#--------------------------
# Execute spot filtering
#--------------------------
  
filter1 = FeatureFilter('QUALITY', 20, True)
  
print('Spot filtering with ' + str(filter1))
  
settings.addSpotFilter(filter1)
trackmate.execSpotFiltering(True)
  
print(str(model.getSpots()))
  
#-----------------
# Execute tracking
#-----------------
  
print('Tracking with parameters:')
print(str(settings.tracker))
print(str(settings.trackerSettings))
  
trackmate.execTracking()
  
print('Found ' + str(model.getTrackModel().nTracks(True)) + ' tracks.')
  
#----------------
# Display results
#----------------

selectionModel = SelectionModel(model)
displayer =  HyperStackDisplayer(model, selectionModel, imp)
displayer.render()
displayer.refresh()




Use the process method

Sometimes you may want to set all parameters at once, then fire TrackMate and simply get the results back. This is how it is done:

from fiji.plugin.trackmate import Model
from fiji.plugin.trackmate import Settings
from fiji.plugin.trackmate import TrackMate
from fiji.plugin.trackmate import SelectionModel
from fiji.plugin.trackmate import Logger
from fiji.plugin.trackmate.detection import LogDetectorFactory
from fiji.plugin.trackmate.tracking import FastLAPTracker
from fiji.plugin.trackmate.tracking import LAPUtils
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer as HyperStackDisplayer
import fiji.plugin.trackmate.features.FeatureFilter as FeatureFilter
import sys
import fiji.plugin.trackmate.features.track.TrackDurationAnalyzer as TrackDurationAnalyzer

# Get currently selected image
imp = WindowManager.getCurrentImage()
#imp = IJ.openImage('http://fiji.sc/samples/FakeTracks.tif')
imp.show()


#----------------------------
# Create the model object now
#----------------------------

# Some of the parameters we configure below need to have
# a reference to the model at creation. So we create an
# empty model now.

model = Model()

# Send all messages to ImageJ log window.
model.setLogger(Logger.IJ_LOGGER)


   
#------------------------
# Prepare settings object
#------------------------
   
settings = Settings()
settings.setFrom(imp)
   
# Configure detector - We use the Strings for the keys
settings.detectorFactory = LogDetectorFactory()
settings.detectorSettings = { 
    'DO_SUBPIXEL_LOCALIZATION' : True,
    'RADIUS' : 2.5,
    'TARGET_CHANNEL' : 1,
    'THRESHOLD' : 0.,
    'DO_MEDIAN_FILTERING' : False,
}  

# Configure spot filters - Classical filter on quality
filter1 = FeatureFilter('QUALITY', 40, True)
settings.addSpotFilter(filter1)
 
# Configure tracker - We want to allow merges and fusions
settings.tracker = FastLAPTracker()
settings.trackerSettings = LAPUtils.getDefaultLAPSettingsMap() # almost good enough
settings.trackerSettings['ALLOW_TRACK_SPLITTING'] = True
settings.trackerSettings['ALLOW_TRACK_MERGING'] = True

# Configure track analyzers - Later on we want to filter out tracks 
# based on their displacement, so we need to state that we want 
# track displacement to be calculated. By default, out of the GUI, 
# not features are calculated. 

# The displacement feature is provided by the TrackDurationAnalyzer.

settings.addTrackAnalyzer(TrackDurationAnalyzer(model))

# Configure track filters - We want to get rid of the two immobile spots at 
# the bottom right of the image. Track displacement must be above 10 pixels.

filter2 = FeatureFilter('TRACK_DISPLACEMENT', 10, True)
settings.addTrackFilter(filter2)


#-------------------
# Instantiate plugin
#-------------------

trackmate = TrackMate(model, settings)
   
#--------
# Process
#--------

ok = trackmate.checkInput()
if not ok:
	sys.exit(str(trackmate.getErrorMessage()))

ok = trackmate.process()
if not ok:
	sys.exit(str(trackmate.getErrorMessage()))

   
#----------------
# Display results
#----------------
 
selectionModel = SelectionModel(model)
displayer =  HyperStackDisplayer(model, selectionModel, imp)
displayer.render()
displayer.refresh()

# Echo results with the logger we set at start:
model.getLogger().log(str(model))




Exporting results to the ISBI 2012 Tracking Challenge file formats

This example is similar to the previous one, except that it does not display the results, but exports them to a specialized XML file, made for the ISBI 2012 tracking challenge. Also note that we use a specialized logger that sends log messages to the IJ log window.

import fiji.plugin.trackmate.Settings;
import fiji.plugin.trackmate.TrackMateModel;
import fiji.plugin.trackmate.TrackMate_;
import fiji.plugin.trackmate.Logger;
import fiji.plugin.trackmate.segmentation.DogSegmenter;
import fiji.plugin.trackmate.tracking.SimpleFastLAPTracker;
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer;
import ij.IJ;
import java.io.File;
import fiji.plugin.trackmate.action.ISBIChallengeExporter;
  
# Get currently selected image
# imp = WindowManager.getCurrentImage()
imp = ij.IJ.openImage('http://fiji.sc/tinevez/TrackMate/FakeTracks.tif')
# imp.show()
  
#------------------------
# Prepare settings object
#------------------------
  
settings = fiji.plugin.trackmate.Settings(imp)
  
# Configure segmenter
settings.segmenter = fiji.plugin.trackmate.segmentation.DogSegmenter()
settings.segmenterSettings = fiji.plugin.trackmate.segmentation.LogSegmenterSettings()
settings.segmenterSettings.expectedRadius = 2.5
  
# Configure tracker
settings.tracker = fiji.plugin.trackmate.tracking.SimpleFastLAPTracker()
settings.trackerSettings = fiji.plugin.trackmate.tracking.LAPTrackerSettings()
  
print(str(settings))
  
#-----------------------------
# Instantiate model and plugin
#-----------------------------
  
model = fiji.plugin.trackmate.TrackMateModel()
model.setSettings(settings)

# We use IJ log window
model.setLogger(fiji.plugin.trackmate.Logger.IJ_LOGGER);
  
trackmate = fiji.plugin.trackmate.TrackMate_(model)

#---------------------
# Execute segmentation
#---------------------
  
print('Segmenting with parameters:')
print(str(settings.segmenter))
print(str(settings.segmenterSettings))
  
trackmate.execSegmentation()
  
print(str(model.getSpots()))
  
#--------------------------
# Execute initial filtering
#--------------------------
  
settings.initialSpotFilterValue = 3.6
  
print('Initial spot filtering with quality above ' + str(settings.initialSpotFilterValue))
  
trackmate.execInitialSpotFiltering()
  
print(str(model.getSpots()))
  
#--------------------------
# Execute spot filtering
#--------------------------
  
filter1 = fiji.plugin.trackmate.FeatureFilter('QUALITY', 20, True)
  
print('Spot filtering with ' + str(filter1))
  
settings.addSpotFilter(filter1)
trackmate.execSpotFiltering()
  
print(str(model.getFilteredSpots()))
  
#-----------------
# Execute tracking
#-----------------
  
print('Tracking with parameters:')
print(str(settings.tracker))
print(str(settings.trackerSettings))
  
trackmate.execTracking()
  
print('Found ' + str(model.getNTracks()) + ' tracks.')
  
#--------------------------------------------------------------
# Use an action to export the results to a specific xml format.
#--------------------------------------------------------------

file = java.io.File('E:/Users/JeanYves/Desktop/results.xml')
fiji.plugin.trackmate.action.ISBIChallengeExporter.exportToFile(model, file)





Loading and reading from a saved TrackMate XML file

Scripting is a good way to interrogate and play non-interactively with tracking results. The example below shows how to load a XML TrackMate file and rebuild a full working model from it.

That way you could for instance redo a full tracking process by only changing one parameter with respect to the saved one. You might also want to check results without relying on the GUI. Etc...

For the example below to work for you, you will have to edit line 12 and put the actual path to your TrackMate file.



import fiji.plugin.trackmate.io.TmXmlReader
import fiji.plugin.trackmate.Logger
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer
import java.io.File


#----------------
# Setup variables
#----------------

# Put here the path to the TrackMate file you want to load
file = java.io.File('E:/Users/JeanYves/Desktop/Data/FakeTracks.xml')

# We have to feed a logger to the reader.
logger = fiji.plugin.trackmate.Logger.DEFAULT_LOGGER

#-------------------
# Instantiate reader
#-------------------

reader = fiji.plugin.trackmate.io.TmXmlReader(file, logger)

# We have to call 'parse()' before doing anything else. 
# Problems with the file will be detected here.
reader.parse()

#-----------------
# Get a full model
#-----------------

# This will return a fully working model, with everything
# stored in the file. Missing fields (e.g. tracks) will be 
# null or None in python
model = reader.getModel();
# model is a fiji.plugin.trackmate.TrackMateModel

#----------------
# Display results
#----------------

# We can now plainly display the model
displayer =  fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer()
displayer.setModel(model)
displayer.render()
displayer.refresh()

#---------------------------------------------
# Get only part of the data stored in the file
#---------------------------------------------

# You might want to access only separate parts of the 
# model. There are methods for that, but a certain order
# must be respected. For instance if you want the 
# filtered spots:

# You have to load first *all* the spots (can take a long time
# if your file is big):
spots = reader.getAllSpots()
# spots is a fiji.plugin.trackmate.SpotCollection

# Then feed the spot collection to the next method:
filtered_spots = reader.getFilteredSpots(spots)
print('Filtered spots:')
print(str(spots))

# If you want to get the tracks, it is a bit trickier. 
# Internally, the tracks are stored as a huge mathematical
# simple graph, which is what you retrieve from the file. 
# There are methods to rebuild the actual tracks, taking
# into account for everything, but frankly, if you want to 
# do that it is simpler to go through the model shown above.
# Here is how to retrieve the graph, which is actually more
# interesting than just the tracks:

graph = reader.readTrackGraph(filtered_spots)
# graph is a  org.jgrapht.graph.SimpleWeightedGraph
# with generic types: <fiji.plugin.trackmate.Spot, 
# org.jgrapht.graph.DefaultWeightedEdge>

#---------------------------------------
# Building a settings object from a file
#---------------------------------------

# Load the basic settings object
settings = reader.getSettings()
# settings is a fiji.plugin.trackmate.Settings
print(str('Basic settings:'))
print(str(settings))
# Note that the settings object is not initialized with
# stored image, segmentation settings and tracking settings.
# You have to reconstruct it manually by pulling stored 
# fields.

# Load the segmentation settings
reader.getSegmenterSettings(settings)
print('Segmenter settings:')
print(str(settings.segmenterSettings))

# Load the tracker settings
reader.getTrackerSettings(settings)
print('Tracker settings:')
print(str(settings.trackerSettings))

# Calling these 2 extra methods also instantiated 
# ready-to-rock segmenter and tracker, respectively:
print('Segmenter chosen:')
print(str(settings.segmenter))
print('Tracker chosen:')
print(str(settings.tracker))


# Load and display the naked image.
# Note that the XML file only stores a link to the image.
# If the link is not valid, the image will not be found.
imp = reader.getImage()
imp.show()

# We also have to feed it to the settings object:
settings.imp = imp

We did not cover how to retrieve saved filters nor the list of filtered tracks. You will have to rely on the javadoc of the TmXmlReader class for that, and apply what we saw. The only key thing to remember is to call the method doublet

reader = fiji.plugin.trackmate.io.TmXmlReader(file, logger)
reader.parse()

before questing the saved model.


JeanYvesTinevez 17:35, 20 June 2012 (CEST)