Difference between revisions of "Scripting TrackMate"

(Remove the ISBI challenge example)
(Loading and reading from a saved TrackMate XML file)
Line 281: Line 281:
  
 
<source lang="python">
 
<source lang="python">
import fiji.plugin.trackmate.io.TmXmlReader
+
from fiji.plugin.trackmate.visualization.hyperstack import HyperStackDisplayer
import fiji.plugin.trackmate.Logger
+
from fiji.plugin.trackmate.io import TmXmlReader
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer
+
from fiji.plugin.trackmate import Logger
import java.io.File
+
from fiji.plugin.trackmate import Settings
 +
from fiji.plugin.trackmate import SelectionModel
 +
from fiji.plugin.trackmate.providers import DetectorProvider
 +
from fiji.plugin.trackmate.providers import TrackerProvider
 +
from fiji.plugin.trackmate.providers import SpotAnalyzerProvider
 +
from fiji.plugin.trackmate.providers import EdgeAnalyzerProvider
 +
from fiji.plugin.trackmate.providers import TrackAnalyzerProvider
 +
from java.io import File
 +
import sys
  
  
Line 292: Line 300:
  
 
# Put here the path to the TrackMate file you want to load
 
# Put here the path to the TrackMate file you want to load
file = java.io.File('E:/Users/JeanYves/Desktop/Data/FakeTracks.xml')
+
file = File('/Users/tinevez/Desktop/Data/FakeTracks.xml')
  
 
# We have to feed a logger to the reader.
 
# We have to feed a logger to the reader.
logger = fiji.plugin.trackmate.Logger.DEFAULT_LOGGER
+
logger = Logger.IJ_LOGGER
  
 
#-------------------
 
#-------------------
Line 301: Line 309:
 
#-------------------
 
#-------------------
  
reader = fiji.plugin.trackmate.io.TmXmlReader(file, logger)
+
reader = TmXmlReader(file)
 
+
if not reader.isReadingOk():
# We have to call 'parse()' before doing anything else.
+
sys.exit(reader.getErrorMessage())
# Problems with the file will be detected here.
 
reader.parse()
 
 
 
 
#-----------------
 
#-----------------
 
# Get a full model
 
# Get a full model
Line 314: Line 319:
 
# stored in the file. Missing fields (e.g. tracks) will be  
 
# stored in the file. Missing fields (e.g. tracks) will be  
 
# null or None in python
 
# null or None in python
model = reader.getModel();
+
model = reader.getModel()
# model is a fiji.plugin.trackmate.TrackMateModel
+
# model is a fiji.plugin.trackmate.Model
  
 
#----------------
 
#----------------
Line 321: Line 326:
 
#----------------
 
#----------------
  
# We can now plainly display the model
+
# We can now plainly display the model. It will be shown on an
displayer = fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer()
+
# empty image with default magnification.
displayer.setModel(model)
+
sm = SelectionModel(model)
 +
displayer =  HyperStackDisplayer(model, sm)
 
displayer.render()
 
displayer.render()
displayer.refresh()
 
  
 
#---------------------------------------------
 
#---------------------------------------------
Line 332: Line 337:
  
 
# You might want to access only separate parts of the  
 
# You might want to access only separate parts of the  
# model. There are methods for that, but a certain order
+
# model.  
# must be respected. For instance if you want the
 
# filtered spots:
 
  
# You have to load first *all* the spots (can take a long time
+
spots = model.getSpots()
# if your file is big):
 
spots = reader.getAllSpots()
 
 
# spots is a fiji.plugin.trackmate.SpotCollection
 
# spots is a fiji.plugin.trackmate.SpotCollection
  
# Then feed the spot collection to the next method:
+
logger.log(str(spots))
filtered_spots = reader.getFilteredSpots(spots)
 
print('Filtered spots:')
 
print(str(spots))
 
  
 
# If you want to get the tracks, it is a bit trickier.  
 
# If you want to get the tracks, it is a bit trickier.  
Line 351: Line 349:
 
# There are methods to rebuild the actual tracks, taking
 
# There are methods to rebuild the actual tracks, taking
 
# into account for everything, but frankly, if you want to  
 
# into account for everything, but frankly, if you want to  
# do that it is simpler to go through the model shown above.
+
# do that it is simpler to go through the model:
# Here is how to retrieve the graph, which is actually more
+
 
# interesting than just the tracks:
+
trackIDs = model.getTrackModel().trackIDs(True) # only filtered out ones
 +
for id in trackIDs:
 +
logger.log(str(id) + ' - ' + str(model.getTrackModel().trackEdges(id)))
  
graph = reader.readTrackGraph(filtered_spots)
 
# graph is a  org.jgrapht.graph.SimpleWeightedGraph
 
# with generic types: <fiji.plugin.trackmate.Spot,
 
# org.jgrapht.graph.DefaultWeightedEdge>
 
  
 
#---------------------------------------
 
#---------------------------------------
Line 364: Line 360:
 
#---------------------------------------
 
#---------------------------------------
  
# Load the basic settings object
+
# Reading the Settings object is actually currently complicated. The
settings = reader.getSettings()
+
# reader wants to initialize properly everything you saved in the file,
# settings is a fiji.plugin.trackmate.Settings
+
# including the spot, edge, track analyzers, the filters, the detector,
print(str('Basic settings:'))
+
# the tracker, etc...
print(str(settings))
+
# It can do that, but you must provide the reader with providers, that
# Note that the settings object is not initialized with
+
# are able to instantiate the correct TrackMate Java classes from
# stored image, segmentation settings and tracking settings.
+
# the XML data.
# You have to reconstruct it manually by pulling stored
 
# fields.
 
  
# Load the segmentation settings
+
# We start by creating an empty settings object
reader.getSegmenterSettings(settings)
+
settings = Settings()
print('Segmenter settings:')
 
print(str(settings.segmenterSettings))
 
  
# Load the tracker settings
+
# Then we create all the providers, and point them to the target model:
reader.getTrackerSettings(settings)
+
detectorProvider = DetectorProvider(model)
print('Tracker settings:')
+
trackerProvider = TrackerProvider(model)
print(str(settings.trackerSettings))
+
spotAnalyzerProvider = SpotAnalyzerProvider(model)
 +
edgeAnalyzerProvider = EdgeAnalyzerProvider(model)
 +
trackAnalyzerProvider = TrackAnalyzerProvider(model)
  
# Calling these 2 extra methods also instantiated
+
# Ouf! now we can flesh out our settings object:
# ready-to-rock segmenter and tracker, respectively:
+
reader.readSettings(settings, detectorProvider, trackerProvider, spotAnalyzerProvider, edgeAnalyzerProvider, trackAnalyzerProvider)
print('Segmenter chosen:')
 
print(str(settings.segmenter))
 
print('Tracker chosen:')
 
print(str(settings.tracker))
 
  
 +
logger.log(str('\n\nSETTINGS:'))
 +
logger.log(str(settings))
  
# Load and display the naked image.
+
# The settings object is also instantiated with the target image.
 
# Note that the XML file only stores a link to the 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.
 
# If the link is not valid, the image will not be found.
imp = reader.getImage()
+
imp = settings.imp
 
imp.show()
 
imp.show()
  
# We also have to feed it to the settings object:
+
# With this, we can overlay the model and the source image:
settings.imp = imp
+
displayer = HyperStackDisplayer(model, sm, imp)
 
+
displayer.render()
</source>
 
 
 
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 [http://fiji.sc/javadoc/fiji/plugin/trackmate/io/TmXmlReader.html TmXmlReader] class for that, and apply what we saw. The only key thing to remember is to call the method doublet
 
<source lang="python">
 
reader = fiji.plugin.trackmate.io.TmXmlReader(file, logger)
 
reader.parse()
 
 
</source>
 
</source>
before questing the saved model.
 
  
 
[[User:JeanYvesTinevez|JeanYvesTinevez]] ([[User talk:JeanYvesTinevez|talk]]) 09:16, 7 August 2013 (CDT)
 
[[User:JeanYvesTinevez|JeanYvesTinevez]] ([[User talk:JeanYvesTinevez|talk]]) 09:16, 7 August 2013 (CDT)

Revision as of 10:03, 7 August 2013

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))






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.



from fiji.plugin.trackmate.visualization.hyperstack import HyperStackDisplayer
from fiji.plugin.trackmate.io import TmXmlReader
from fiji.plugin.trackmate import Logger
from fiji.plugin.trackmate import Settings
from fiji.plugin.trackmate import SelectionModel
from fiji.plugin.trackmate.providers import DetectorProvider
from fiji.plugin.trackmate.providers import TrackerProvider
from fiji.plugin.trackmate.providers import SpotAnalyzerProvider
from fiji.plugin.trackmate.providers import EdgeAnalyzerProvider
from fiji.plugin.trackmate.providers import TrackAnalyzerProvider
from java.io import File
import sys


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

# Put here the path to the TrackMate file you want to load
file = File('/Users/tinevez/Desktop/Data/FakeTracks.xml')

# We have to feed a logger to the reader.
logger = Logger.IJ_LOGGER

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

reader = TmXmlReader(file)
if not reader.isReadingOk():
	sys.exit(reader.getErrorMessage())
#-----------------
# 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.Model

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

# We can now plainly display the model. It will be shown on an
# empty image with default magnification.
sm = SelectionModel(model)
displayer =  HyperStackDisplayer(model, sm)
displayer.render()

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

# You might want to access only separate parts of the 
# model. 

spots = model.getSpots()
# spots is a fiji.plugin.trackmate.SpotCollection

logger.log(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:

trackIDs = model.getTrackModel().trackIDs(True) # only filtered out ones
for id in trackIDs:
	logger.log(str(id) + ' - ' + str(model.getTrackModel().trackEdges(id)))


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

# Reading the Settings object is actually currently complicated. The 
# reader wants to initialize properly everything you saved in the file,
# including the spot, edge, track analyzers, the filters, the detector,
# the tracker, etc...
# It can do that, but you must provide the reader with providers, that
# are able to instantiate the correct TrackMate Java classes from
# the XML data.

# We start by creating an empty settings object
settings = Settings()

# Then we create all the providers, and point them to the target model:
detectorProvider 		= DetectorProvider(model)
trackerProvider 		= TrackerProvider(model)
spotAnalyzerProvider	= SpotAnalyzerProvider(model)
edgeAnalyzerProvider	= EdgeAnalyzerProvider(model)
trackAnalyzerProvider 	= TrackAnalyzerProvider(model)

# Ouf! now we can flesh out our settings object:
reader.readSettings(settings, detectorProvider, trackerProvider, spotAnalyzerProvider, edgeAnalyzerProvider, trackAnalyzerProvider)

logger.log(str('\n\nSETTINGS:'))
logger.log(str(settings))

# The settings object is also instantiated with the target 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 = settings.imp
imp.show()

# With this, we can overlay the model and the source image:
displayer =  HyperStackDisplayer(model, sm, imp)
displayer.render()

JeanYvesTinevez (talk) 09:16, 7 August 2013 (CDT)