4141import net .imglib2 .view .IntervalView ;
4242import net .imglib2 .view .Views ;
4343
44- import org .mastodon .mamut .util .appose .ApposeProcess ;
45- import org .mastodon .mamut .util .ByteFormatter ;
44+ import org .apposed .appose .Appose ;
45+ import org .apposed .appose .Environment ;
46+ import org .apposed .appose .Service ;
4647import org .mastodon .mamut .detection .util .SpimImageProperties ;
4748import org .mastodon .mamut .model .ModelGraph ;
49+ import org .mastodon .mamut .util .ByteFormatter ;
4850import org .mastodon .mamut .util .ImgUtils ;
4951import org .mastodon .mamut .util .LabelImageUtils ;
5052import org .mastodon .tracking .detection .AbstractDetectorOp ;
@@ -78,13 +80,13 @@ public abstract class DeepLearningDetector extends AbstractSpotDetectorOp
7880 @ Parameter
7981 protected Context context ;
8082
83+ protected Service pythonService ;
84+
8185 /**
8286 * Represents the maximum allowable size in bytes for datasets handle via the appose java-python bridge.
8387 */
8488 private static final int MAX_SIZE_IN_BYTES = Integer .MAX_VALUE - 1 ;
8589
86- protected ApposeProcess apposeProcess ;
87-
8890 @ Override
8991 public void compute ( final List < SourceAndConverter < ? > > sources , final ModelGraph graph )
9092 {
@@ -111,17 +113,39 @@ public void compute( final List< SourceAndConverter< ? > > sources, final ModelG
111113 log .info ( "Initialize python environment." );
112114 log .info ( "On first time use this requires internet connection and may take a couple of minutes." );
113115 log .info ( "Progress can be observed using FIJI console: FIJI > Window > Console." );
114- for ( int timepoint = minTimepoint ; timepoint <= maxTimepoint ; timepoint ++ )
116+ Environment environment = Appose .mamba ().scheme ( "environment.yml" ).content ( getPythonEnvContent () ).logDebug ()
117+ .subscribeProgress ( ( title , cur , max ) -> logger .info ( "{}: {}/{}" , title , cur , max ) )
118+ .subscribeOutput ( logger ::info )
119+ .subscribeError ( logger ::error ).build ();
120+ if ( logger .isInfoEnabled () )
121+ logger .info ( "Set up environment. Path: {}" , environment .base () );
122+ try (Service python = environment .python ())
115123 {
116- // We use the `statusService to show progress.
117- statusService .showProgress ( timepoint - minTimepoint + 1 , maxTimepoint - minTimepoint + 1 );
118-
119- if ( isCanceled () )
120- break ; // Exit but don't fail.
121-
122- if ( DetectionUtil .isPresent ( sources , settings .getSetupId (), timepoint ) )
123- detectAndAddSpots ( sources , graph , settings .getSetupId (), timepoint , settings .getResolutionLevel () );
124+ if ( isWindows () )
125+ python .init ( getPythonEnvInit () );
126+
127+ // First, get the source for the current channel (or setup) at the desired time-point. In BDV jargon, this is a source.
128+ final Source < ? > source = sources .get ( settings .getSetupId () ).getSpimSource ();
129+ RandomAccessibleInterval < ? > image = source .getSource ( 0 , 0 );
130+
131+ Service .Task importTask = python .task ( getImportScript ( !is3D ( image ) ), "main" );
132+ importTask .waitFor ();
133+ this .pythonService = python ;
134+ for ( int timepoint = minTimepoint ; timepoint <= maxTimepoint ; timepoint ++ )
135+ {
136+ // We use the `statusService to show progress.
137+ statusService .showProgress ( timepoint - minTimepoint + 1 , maxTimepoint - minTimepoint + 1 );
138+
139+ if ( isCanceled () )
140+ break ; // Exit but don't fail.
141+
142+ if ( DetectionUtil .isPresent ( sources , settings .getSetupId (), timepoint ) )
143+ detectAndAddSpots ( sources , graph , settings .getSetupId (), timepoint , settings .getResolutionLevel (), python );
144+ }
145+ if ( logger .isInfoEnabled () )
146+ logger .info ( "Finished python process." );
124147 }
148+
125149 }
126150 catch ( Exception e )
127151 {
@@ -174,7 +198,7 @@ private SpimImageProperties extractSettings( final List< SourceAndConverter< ? >
174198 }
175199
176200 private void detectAndAddSpots ( final List < SourceAndConverter < ? > > sources , final ModelGraph graph , final int setup ,
177- final int timepoint , final int level )
201+ final int timepoint , final int level , final Service python )
178202 {
179203 // First, get the source for the current channel (or setup) at the desired time-point. In BDV jargon, this is a source.
180204 final Source < ? > source = sources .get ( setup ).getSpimSource ();
@@ -212,7 +236,8 @@ private void detectAndAddSpots( final List< SourceAndConverter< ? > > sources, f
212236 }
213237
214238 final Img < ? > segmentation =
215- performSegmentation ( Views .dropSingletonDimensions ( image ), source .getVoxelDimensions ().dimensionsAsDoubleArray () );
239+ performSegmentation ( Views .dropSingletonDimensions ( image ), source .getVoxelDimensions ().dimensionsAsDoubleArray (),
240+ python );
216241
217242 if ( segmentation != null )
218243 {
@@ -301,20 +326,36 @@ public Map< String, Object > getDefaultSettings()
301326
302327 protected abstract boolean validateSettings ( final StringBuilder errorHolder );
303328
304- protected abstract Img < ? > performSegmentation ( final RandomAccessibleInterval < ? > image , final double [] voxelDimensions );
329+ protected abstract Img < ? > performSegmentation ( final RandomAccessibleInterval < ? > image , final double [] voxelDimensions ,
330+ final Service python );
305331
306332 protected abstract void addSpecificDefaultSettings ( final Map < String , Object > defaultSettings );
307333
308334 protected abstract String getDetectorName ();
309335
336+ protected abstract String getPythonEnvContent ();
337+
338+ protected String getPythonEnvInit ()
339+ {
340+ return "import numpy\n " ;
341+ }
342+
343+ protected abstract String getImportScript ( final boolean dataIs2D );
344+
345+ private static boolean isWindows ()
346+ {
347+ String os = System .getProperty ( "os.name" ).toLowerCase ();
348+ return os .contains ( "win" );
349+ }
350+
310351 /** Cancels the command execution, with the given reason for doing so. */
311352 @ Override
312353 public void cancel ( final String reason )
313354 {
314355 // this is a workaround to avoid a null pointer exception during the cancel operation
315356 detector = new DummyDetectorOp ();
316- if ( apposeProcess != null )
317- apposeProcess . cancel ();
357+ if ( pythonService != null )
358+ pythonService . kill ();
318359 super .cancel ( reason );
319360 }
320361
0 commit comments