trackmate-sc / TrackMate

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

Broken script after update #207

Closed phisanti closed 2 years ago

phisanti commented 2 years ago

I have been writing scripts with TrackMatefor a while. However, since the last update (I believe around October) the script has stopped working. The script is relatively simple aiming to iterate over images on a folder and track different bacteria using a reference channel. Here is the code:

#@ File(label="Input directory", description="Select the directory with input images", style="directory") inputDir
#@ File(label="Output directory", description="Select the output directory", style="directory") outputFolder

import sys
import csv
import os
import Stack_Interleaver
from ij import IJ, ImagePlus
from ij.plugin import Duplicator, ImageCalculator, GroupedZProjector, HyperStackConverter
from ij.io import FileSaver, DirectoryChooser
from ij.gui import WaitForUserDialog, GenericDialog, NonBlockingGenericDialog
from ij.plugin.frame import RoiManager
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 CaptureOverlayAction as CaptureOverlayAction
import fiji.plugin.trackmate.action.ExportStatsToIJAction as ExportStatsToIJAction
import fiji.plugin.trackmate.features.TrackFeatureCalculator as TrackFeatureCalculator
import fiji.plugin.trackmate.features.spot.SpotIntensityAnalyzerFactory as SpotIntensityAnalyzerFactory
import fiji.plugin.trackmate.features.spot.SpotContrastAndSNRAnalyzer as SpotContrastAndSNRAnalyzer
import fiji.plugin.trackmate.features.spot.SpotContrastAndSNRAnalyzerFactory as SpotContrastAndSNRAnalyzerFactory
import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer as HyperStackDisplayer
import fiji.plugin.trackmate.features.track.TrackDurationAnalyzer as TrackDurationAnalyzer
import fiji.plugin.trackmate.features.FeatureFilter as FeatureFilter
import fiji.plugin.trackmate.features.track.TrackIndexAnalyzer as TrackIndexAnalyzer
import fiji.plugin.trackmate.visualization.PerTrackFeatureColorGenerator as PerTrackFeatureColorGenerator
import fiji.plugin.trackmate.extra.spotanalyzer.SpotMultiChannelIntensityAnalyzerFactory as SpotMultiChannelIntensityAnalyzerFactory

files_mask = []
files_raw = []
for i in inputDir.listFiles():
    file_i = str(i)

    if "MASK" in file_i:

        files_mask.append(i.getName())
    else:
        files_raw.append(i.getName())

    #----------------------------
    # Define interactive dialogs
    #----------------------------

def dialog_size_thr(title='Select images for processing'):

    # Defining the dialog
    gd = GenericDialog(title)
    gd.addNumericField("Cell size: ", 1, 1)
    gd.addNumericField("Threshold: ", 10, 0)
    gd.showDialog()

    if gd.wasCanceled():
        return None

    # Extract input values

    size = gd.getNextNumber()
    thr = gd.getNextNumber()
    return [size, thr]

def dialog_TrackCheck(title='Repeat tracking analysis?'):

    # Define dialog
    gd = NonBlockingGenericDialog(title)
    gd.enableYesNoCancel("Repeat tracking", "No")
    gd.showDialog()

    # Extract input values

    if gd.wasCanceled():
        sys.exit(0)
    if gd.wasOKed():
        return True
    else:
        return False

    #----------------------------
    # Loop over images
    #----------------------------

n = len(files_raw)
for f in range(n):

    # Image preparation

    experiment = files_raw[f] # Get experiment file
    mask = [s for s in files_mask if experiment[:-4] in s]
    print(mask)

    imp = IJ.openImage(os.path.join(inputDir.getCanonicalPath(), experiment))
    imp2 = IJ.openImage(os.path.join(inputDir.getCanonicalPath(), mask[0]))
    #experiment = experiment[:-4]
    print(experiment)

    # Create file with results
    outpath = outputFolder.getPath() + "/"+ experiment + ".csv"
    resultFile = open(outpath, 'w')
    writer = csv.writer(resultFile)
    csvWriter = csv.writer(resultFile, delimiter=',', quotechar='|')
    csvWriter.writerow(['TRACK_ID','QUALITY','POSITION_X','POSITION_Y', 'POSITION_T','FRAME', 'MEAN_MASK','MEAN_INTENSITY', 'STANDARD_DEVIATION','ESTIMATED_DIAMETER','CONTRAST','SNR', 'REF'])

    # Get frame interval and original pixel size

    calibration  = imp.getCalibration()
    frame_interval = calibration.frameInterval
    pxl_distance = 1/calibration.pixelHeight

    # Sharpen borders

    IJ.run(imp, "Subtract Background...", "rolling=15 stack")
    IJ.run(imp2, "Subtract Background...", "rolling=15 stack")
    IJ.run(imp2, "Convolve...", "text1=[-1 -1 -1 -1 -1\n-1 -1 5 -1 -1\n-1 5 24 5 -1\n-1 5 24 5 -1\n-1 5 24 5 -1\n-1 -1 5 -1 -1\n-1 -1 -1 -1 -1\n] normalize stack")

    interleaver = Stack_Interleaver()

    imp = interleaver.interleave(imp.getStack(), imp2.getStack()) #
    imp = ImagePlus(experiment, imp)
    stack = imp.getStack() # get stack for later measurement of the background
    n_slices = imp.getStackSize()/2
    Final = HyperStackConverter.toHyperStack(imp, 2, 1, n_slices, "Color")
    IJ.run(Final, "Set Scale...", "distance=" + str(pxl_distance) +" known=1 unit=micron")

    rm = RoiManager.getRoiManager()

    Final.show()
    myWait = WaitForUserDialog ("Add channel FL ROI", "Select the background region?")
    myWait.show()

    stack = imp.getStack() # get stack for later measurement of the background
    ra = rm.getRoisAsArray()[0]
    IJ.run("Select None", "")

    #----------------------------
    # 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)
    logger = Logger.IJ_LOGGER

    #------------------------
    # Prepare settings object
    #------------------------

    run_tracker = True
    while run_tracker:

        # Get cell size and pixel threshold

        cell_size, threshold = dialog_size_thr()
        settings = Settings()
        settings.setFrom(Final)

        # Configure detector - We use the Strings for the keys

        settings.detectorFactory = LogDetectorFactory()
        settings.detectorSettings = { 
            'DO_SUBPIXEL_LOCALIZATION' : True,
            'RADIUS' : cell_size,
            'TARGET_CHANNEL' : 2,
            'THRESHOLD' : threshold,
            '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['LINKING_MAX_DISTANCE'] = 2.5
        settings.trackerSettings['GAP_CLOSING_MAX_DISTANCE'] = 2.5
        settings.trackerSettings['MAX_FRAME_GAP'] = n_slices/4
        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.
        # Spot analyzer: we want the multi-C intensity analyzer.

        settings.addSpotAnalyzerFactory( SpotMultiChannelIntensityAnalyzerFactory() )
        settings.addTrackAnalyzer(TrackDurationAnalyzer())
        settings.addTrackAnalyzer( TrackIndexAnalyzer() )
        settings.addSpotAnalyzerFactory(SpotIntensityAnalyzerFactory())
        settings.addSpotAnalyzerFactory(SpotContrastAndSNRAnalyzerFactory())

        #-------------------
        # 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)
        color = PerTrackFeatureColorGenerator(model, 'TRACK_DURATION')
        displayer =  HyperStackDisplayer(model, selectionModel, Final)
        displayer.setDisplaySettings('TrackColoring', color)
        displayer.render()
        displayer.refresh()

        run_tracker = dialog_TrackCheck()

    # The feature model, that stores edge and track features.
    model.getLogger().log(str(model))

    trackIDs = model.getTrackModel().trackIDs(True) # only filtered out ones
    for id in trackIDs:

        # Fetch the track feature from the feature model.

        track = model.getTrackModel().trackSpots(id)
        for spot in track:
            sid = spot.ID()
            # Fetch spot features directly from spot. 
            x = spot.getFeature('POSITION_X')
            y = spot.getFeature('POSITION_Y') 
            pos_t = spot.getFeature('POSITION_T') * frame_interval

            t = spot.getFeature('FRAME')
            q = spot.getFeature('QUALITY')
            mean = spot.getFeature('MEAN_INTENSITY')
            mean_mask = spot.getFeature( 'MEAN_INTENSITY%02d' % (2) )

            std = spot.getFeature('STANDARD_DEVIATION')
            est_r = spot.getFeature('ESTIMATED_DIAMETER')
            contrast = spot.getFeature('CONTRAST')
            snr = spot.getFeature('SNR')
            processor = 2 * (t) + 1
            ip = stack.getProcessor(int(processor))
            ip.setRoi(ra)
            stats = ip.getStatistics()

            # Write results
            csvWriter.writerow([str(id), str(q), str(x),str(y), str(pos_t), str(t),  str(mean), str(mean_mask), str(std), str(est_r), str(contrast), str(snr), str(stats.mean)])

    resultFile.close()
    IJ.run("Close All", "")
    rm.runCommand("Delete")
    Final.close()

The problem is that now it says that some modules do not exist anymore. These are:

import fiji.plugin.trackmate.action.ExportStatsToIJAction as ExportStatsToIJAction
import fiji.plugin.trackmate.features.spot.SpotIntensityAnalyzerFactory as SpotIntensityAnalyzerFactory

In addition, I have noticed that I am running the latest version from MAVEN (which renders into a file called TrackMate_-0.0.0-STUB) and cites the 2021 paper when opened (https://doi.org/10.1101/2021.09.03.458852). I believe that is the 7.5 version. Still, the version released last year was called 7.1. Is that correct?

In any case, if you could help me to fix the script so that I can run the script again, I will highly appreciate it.

Kind regards,

imagesc-bot commented 2 years ago

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/script-broken-with-latest-trackmate-update/61962/2

tinevez commented 2 years ago

Fixed here: https://forum.image.sc/t/script-broken-with-latest-trackmate-update/61962/6?u=tinevez