Skip to content

Commit a1b7d70

Browse files
authored
Merge pull request #299 from trackmate-sc/cli-tools
Utilities to simplify the integration of command-line tools in TrackMate modules
2 parents 41b8986 + 982a1e9 commit a1b7d70

21 files changed

Lines changed: 3350 additions & 65 deletions

src/main/java/fiji/plugin/trackmate/TrackMate.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@
4545
import fiji.plugin.trackmate.features.FeatureFilter;
4646
import fiji.plugin.trackmate.features.SpotFeatureCalculator;
4747
import fiji.plugin.trackmate.features.TrackFeatureCalculator;
48+
import fiji.plugin.trackmate.tracking.SpotImageTrackerFactory;
4849
import fiji.plugin.trackmate.tracking.SpotTracker;
49-
import fiji.plugin.trackmate.util.Threads;
5050
import fiji.plugin.trackmate.util.TMUtils;
51+
import fiji.plugin.trackmate.util.Threads;
5152
import ij.gui.Roi;
5253
import net.imagej.ImgPlus;
5354
import net.imagej.axis.Axes;
@@ -286,10 +287,21 @@ public boolean execTracking()
286287
return true; // Not an error.
287288
}
288289

289-
final SpotTracker tracker = settings.trackerFactory.create( model.getSpots(), settings.trackerSettings );
290+
// Deal with trackers vs image trackers.
291+
final SpotTracker tracker;
292+
if ( SpotImageTrackerFactory.class.isInstance( settings.trackerFactory ) )
293+
{
294+
final SpotImageTrackerFactory f = ( SpotImageTrackerFactory ) settings.trackerFactory;
295+
tracker = f.create( model.getSpots(), settings.trackerSettings, settings.imp );
296+
}
297+
else
298+
{
299+
tracker = settings.trackerFactory.create( model.getSpots(), settings.trackerSettings );
300+
}
301+
290302
if ( tracker == null )
291303
{
292-
logger.log( "Tracker return by factory is null. Skipping tracking.\n" );
304+
logger.log( "Tracker returned by factory is null. Skipping tracking.\n" );
293305
return true; // Not an error.
294306
}
295307

src/main/java/fiji/plugin/trackmate/action/LabelImgExporter.java

Lines changed: 129 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import fiji.plugin.trackmate.Model;
3838
import fiji.plugin.trackmate.SelectionModel;
3939
import fiji.plugin.trackmate.Spot;
40+
import fiji.plugin.trackmate.SpotCollection;
4041
import fiji.plugin.trackmate.TrackMate;
4142
import fiji.plugin.trackmate.TrackModel;
4243
import fiji.plugin.trackmate.gui.displaysettings.DisplaySettings;
@@ -52,8 +53,8 @@
5253
import net.imglib2.RandomAccess;
5354
import net.imglib2.img.Img;
5455
import net.imglib2.img.display.imagej.ImageJFunctions;
56+
import net.imglib2.type.NativeType;
5557
import net.imglib2.type.numeric.RealType;
56-
import net.imglib2.type.numeric.integer.UnsignedShortType;
5758
import net.imglib2.type.numeric.real.FloatType;
5859
import net.imglib2.util.Util;
5960
import net.imglib2.view.Views;
@@ -121,8 +122,7 @@ public void execute( final TrackMate trackmate, final SelectionModel selectionMo
121122

122123
/**
123124
* Creates a new label {@link ImagePlus} where the spots of the specified
124-
* model are painted as ellipsoids taken from their shape, with their track
125-
* ID as pixel value.
125+
* model are painted with their shape, with their track ID as pixel value.
126126
*
127127
* @param trackmate
128128
* the trackmate instance from which we takes the spots to paint.
@@ -156,8 +156,7 @@ public static final ImagePlus createLabelImagePlus(
156156

157157
/**
158158
* Creates a new label {@link ImagePlus} where the spots of the specified
159-
* model are painted as ellipsoids taken from their shape, with their track
160-
* ID as pixel value.
159+
* model are painted with their shape, with their track ID as pixel value.
161160
*
162161
* @param trackmate
163162
* the trackmate instance from which we takes the spots to paint.
@@ -168,7 +167,7 @@ public static final ImagePlus createLabelImagePlus(
168167
* will be 1.
169168
* @param exportSpotsAsDots
170169
* if <code>true</code>, spots will be painted as single dots
171-
* instead of ellipsoids.
170+
* instead their shape.
172171
* @param exportTracksOnly
173172
* if <code>true</code>, only the spots belonging to visible
174173
* tracks will be painted. If <code>false</code>, spots not
@@ -194,8 +193,7 @@ public static final ImagePlus createLabelImagePlus(
194193

195194
/**
196195
* Creates a new label {@link ImagePlus} where the spots of the specified
197-
* model are painted as ellipsoids taken from their shape, with their track
198-
* ID as pixel value.
196+
* model are painted with their shape, with their track ID as pixel value.
199197
*
200198
* @param model
201199
* the model from which we takes the spots to paint.
@@ -206,7 +204,7 @@ public static final ImagePlus createLabelImagePlus(
206204
* 1.
207205
* @param exportSpotsAsDots
208206
* if <code>true</code>, spots will be painted as single dots
209-
* instead of ellipsoids.
207+
* instead their shape.
210208
* @param exportTracksOnly
211209
* if <code>true</code>, only the spots belonging to visible
212210
* tracks will be painted. If <code>false</code>, spots not
@@ -229,8 +227,7 @@ public static final ImagePlus createLabelImagePlus(
229227

230228
/**
231229
* Creates a new label {@link ImagePlus} where the spots of the specified
232-
* model are painted as ellipsoids taken from their shape, with their track
233-
* ID as pixel value.
230+
* model are painted with their shape, with their track ID as pixel value.
234231
*
235232
* @param model
236233
* the model from which we takes the spots to paint.
@@ -241,7 +238,7 @@ public static final ImagePlus createLabelImagePlus(
241238
* 1.
242239
* @param exportSpotsAsDots
243240
* if <code>true</code>, spots will be painted as single dots
244-
* instead of ellipsoids.
241+
* instead their shape.
245242
* @param exportTracksOnly
246243
* if <code>true</code>, only the spots belonging to visible
247244
* tracks will be painted. If <code>false</code>, spots not
@@ -280,18 +277,17 @@ public static final ImagePlus createLabelImagePlus(
280277

281278
/**
282279
* Creates a new label {@link ImagePlus} where the spots of the specified
283-
* model are painted as ellipsoids taken from their shape, with their track
284-
* ID as pixel value.
280+
* model are painted with their shape, with their track ID as pixel value.
285281
*
286282
* @param model
287283
* the model from which we takes the spots to paint.
288284
* @param dimensions
289285
* the desired dimensions of the output image (width, height,
290-
* nZSlices, nFrames) as a 4 element int array. Spots outside
286+
* nZSlices, nFrames) as a 4 element long array. Spots outside
291287
* these dimensions are ignored.
292288
* @param exportSpotsAsDots
293289
* if <code>true</code>, spots will be painted as single dots
294-
* instead of ellipsoids.
290+
* instead their shape.
295291
* @param exportTracksOnly
296292
* if <code>true</code>, only the spots belonging to visible
297293
* tracks will be painted. If <code>false</code>, spots not
@@ -315,8 +311,7 @@ public static final ImagePlus createLabelImagePlus(
315311

316312
/**
317313
* Creates a new label {@link ImagePlus} where the spots of the specified
318-
* model are painted as ellipsoids taken from their shape, with their track
319-
* ID as pixel value.
314+
* model are painted with their shape, with their track ID as pixel value.
320315
*
321316
* @param model
322317
* the model from which we takes the spots to paint.
@@ -326,7 +321,7 @@ public static final ImagePlus createLabelImagePlus(
326321
* these dimensions are ignored.
327322
* @param exportSpotsAsDots
328323
* if <code>true</code>, spots will be painted as single dots
329-
* instead of ellipsoids.
324+
* instead their shape.
330325
* @param exportTracksOnly
331326
* if <code>true</code>, only the spots belonging to visible
332327
* tracks will be painted. If <code>false</code>, spots not
@@ -362,19 +357,19 @@ public static final ImagePlus createLabelImagePlus(
362357
}
363358

364359
/**
365-
* Creates a new label {@link Img} of {@link UnsignedShortType} where the
366-
* spots of the specified model are painted as ellipsoids taken from their
367-
* shape, with their track ID as pixel value.
360+
* Creates a new label {@link Img} of {@link FloatType} where the spots of
361+
* the specified model are painted with their shape, with their track ID as
362+
* pixel value.
368363
*
369364
* @param model
370365
* the model from which we takes the spots to paint.
371366
* @param dimensions
372367
* the desired dimensions of the output image (width, height,
373-
* nZSlices, nFrames) as a 4 element int array. Spots outside
368+
* nZSlices, nFrames) as a 4 element long array. Spots outside
374369
* these dimensions are ignored.
375370
* @param exportSpotsAsDots
376371
* if <code>true</code>, spots will be painted as single dots
377-
* instead of ellipsoids.
372+
* instead their shape.
378373
* @param exportTracksOnly
379374
* if <code>true</code>, only the spots belonging to visible
380375
* tracks will be painted. If <code>false</code>, spots not
@@ -397,19 +392,18 @@ public static final Img< FloatType > createLabelImg(
397392
}
398393

399394
/**
400-
* Creates a new label {@link Img} of {@link UnsignedShortType} where the
401-
* spots of the specified model are painted as ellipsoids taken from their
402-
* shape, with their track ID as pixel value.
395+
* Creates a new label {@link Img} of {@link FloatType} where the spots of
396+
* the specified model are painted with their shape, with an ID pixel value.
403397
*
404398
* @param model
405399
* the model from which we takes the spots to paint.
406400
* @param dimensions
407401
* the desired dimensions of the output image (width, height,
408-
* nZSlices, nFrames) as a 4 element int array. Spots outside
402+
* nZSlices, nFrames) as a 4 element long array. Spots outside
409403
* these dimensions are ignored.
410404
* @param exportSpotsAsDots
411405
* if <code>true</code>, spots will be painted as single dots
412-
* instead of ellipsoids.
406+
* instead their shape.
413407
* @param exportTracksOnly
414408
* if <code>true</code>, only the spots belonging to visible
415409
* tracks will be painted. If <code>false</code>, spots not
@@ -475,6 +469,98 @@ public static final Img< FloatType > createLabelImg(
475469
return lblImg;
476470
}
477471

472+
473+
/**
474+
* Creates a new label {@link ImgPlus} of {@link FloatType} where the spots
475+
* are painted with an ID. All visible spots are painted, whether they are
476+
* in a track or not.
477+
*
478+
* @param spots
479+
* the spots to paint.
480+
* @param dimensions
481+
* the desired dimensions of the output image (width, height,
482+
* nZSlices, nFrames) as a 4 element long array. Spots outside
483+
* these dimensions are ignored.
484+
* @param exportSpotsAsDots
485+
* if <code>true</code>, spots will be painted as single dots
486+
* instead of their shape.
487+
* @param labelIdPainting
488+
* specifies how to paint the label ID of spots. The
489+
* {@link LabelIdPainting#LABEL_IS_TRACK_ID} is not supported and
490+
* defaults to {@link LabelIdPainting#LABEL_IS_SPOT_ID}.
491+
* @param logger
492+
* a {@link Logger} instance, to report progress of the export
493+
* process.
494+
*
495+
* @return a new {@link ImgPlus}.
496+
*/
497+
public static < T extends RealType< T > & NativeType< T > > ImgPlus< T > createLabelImg(
498+
final SpotCollection spots,
499+
final long[] dimensions,
500+
final double[] calibration,
501+
final boolean exportSpotsAsDots,
502+
final LabelIdPainting labelIdPainting,
503+
final T outputType,
504+
final Logger logger )
505+
{
506+
/*
507+
* Create target image.
508+
*/
509+
final Dimensions targetSize = FinalDimensions.wrap( dimensions );
510+
final Img< T > lblImg = Util.getArrayOrCellImgFactory( targetSize, outputType ).create( targetSize );
511+
final AxisType[] axes = new AxisType[] {
512+
Axes.X,
513+
Axes.Y,
514+
Axes.Z,
515+
Axes.TIME };
516+
final ImgPlus< T > imgPlus = new ImgPlus<>( lblImg, "LblImg", axes, calibration );
517+
518+
/*
519+
* How to assign an ID to spots.
520+
*/
521+
522+
final IdGenerator idGenerator;
523+
switch ( labelIdPainting )
524+
{
525+
case LABEL_IS_INDEX:
526+
idGenerator = new SpotIndexGeneratorUniqueInFrame( null, false );
527+
break;
528+
case LABEL_IS_INDEX_MOVIE_UNIQUE:
529+
idGenerator = new SpotIndexGeneratorUniqueInMovie( null, false );
530+
break;
531+
case LABEL_IS_SPOT_ID:
532+
case LABEL_IS_TRACK_ID:
533+
idGenerator = new SpotIdGenerator( null, false );
534+
break;
535+
default:
536+
throw new IllegalArgumentException( "Unknown painting method: " + labelIdPainting );
537+
}
538+
539+
/*
540+
* Frame by frame iteration.
541+
*/
542+
543+
logger.log( "Writing label image.\n" );
544+
for ( int frame = 0; frame < dimensions[ 3 ]; frame++ )
545+
{
546+
final ImgPlus< T > imgCT = TMUtils.hyperSlice( imgPlus, 0, frame );
547+
final SpotWriter spotWriter = exportSpotsAsDots
548+
? new SpotAsDotWriter<>( imgCT )
549+
: new SpotRoiWriter<>( imgCT );
550+
idGenerator.nextFrame();
551+
552+
for ( final Spot spot : spots.iterable( frame, true ) )
553+
{
554+
final int id = idGenerator.id( spot );
555+
spotWriter.write( spot, id );
556+
}
557+
logger.setProgress( ( double ) ( 1 + frame ) / dimensions[ 3 ] );
558+
}
559+
logger.log( "Done.\n" );
560+
561+
return imgPlus;
562+
}
563+
478564
@Plugin( type = TrackMateActionFactory.class )
479565
public static class Factory implements TrackMateActionFactory
480566
{
@@ -685,11 +771,14 @@ public SpotIdGenerator( final TrackModel tm, final boolean visibleTracksOnly )
685771
@Override
686772
public int id( final Spot spot )
687773
{
688-
final Integer trackID = tm.trackIDOf( spot );
689-
if ( null == trackID || !tm.isVisible( trackID ) )
774+
if ( tm != null )
690775
{
691-
if ( visibleTracksOnly )
692-
return -1;
776+
final Integer trackID = tm.trackIDOf( spot );
777+
if ( null == trackID || !tm.isVisible( trackID ) )
778+
{
779+
if ( visibleTracksOnly )
780+
return -1;
781+
}
693782
}
694783
return spot.ID() + 1;
695784
}
@@ -709,11 +798,14 @@ public SpotIndexGeneratorUniqueInMovie( final TrackModel tm, final boolean visib
709798
@Override
710799
public int id( final Spot spot )
711800
{
712-
final Integer trackID = tm.trackIDOf( spot );
713-
if ( null == trackID || !tm.isVisible( trackID ) )
801+
if ( tm != null )
714802
{
715-
if ( visibleTracksOnly )
716-
return -1;
803+
final Integer trackID = tm.trackIDOf( spot );
804+
if ( null == trackID || !tm.isVisible( trackID ) )
805+
{
806+
if ( visibleTracksOnly )
807+
return -1;
808+
}
717809
}
718810
return index.incrementAndGet();
719811
}

0 commit comments

Comments
 (0)