"""Tools to perform particle tracking with Trackmate ImageJ plugin.
This module includes functions for prepping images and performing tracking
using the TrackMate ImageJ plugin [1]_.
References
----------
.. [1] Tinevez, JY,; Perry, N. & Schindelin, J. et al. (2016), "TrackMate: an
open and extensible platoform for single-particle tracking.", Methods 115:
80-90, PMID 27713081 (on Google Scholar).
"""
import sys
import subprocess
import tempfile
import random
import os.path as op
import numpy as np
import skimage.io as sio
import diff_classifier as dc
import diff_classifier.aws as aws
from sklearn import linear_model
from sklearn import svm
[docs]def partition_im(tiffname, irows=4, icols=4, ores=(2048, 2048),
ires=(512, 512)):
"""Partitions image into smaller images.
Partitions a large image into irows x icols images of size ires and saves
them. Also forces image to be square. Default input image sizes are from
a Nikon/Hamamatsu camera setup (2048 x 2044 pixels).
Parameters
----------
tiffname : string
Location of input image to be partitioned.
irows : int
Number of rows of size ires pixels to be partitioned from source image.
icols : int
Number of columns of size ires pixels to be partitioned from source image.
ores : tuple of int
Input images are scaled to size ores pixels prior to splitting.
ires : tuple of int
Output images are of size ires pixels.
Examples
--------
>>> partition_im('your/sample/image.tif', irows=8, icols=8, ires=(256, 256))
"""
test = sio.imread(tiffname)
oshape = test.shape
test2 = np.zeros((oshape[0], ores[0], ores[1]), dtype=test.dtype)
test2[0:oshape[0], 0:oshape[1], :] = test
new_image = np.zeros((oshape[0], ires[0], ires[1]), dtype=test.dtype)
names = []
for row in range(irows):
for col in range(icols):
new_image = test2[:, row*ires[0]:(row+1)*ires[0],
col*ires[1]:(col+1)*ires[1]]
current = tiffname.split('.tif')[0] + '_%s_%s.tif' % (row, col)
sio.imsave(current, new_image)
names.append(current)
return names
[docs]def mean_intensity(local_im, frame=0):
"""Calculates mean intensity of first frame of input image.
Parameters
----------
local_im : string
Location of input image.
frame : int
Frame at which to perform mean.
Returns
-------
test_intensity : float
Mean intensity of input image.
Examples
--------
>>> mean_intensity('your/sample/image')
"""
test_image = sio.imread(local_im)
test_intensity = np.mean(test_image[frame, :, :])
return test_intensity
[docs]def track(target, out_file, template=None, fiji_bin=None,
tparams={'radius': 3.0, 'threshold': 0.0, 'do_median_filtering': False,
'quality': 15.0, 'xdims': (0, 511), 'ydims': (1, 511),
'median_intensity': 300.0, 'snr': 0.0, 'linking_max_distance': 6.0,
'gap_closing_max_distance': 10.0, 'max_frame_gap': 3,
'track_duration': 20.0}):
"""Performs particle tracking on input video.
Particle tracking is performed with the ImageJ plugin Trackmate. Outputs
a csv file containing analysis settings and particle trajectories.
Parameters
----------
target : str
Full path to a tif file to do tracking on. Can also be a URL
(e.g., 'http://fiji.sc/samples/FakeTracks.tif')
out_file : str
Full path to a csv file to store the results.
template : str, optional
The full path of a template for tracking. Defaults to use
`data/trackmate_template.py` stored in the diff_classifier source-code.
fiji_bin : str
The full path to ImageJ executable file. Includes default search
locations for Mac and Linux systems.
radius : float
Estimated radius of particles in image.
threshold : float
Threshold value for particle detection step.
do_median_filtering : bool
If True, performs a median filter on video prior to tracking.
quality : float
Lower quality cutoff value for particle filtering.
xdims : tuple of int
Upper and lower x limits for particle filtering.
ydims : tuple of int
Upper and lower y limits for particle filtering.
median_intensity : float
Lower median intensity cutoff value for particle filtering.
snr : float
Lower signal to noise ratio cutoff value for particle filtering.
limking_max_distance : float
Maximum allowable distance in pixels between two frames to join
particles in track.
gap_closing_max_distance : float
Maximum allowable distance in pixels between more than two frames to
join particles in track.
max_frame_gap : int
Maximum allowable number of frames a particle is allowed to leave video
and be counted as same trajectory.
track_duration : float
Lower duration cutoff in frames for trajectory filtering.
"""
if template is None:
template = op.join(op.split(dc.__file__)[0],
'data',
'trackmate_template3.py')
if fiji_bin is None:
if sys.platform == "darwin":
fiji_bin = op.join(
'/Applications/Fiji.app/Contents/MacOS/ImageJ-macosx')
elif sys.platform.startswith("linux"):
fiji_bin = op.join(op.expanduser('~'), 'Fiji.app/ImageJ-linux64')
script = ''.join(open(template).readlines())
tpfile = tempfile.NamedTemporaryFile(suffix=".py")
fid = open(tpfile.name, 'w')
fid.write(script.format(target_file=target, radius=str(tparams['radius']),
threshold=str(tparams['threshold']),
do_median_filtering=str(tparams['do_median_filtering']),
quality=str(tparams['quality']),
xd=str(tparams['xdims'][1]), yd=str(tparams['ydims'][1]), ylo=str(tparams['ydims'][0]),
median_intensity=str(tparams['median_intensity']), snr=str(tparams['snr']),
linking_max_distance=str(tparams['linking_max_distance']),
gap_closing_max_distance=str(tparams['gap_closing_max_distance']),
max_frame_gap=str(tparams['max_frame_gap']),
track_duration=str(tparams['track_duration'])))
fid.close()
cmd = "%s --ij2 --headless --run %s" % (fiji_bin, tpfile.name)
print(cmd)
subp = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
fid = open(out_file, 'w')
fid.write(subp.stdout.decode())
fid.close()
[docs]def regress_sys(folder, all_videos, yfit, training_size, randselect=True,
trainingdata=[], frame=0, have_output=True, download=True,
bucket_name='ccurtis.data'):
"""Uses regression based on image intensities to select tracking parameters.
This function uses regression methods from the scikit-learn module to
predict the lower quality cutoff values for particle filtering in TrackMate
based on the intensity distributions of input images. Currently only uses
the first frame of videos for analysis, and is limited to predicting
quality values.
In practice, users will run regress_sys twice in different modes to build
a regression system. First, set have_output to False. Function will return
list of randomly selected videos to include in the training dataset. The
user should then manually track particles using the Trackmate GUI, and enter
these values in during the next round as the input yfit variable.
Parameters
----------
folder : str
S3 directory containing video files specified in all_videos.
all_videos: list of str
Contains prefixes of video filenames of entire video set to be
tracked. Training dataset will be some subset of these videos.
yfit: numpy.ndarray
Contains manually acquired quality levels using Trackmate for the
files contained in the training dataset.
training_size : int
Number of files in training dataset.
randselect : bool
If True, will randomly select training videos from all_videos.
If False, will use trainingdata as input training dataset.
trainingdata : list of str
Optional manually selected prefixes of video filenames to be
used as training dataset.
have_output: bool
If you have already acquired the quality values (yfit) for the
training dataset, set to True. If False, it will output the files
the user will need to acquire quality values for.
bucket_name : str
S3 bucket containing videos to be downloaded for regression
calculations.
Returns
-------
regress_object : list of sklearn.svm.classes.
Contains list of regression objects assembled from the training
datasets. Uses the mean, 10th percentile, 90th percentile, and
standard deviation intensities to predict the quality parameter
in Trackmate.
tprefix : list of str
Contains randomly selected images from all_videos to be included in
training dataset.
"""
if randselect:
tprefix = []
for i in range(0, training_size):
random.seed(i+1)
tprefix.append(all_videos[random.randint(0, len(all_videos))])
if have_output is False:
print("Get parameters for: {}".format(tprefix[i]))
else:
tprefix = trainingdata
if have_output is True:
# Define descriptors
descriptors = np.zeros((training_size, 4))
counter = 0
for name in tprefix:
local_im = name + '.tif'
remote_im = "{}/{}".format(folder, local_im)
if download:
aws.download_s3(remote_im, local_im, bucket_name=bucket_name)
test_image = sio.imread(local_im)
descriptors[counter, 0] = np.mean(test_image[frame, :, :])
descriptors[counter, 1] = np.std(test_image[frame, :, :])
descriptors[counter, 2] = np.percentile(test_image[frame, :, :], 10)
descriptors[counter, 3] = np.percentile(test_image[frame, :, :], 90)
counter = counter + 1
# Define regression techniques
xfit = descriptors
classifiers = [
svm.SVR(),
linear_model.SGDRegressor(),
linear_model.BayesianRidge(),
linear_model.LassoLars(),
linear_model.ARDRegression(),
linear_model.PassiveAggressiveRegressor(),
linear_model.TheilSenRegressor(),
linear_model.LinearRegression()]
regress_object = []
for item in classifiers:
clf = item
regress_object.append(clf.fit(xfit, yfit))
return regress_object
else:
return tprefix
[docs]def regress_tracking_params(regress_object, to_track,
regmethod='LinearRegression', frame=0):
"""Predicts quality values to be used in particle tracking.
Uses the regress object from regress_sys to predict tracking
parameters for TrackMate analysis.
Parameters
----------
regress_object: list of sklearn.svm.classes.
Obtained from regress_sys
to_track: string
Prefix of video files to be tracked.
regmethod: {'LinearRegression', 'SVR', 'SGDRegressor', 'BayesianRidge',
'LassoLars', 'ARDRegression', 'PassiveAggressiveRegressor',
'TheilSenRegressor'}
Desired regression method.
Returns
-------
fqual: float
Predicted quality factor used in TrackMate analysis.
"""
local_im = to_track + '.tif'
pX = np.zeros((1, 4))
test_image = sio.imread(local_im)
pX[0, 0] = np.mean(test_image[frame, :, :])
pX[0, 1] = np.std(test_image[frame, :, :])
pX[0, 2] = np.percentile(test_image[frame, :, :], 10)
pX[0, 3] = np.percentile(test_image[frame:, :, :], 90)
quality = []
for item in regress_object:
quality.append(item.predict(pX)[0])
if regmethod == 'SVR':
fqual = quality[0]
elif regmethod == 'SGDRegressor':
fqual = quality[1]
elif regmethod == 'BayesianRidge':
fqual = quality[2]
elif regmethod == 'LassoLars':
fqual = quality[3]
elif regmethod == 'ARDRegression':
fqual = quality[4]
elif regmethod == 'PassiveAggressiveRegressor':
fqual = quality[5]
elif regmethod == 'TheilSenRegressor':
fqual = quality[6]
elif regmethod == 'LinearRegression':
fqual = quality[7]
else:
fqual = 3.0
return fqual