Sure, its a bit of a mess though since I’m running trackmate inside a class function to make it easier to run analysis of multiple cases:
import os, glob, sys
import csv
from ij import IJ,ImageJ, ImageStack,WindowManager
from __builtin__ import None
from ij.plugin import ImageCalculator
from ij.plugin import FolderOpener
from ij.plugin import ZProjector
import logging
logging.basicConfig(level=logging.DEBUG)
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
from fiji.plugin.trackmate.detection import LogDetectorFactory
import fiji.plugin.trackmate.tracking.sparselap.SparseLAPTrackerFactory as SparseLAPTrackerFactory
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
import fiji.plugin.trackmate.features.FeatureAnalyzer as FeatureAnalyzer
import fiji.plugin.trackmate.features.spot.SpotContrastAndSNRAnalyzerFactory as SpotContrastAndSNRAnalyzerFactory
import fiji.plugin.trackmate.action.ExportStatsToIJAction as ExportStatsToIJAction
import fiji.plugin.trackmate.io.TmXmlReader as TmXmlReader
import fiji.plugin.trackmate.action.ExportTracksToXML as ExportTracksToXML
import fiji.plugin.trackmate.io.TmXmlWriter as TmXmlWriter
import fiji.plugin.trackmate.features.ModelFeatureUpdater as ModelFeatureUpdater
import fiji.plugin.trackmate.features.SpotFeatureCalculator as SpotFeatureCalculator
import fiji.plugin.trackmate.features.spot.SpotContrastAndSNRAnalyzer as SpotContrastAndSNRAnalyzer
import fiji.plugin.trackmate.features.spot.SpotIntensityAnalyzerFactory as SpotIntensityAnalyzerFactory
import fiji.plugin.trackmate.features.spot.SpotRadiusEstimatorFactory as SpotRadiusEstimatorFactory
import fiji.plugin.trackmate.features.edges.EdgeVelocityAnalyzer as EdgeVelocityAnalyzer
import fiji.plugin.trackmate.features.edges.EdgeTargetAnalyzer as EdgeTargetAnalyzer
import fiji.plugin.trackmate.features.edges.EdgeTimeLocationAnalyzer as EdgeTimeLocationAnalyzer
import fiji.plugin.trackmate.features.track.TrackSpeedStatisticsAnalyzer as TrackSpeedStatisticsAnalyzer
import fiji.plugin.trackmate.util.TMUtils as TMUtils
import fiji.plugin.trackmate.features.track.TrackDurationAnalyzer as TrackDurationAnalyzer
import fiji.plugin.trackmate.features.track.TrackLocationAnalyzer as TrackLocationAnalyzer
import fiji.plugin.trackmate.features.track.TrackSpotQualityFeatureAnalyzer as TrackSpotQualityFeatureAnalyzer
import fiji.plugin.trackmate.action.ExportTracksToXML as ExportTracksToXML
from fiji.plugin.trackmate.action import TrackBranchAnalysis as TrackBranchAnalysis
from fiji.plugin.trackmate.action import CaptureOverlayAction as CaptureOverlayAction
from fiji.plugin.trackmate.gui import TrackMateWizard as TrackMateWizard
from fiji.plugin.trackmate.gui import TrackMateGUIController
import java.io.File as File
from java.lang import System
class pre_fiji_case:
def __init__(self, path, overwrite_settings=False, overwrite_movie=True):
if path.endswith('/'):
path = path[:-1]
self.path = path
self.analysis_path = os.path.join(path,'analysis')
self.overwrite_settings = overwrite_settings
self.overwrite_movie = overwrite_movie
self.case_file_path = os.path.join(self.analysis_path, "case.settings")
#Default settings (Will be overwritten if case.settings file exists)
self.background_removal = "max"
self.mask_threshold_method = "Default"
self.fill_hole = 1
self.track_threshold = 0.1
#Figure out tracking diameter based on naming convention
#FolderName: particleMaterial_ParticleSize_WallMaterial_FallHeight_Temperature
case_name = os.path.basename(path)
try:
logging.debug("The split was {}".format(case_name.split('_')))
self.track_diameter = float(case_name.split('_')[1].replace('mm',''))
logging.debug("Read tracking diameter from folder name as {}mm".format(self.track_diameter))
except (ValueError,IndexError) as e:
logging.warning("Did not manage to guess tracking diameter from folder name!")
self.track_diameter = 1.0
if os.path.exists(self.analysis_path) == False:
try:
os.mkdir(self.analysis_path)
except OSError:
logging.debug("Creation of the directory %s failed" % self.analysis_path)
else:
logging.debug("Successfully created the directory %s " % self.analysis_path)
#If case.settings file exists read and import settings for case
if os.path.exists(self.case_file_path) and not self.overwrite_settings:
logging.debug("Reading settings from file instead of defaults!")
with open(self.case_file_path) as file:
readCSV = csv.reader(file, delimiter=',')
csv_file = zip(*readCSV)
for i in csv_file:
col = list(i)
logging.debug("Reading {}".format(col))
if col[0] == "background_removal":
self.background_removal = col[1]
elif col[0] == "mask_threshold_method":
self.mask_threshold_method = col[1]
elif col[0] == "fill_hole":
self.fill_hole = bool(int(col[1]))
elif col[0] == "track_diameter":
self.track_diameter = float(col[1])
elif col[0] == "track_threshold":
self.track_threshold = float(col[1])
else:
#if no case.settings set default settings
with open(self.case_file_path, 'w') as file:
writer = csv.writer(file)
writer.writerow(["background_removal", "mask_threshold_method", "fill_hole","track_diameter", "track_threshold"])
writer.writerow([self.background_removal, self.mask_threshold_method, self.fill_hole, self.track_diameter, self.track_threshold])
def run_fiji_analysis(self):
# Run fiji
self.open_in_fiji()
self.set_scalebar()
self.export_movie(name=self.case_name)
logging.debug("Running analysis on case: {}".format(self.case_name))
# Pre-segmentation
IJ.run(self.imp,"32-bit", "")
#IJ.run(self.imp, "Invert", "stack")
#Reorder stacks Z and T
#
self.export_snapshot(name='Step_0_32bit')
# Remove gradient background
if self.background_removal is not None:
logging.debug("\tBackground removal: {}".format(self.background_removal))
IJ.run(self.imp, "Subtract Background...", "rolling=50 light stack")
#IJ.run(self.imp, "Median...", "radius=5 stack")
self.export_snapshot(name='Step_1_removed_background_32bit')
# Segmentation
if self.mask_threshold_method is not None:
logging.debug("\tThreshold: {}".format(self.mask_threshold_method))
IJ.run(self.imp, "Convert to Mask", "method="+self.mask_threshold_method + " background=Light calculate")
self.export_snapshot(name='Step_2_masked_8bit')
# Post-segmentation
if self.fill_hole == True:
logging.debug("\tFilling mask holes.")
IJ.run(self.imp,"Fill Holes", "stack")
self.export_snapshot(name='Step_3_filled_holes_8bit')
logging.debug("\tStarting TrackMate")
self.run_trackmate_analysis()
def run_trackmate_analysis(self):
#Calculated how high intensity a full sphere is assuming 8-bit
pixel_max = 255
cal = self.imp.getCalibration()
x = cal.pixelWidth
y = cal.pixelHeight
area_per_pixel = 1/x*y
area_sphere = 3.14*(0.5*self.track_diameter)*(0.5*self.track_diameter)
total_intensity_full_sphere = pixel_max*area_per_pixel/(area_sphere)
model = Model()
# Swap Z and T dimensions if T=1
dims = self.imp.getDimensions() # default order: XYCZT
if (dims[4] == 1):
self.imp.setDimensions( dims[2],dims[4],dims[3] )
# Send all messages to ImageJ log window.
model.setLogger(Logger.IJ_LOGGER)
#------------------------
# Prepare settings object
#------------------------
settings = Settings()
settings.setFrom(self.imp)
# Configure detector - We use the Strings for the keys
settings.detectorFactory = LogDetectorFactory()
settings.detectorSettings = {
'DO_SUBPIXEL_LOCALIZATION' : True,
'RADIUS' : float(0.5*self.track_diameter),
'THRESHOLD' : self.track_threshold,
'DO_MEDIAN_FILTERING' : False,
}
filter1 = FeatureFilter('QUALITY', 0.5, True)
settings.addSpotFilter(filter1)
filter2 = FeatureFilter('TOTAL_INTENSITY', total_intensity_full_sphere*0.8, True)
settings.addSpotFilter(filter2)
# Configure tracker
settings.trackerFactory = SparseLAPTrackerFactory()
settings.trackerSettings = LAPUtils.getDefaultLAPSettingsMap()
settings.trackerSettings['LINKING_MAX_DISTANCE'] = 20.0
settings.trackerSettings['GAP_CLOSING_MAX_DISTANCE'] = 20.0
settings.trackerSettings['MAX_FRAME_GAP']= 8
settings.addSpotAnalyzerFactory(SpotIntensityAnalyzerFactory())
settings.addSpotAnalyzerFactory(SpotRadiusEstimatorFactory())
settings.addSpotAnalyzerFactory(SpotContrastAndSNRAnalyzerFactory())
# Add an analyzer for some track features, such as the track mean speed.
settings.addTrackAnalyzer(TrackSpeedStatisticsAnalyzer())
settings.addTrackAnalyzer(TrackDurationAnalyzer())
settings.addTrackAnalyzer(TrackLocationAnalyzer())
settings.addTrackAnalyzer(TrackSpotQualityFeatureAnalyzer())
settings.addEdgeAnalyzer(EdgeVelocityAnalyzer())
settings.addEdgeAnalyzer(EdgeTargetAnalyzer())
settings.addEdgeAnalyzer(EdgeTimeLocationAnalyzer())
filter3 = FeatureFilter('TRACK_DURATION', 3, True)
settings.addTrackFilter(filter3)
settings.initialSpotFilterValue = 0
#----------------------
# Instantiate trackmate
#----------------------
trackmate = TrackMate(model, settings)
#------------
# Execute all
#------------
ok = trackmate.checkInput()
if not ok:
sys.exit(str(trackmate.getErrorMessage()))
ok = trackmate.process()
if not ok:
sys.exit(str(trackmate.getErrorMessage()))
#----------------
# Display results
#----------------
model.getLogger().log('Found ' + str(model.getTrackModel().nTracks(True)) + ' tracks.')
selectionModel = SelectionModel(model)
displayer = HyperStackDisplayer(model, selectionModel, self.imp)
displayer.render()
displayer.refresh()
esta = ExportStatsToIJAction()
esta.execute(trackmate)
overlay = CaptureOverlayAction()
overlay.execute(trackmate)
# Export results
if os.path.exists(self.analysis_path) == False:
try:
os.mkdir(self.analysis_path)
except OSError:
print ("Creation of the directory %s failed" % self.analysis_path)
else:
print ("Successfully created the directory %s " % self.analysis_path)
win_names = ["Spots in tracks statistics","Links in tracks statistics","Track statistics"]
windows = [WindowManager.getWindow(i) for i in win_names]
for i in windows:
WindowManager.setWindow(i)
logging.debug("looking at window {}".format(i.title))
IJ.saveAs("Results", os.path.join(self.analysis_path,i.title + ".csv"))
IJ.run("Close", "")
#Close log
WindowManager.setWindow(WindowManager.getWindow("Log"))
IJ.run("Close", "")
self.export_movie(name=self.case_name+"_Tracking_analysis")
def open_in_fiji(self):
#IJ.run("Image Sequence...", "open=" + self.path + " use file=.tif sort")
#self.imp = IJ.getImage()
self.imp = FolderOpener.open(self.path, " file=.tif")
#
self.case_name = self.imp.getTitle()
#IJ.getImage().close()
self.imp.show()
self.nrOfFrames = self.imp.getNSlices()
logging.debug("Read {} frames".format(self.nrOfFrames))
def export_snapshot(self,name,position = None,file_type = 'PNG'):
if (position is None):
position = int(0.5*self.nrOfFrames)
self.imp.setPosition(1,position,1)
logging.debug("Showing position {}".format(position))
if os.path.exists(self.analysis_path) == False:
try:
os.mkdir(self.analysis_path)
except OSError:
print ("Creation of the directory %s failed" % self.analysis_path)
else:
print ("Successfully created the directory %s " % self.analysis_path)
IJ.saveAs(self.imp, 'PNG', os.path.join(self.analysis_path,name+'.png'))
self.imp.setTitle(self.case_name)
def export_movie(self,name, scalebar=True):
movie_title = os.path.join(self.analysis_path, name + ".avi")
if os.path.exists(movie_title) == False or self.overwrite_movie:
if scalebar:
IJ.run(self.imp, "Scale Bar...",
"width=1 color=Black background=None location=[Upper Right] bold overlay")
IJ.run(self.imp, "AVI... ", "compression=JPEG frame=15 save=" + movie_title)
if scalebar:
IJ.run("Remove Overlay")
def set_scalebar(self):
child_scalebar_path = os.path.join(self.path, 'scalebar.txt')
parent_scalebar_path = os.path.join(os.path.dirname(self.path), "scalebar.txt")
if os.path.exists(child_scalebar_path):
self.scalebar_string = get_scalebar_string(child_scalebar_path)
elif os.path.exists(parent_scalebar_path):
self.scalebar_string = get_scalebar_string(parent_scalebar_path)
else:
logging.critical("Warning: No scalebar found! Will not set scale")
self.scalebar_string = None
if self.scalebar_string is not None:
logging.debug("\tScalebar set to {}".format(self.scalebar_string))
IJ.run(self.imp, "Set Scale...", self.scalebar_string)
def get_scalebar_string(path):
path = os.path.join(path, "")
case_folder = os.path.join(path, "scalebar.txt")
parent_folder = os.path.join(os.path.dirname(os.path.dirname(path)), "scalebar.txt")
if os.path.exists(case_folder):
scalebar_file = case_folder
elif os.path.exists(parent_folder):
scalebar_file = parent_folder
else:
scalebar_file = None
if scalebar_file is not None:
with open(scalebar_file) as f:
scalebar_string = f.readline()
else:
scalebar_string = None
return scalebar_string
main_folder = "/home/eidevag/VIPP/experiments/artic_falls_2019/test_data/small_data/"
sub_folders = [x[0] for x in os.walk(main_folder)][1:]
test = []
for root, dirs, files in os.walk(main_folder):
[dirs.remove(d) for d in list(dirs) if d.startswith('.') or d in ["analysis","post",'Lib']]
logging.debug("Looking into {}".format(root))
if any('.tif' in x for x in files):
case = pre_fiji_case(root,overwrite_settings=True)
case.run_fiji_analysis()