2323
2424import java .util .ArrayList ;
2525import java .util .HashMap ;
26- import java .util .Iterator ;
2726import java .util .Map ;
2827import java .util .function .DoubleConsumer ;
2928import java .util .function .Supplier ;
3029
3130import javax .swing .JFormattedTextField ;
3231
32+ import fiji .plugin .trackmate .Logger ;
3333import fiji .plugin .trackmate .Model ;
3434import fiji .plugin .trackmate .Settings ;
3535import fiji .plugin .trackmate .Spot ;
4040import fiji .plugin .trackmate .features .FeatureFilter ;
4141import fiji .plugin .trackmate .features .FeatureUtils ;
4242import fiji .plugin .trackmate .gui .displaysettings .DisplaySettings .TrackMateObject ;
43+ import net .imglib2 .util .Pair ;
44+ import net .imglib2 .util .ValuePair ;
4345
4446public class DetectionPreview
4547{
4648
4749 private final DetectionPreviewPanel panel ;
4850
49- private DetectionPreview (
51+ protected DetectionPreview (
5052 final Model model ,
5153 final Settings settings ,
5254 final SpotDetectorFactoryBase < ? > detectorFactory ,
@@ -71,7 +73,12 @@ public DetectionPreviewPanel getPanel()
7173 return panel ;
7274 }
7375
74- private final void preview (
76+ public Logger getLogger ()
77+ {
78+ return panel .logger ;
79+ }
80+
81+ protected void preview (
7582 final Model model ,
7683 final Settings settings ,
7784 final SpotDetectorFactoryBase < ? > detectorFactory ,
@@ -87,78 +94,22 @@ public void run()
8794 {
8895 try
8996 {
90-
91- // Configure local settings.
92- final Settings lSettings = new Settings ( settings .imp );
93- lSettings .tstart = frame ;
94- lSettings .tend = frame ;
95- settings .setRoi ( settings .imp .getRoi () );
96-
97- lSettings .detectorFactory = detectorFactory ;
98- lSettings .detectorSettings = new HashMap <>( detectorSettings );
99-
100- /*
101- * If we have a threshold parameter, we set it to 0, then we
102- * will filter out with real value later.
103- */
104- // Does this detector have a THRESHOLD parameter?
105- final boolean hasThreshold = ( thresholdKey != null ) && ( detectorSettings .containsKey ( thresholdKey ) );
106- final double threshold ;
107- if ( hasThreshold )
108- {
109- threshold = ( ( Double ) detectorSettings .get ( thresholdKey ) ).doubleValue ();
110- lSettings .detectorSettings .put ( thresholdKey , Double .valueOf ( Double .NEGATIVE_INFINITY ) );
111- }
112- else
113- {
114- threshold = Double .NaN ;
115- }
116-
117- // Execute preview.
118- final TrackMate trackmate = new TrackMate ( lSettings );
119- trackmate .getModel ().setLogger ( panel .logger );
120-
121- final boolean detectionOk = trackmate .execDetection ();
122- if ( !detectionOk )
123- {
124- panel .logger .error ( trackmate .getErrorMessage () );
97+ // Run preview.
98+ final Pair < Model , Double > out = runPreviewDetection (
99+ settings ,
100+ frame ,
101+ detectorFactory ,
102+ detectorSettings ,
103+ thresholdKey );
104+ if ( out == null )
125105 return ;
126- }
127-
128- if ( hasThreshold )
129- // Filter by the initial threshold value.
130- trackmate .getModel ().getSpots ().filter ( new FeatureFilter ( Spot .QUALITY , threshold , true ) );
131- else
132- // Make them all visible.
133- trackmate .getModel ().getSpots ().setVisible ( true );
134- panel .logger .log ( "Found " + trackmate .getModel ().getSpots ().getNSpots ( true ) + " spots." );
135-
136- // Wrap new spots in a list.
137- final SpotCollection newspots = trackmate .getModel ().getSpots ();
138- final Iterator < Spot > it = newspots .iterator ( frame , true );
139- final ArrayList < Spot > spotsToCopy = new ArrayList <>( newspots .getNSpots ( frame , true ) );
140- while ( it .hasNext () )
141- spotsToCopy .add ( it .next () );
142-
143- if ( model != null )
144- {
145- // Pass new spot list to model.
146- model .getSpots ().put ( frame , spotsToCopy );
147- // Make them visible
148- for ( final Spot spot : spotsToCopy )
149- spot .putFeature ( SpotCollection .VISIBILITY , SpotCollection .ONE );
150-
151- // Generate event for listener to reflect changes.
152- model .setSpots ( model .getSpots (), true );
153- }
154-
155- // Update histogram if any.
156- if ( panel .chart != null )
157- {
158- final double [] values = FeatureUtils .collectFeatureValues (
159- Spot .QUALITY , TrackMateObject .SPOTS , trackmate .getModel (), false );
160- panel .chart .displayHistogram ( values , threshold );
161- }
106+
107+ final Model sourceModel = out .getA ();
108+ final Double threshold = out .getB ();
109+ panel .logger .log ( "Found " + sourceModel .getSpots ().getNSpots ( true ) + " spots." );
110+
111+ // Update target model.
112+ updateModelAndHistogram ( model , sourceModel , frame , threshold );
162113 }
163114 catch ( final Exception e )
164115 {
@@ -173,6 +124,110 @@ public void run()
173124 }.start ();
174125 }
175126
127+ /**
128+ * Runs the preview with the specified parameters.
129+ *
130+ * @param settings
131+ * the settings object to use as preview. Will be used for its
132+ * image and ROI fields.
133+ * @param frame
134+ * the frame in which to perform the preview.
135+ * @param detectorFactory
136+ * the detector to use for the preview.
137+ * @param detectorSettings
138+ * suitable detection settings for the detector.
139+ * @param thresholdKey
140+ * a key to a parameter that is used by the detector to threshold
141+ * spots based on their quality. This will be used to configure
142+ * the preview so that the generated histogram is interactive. If
143+ * <code>null</code> or not used by the detector, this is simply
144+ * ignored.
145+ * @return a pair of objects: A) The model that contains the results of the
146+ * preview (normally, the visible spots in the specified frame). B)
147+ * The threshold value in case the <code>thresholdKey</code>
148+ * parameter is used. This threshold value is to be used with the
149+ * {@link #updateModelAndHistogram(Model, Model, int, double)}
150+ * method to properly display the quality histogram.
151+ */
152+ protected Pair < Model , Double > runPreviewDetection (
153+ final Settings settings ,
154+ final int frame ,
155+ final SpotDetectorFactoryBase < ? > detectorFactory ,
156+ final Map < String , Object > detectorSettings ,
157+ final String thresholdKey )
158+ {
159+ // Configure local settings.
160+ final Settings lSettings = new Settings ( settings .imp );
161+ lSettings .tstart = frame ;
162+ lSettings .tend = frame ;
163+ settings .setRoi ( settings .imp .getRoi () );
164+
165+ lSettings .detectorFactory = detectorFactory ;
166+ lSettings .detectorSettings = new HashMap <>( detectorSettings );
167+
168+ // Does this detector have a THRESHOLD parameter?
169+ final boolean hasThreshold = ( thresholdKey != null ) && ( detectorSettings .containsKey ( thresholdKey ) );
170+ final double threshold ;
171+ if ( hasThreshold )
172+ {
173+ threshold = ( ( Double ) detectorSettings .get ( thresholdKey ) ).doubleValue ();
174+ lSettings .detectorSettings .put ( thresholdKey , Double .valueOf ( Double .NEGATIVE_INFINITY ) );
175+ }
176+ else
177+ {
178+ threshold = Double .NaN ;
179+ }
180+
181+ // Execute preview.
182+ final TrackMate trackmate = new TrackMate ( lSettings );
183+ trackmate .getModel ().setLogger ( panel .logger );
184+
185+ final boolean detectionOk = trackmate .execDetection ();
186+ if ( !detectionOk )
187+ {
188+ panel .logger .error ( trackmate .getErrorMessage () );
189+ return null ;
190+ }
191+
192+ if ( hasThreshold )
193+ // Filter by the initial threshold value.
194+ trackmate .getModel ().getSpots ().filter ( new FeatureFilter ( Spot .QUALITY , threshold , true ) );
195+ else
196+ // Make them all visible.
197+ trackmate .getModel ().getSpots ().setVisible ( true );
198+
199+ return new ValuePair < Model , Double >( trackmate .getModel (), Double .valueOf ( threshold ) );
200+ }
201+
202+ protected void updateModelAndHistogram ( final Model targetModel , final Model sourceModel , final int frame , final double threshold )
203+ {
204+ final int nSpots = sourceModel .getSpots ().getNSpots ( frame , true );
205+ final ArrayList < Spot > spotsToCopy = new ArrayList <>( nSpots );
206+ final Iterable < Spot > it = sourceModel .getSpots ().iterable ( frame , true );
207+ for ( final Spot spot : it )
208+ spotsToCopy .add ( spot );
209+
210+ if ( targetModel != null )
211+ {
212+ // Pass new spot list to model.
213+ targetModel .getSpots ().put ( frame , spotsToCopy );
214+ // Make them visible
215+ for ( final Spot spot : spotsToCopy )
216+ spot .putFeature ( SpotCollection .VISIBILITY , SpotCollection .ONE );
217+
218+ // Generate event for listener to reflect changes.
219+ targetModel .setSpots ( targetModel .getSpots (), true );
220+ }
221+
222+ // Update histogram if any.
223+ if ( panel .chart != null )
224+ {
225+ final double [] values = FeatureUtils .collectFeatureValues (
226+ Spot .QUALITY , TrackMateObject .SPOTS , sourceModel , false );
227+ panel .chart .displayHistogram ( values , threshold );
228+ }
229+ }
230+
176231 public static Builder create ()
177232 {
178233 return new Builder ();
0 commit comments