trackmate-sc / TrackMate

TrackMate is your buddy for your everyday tracking.
https://imagej.net/plugins/trackmate
GNU General Public License v3.0
167 stars 75 forks source link

Issues with scripting: tracks are not saved in XML #120

Closed MaximeMaW closed 5 years ago

MaximeMaW commented 6 years ago

(Sorry for the long message. I tried to provide a reproducible, minimal (non)working example).

I am adapting the script provided on the Scripting TrackMate page. My goal is to perform the tracking in batch mode, and to save the result of the tracking in the TrackMate file (so that I can then use TrackMate to inspect the trajectories, etc).

To do so, I am using the TmXmlWriter function. However, when I do that, although the XML containing only the tracks is correct (it is the file exportTracks.xml generated by the script below), the XML file containing the full model -- exportModel.xml -- seems to be missing the track edges: the <Edge /> elements of the <Track ...> appear to be empty). Here is an example:

<Track name="Track_510" TRACK_DURATION="11.0" TRACK_START="38.0" TRACK_STOP="49.0" TRACK_DISPLACEMENT="11.617824674726934">
        <Edge />
        <Edge />
        <Edge />
        <Edge />
        <Edge />
        ...
</Track>

Am I doing anything wrong? Is there something that I forgot to instanciate? Or is that a bug? Any pointer would be much appreciated! Many thanks!

===================== I am attaching the following files produced by the .py script below:

(they are all provided in the zipped archive below)

Here is my modified Python code (launched with the command: fiji TrackMate-auto.py --headless. I am providing the exportXML and

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.sparselap import SparseLAPTrackerFactory
from fiji.plugin.trackmate.tracking import LAPUtils
from fiji.plugin.trackmate.action import ExportTracksToXML

from ij import IJ
import java.io.File as File
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
import fiji.plugin.trackmate.io.TmXmlWriter as TmXmlWriter

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

#----------------------------
# 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' : 1.,
    'DO_MEDIAN_FILTERING' : True,
}  

# Configure tracker - We want to allow merges and fusions
settings.trackerFactory = SparseLAPTrackerFactory()
settings.trackerSettings = LAPUtils.getDefaultLAPSettingsMap() # almost good enough
#settings.trackerSettings['ALLOW_TRACK_SPLITTING'] = False
#settings.trackerSettings['ALLOW_TRACK_MERGING'] = False

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

# 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.

## Commented for debug
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()
outputFolder= "."
outFile = File(outputFolder, "exportTracks.xml")
ExportTracksToXML.export(model, settings, outFile)

outFile = File(outputFolder, "exportModel.xml")
writer = TmXmlWriter(outFile)
writer.appendModel(model)
writer.appendSettings(settings)
writer.writeToFile()
print "All Done!"

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

TrackMate_auto.zip

MaximeMaW commented 6 years ago

Hello, any update regarding this issue? Many thanks!

tinevez commented 6 years ago

Not yet. One guy I will not name gave me plenty of work on TrackMate - involving a CSV importer and a better overlay capture - and it is consuming all my time.

tinevez commented 5 years ago

I think it is because there are some features missing required for saving. For instance you need to compute the TARGET_ID and SOURCE_ID of all edges to properly save them.

What I would suggest is then to add all features at once, using feature providers. Like this (this is Java, so you have to adapt to Jython):

If settings is your Settings object:

settings.clearSpotAnalyzerFactories();
        final SpotAnalyzerProvider spotAnalyzerProvider = new SpotAnalyzerProvider();
        final List< String > spotAnalyzerKeys = spotAnalyzerProvider.getKeys();
        for ( final String key : spotAnalyzerKeys )
        {
            final SpotAnalyzerFactory< ? > spotFeatureAnalyzer = spotAnalyzerProvider.getFactory( key );
            settings.addSpotAnalyzerFactory( spotFeatureAnalyzer );
        }

        settings.clearEdgeAnalyzers();
        final EdgeAnalyzerProvider edgeAnalyzerProvider = new EdgeAnalyzerProvider();
        final List< String > edgeAnalyzerKeys = edgeAnalyzerProvider.getKeys();
        for ( final String key : edgeAnalyzerKeys )
        {
            final EdgeAnalyzer edgeAnalyzer = edgeAnalyzerProvider.getFactory( key );
            settings.addEdgeAnalyzer( edgeAnalyzer );
        }

        settings.clearTrackAnalyzers();
        final TrackAnalyzerProvider trackAnalyzerProvider = new TrackAnalyzerProvider();
        final List< String > trackAnalyzerKeys = trackAnalyzerProvider.getKeys();
        for ( final String key : trackAnalyzerKeys )
        {
            final TrackAnalyzer trackAnalyzer = trackAnalyzerProvider.getFactory( key );
            settings.addTrackAnalyzer( trackAnalyzer );
        }
MaximeMaW commented 5 years ago

Hi @tinevez

Thank you very much for the update. I translated your Java code to Python as follows:

from fiji.plugin.trackmate.providers import SpotAnalyzerProvider
from fiji.plugin.trackmate.providers import EdgeAnalyzerProvider
from fiji.plugin.trackmate.providers import TrackAnalyzerProvider

# Compute edge properties, following https://github.com/fiji/TrackMate/issues/120
settings.clearSpotAnalyzerFactories()
spotAnalyzerProvider = SpotAnalyzerProvider()
spotAnalyzerKeys = spotAnalyzerProvider.getKeys()
for key in spotAnalyzerKeys:
    spotFeatureAnalyzer = spotAnalyzerProvider.getFactory(key)
    settings.addSpotAnalyzerFactory(spotFeatureAnalyzer)

settings.clearEdgeAnalyzers()
edgeAnalyzerProvider = EdgeAnalyzerProvider()
edgeAnalyzerKeys = edgeAnalyzerProvider.getKeys()
for key in edgeAnalyzerKeys:
    edgeAnalyzer = edgeAnalyzerProvider.getFactory(key)
    settings.addEdgeAnalyzer(edgeAnalyzer)

settings.clearTrackAnalyzers();
trackAnalyzerProvider = TrackAnalyzerProvider()
trackAnalyzerKeys = trackAnalyzerProvider.getKeys()
for key in trackAnalyzerKeys:
    trackAnalyzer = trackAnalyzerProvider.getFactory(key)
    settings.addTrackAnalyzer(trackAnalyzer)

That seems to solve the problem, thank you so much! I had totally missed this in the documentation. Thanks again!