3636
3737import java .util .ArrayList ;
3838import java .util .Arrays ;
39- import java .util .Collections ;
4039import java .util .List ;
41- import java .util .concurrent .ExecutorService ;
42- import java .util .concurrent .Executors ;
43- import java .util .concurrent .TimeUnit ;
4440
41+ import net .imglib2 .FinalInterval ;
4542import net .imglib2 .Interval ;
4643import net .imglib2 .Localizable ;
4744import net .imglib2 .Point ;
4845import net .imglib2 .RandomAccess ;
4946import net .imglib2 .RandomAccessible ;
5047import net .imglib2 .RealPoint ;
5148import net .imglib2 .RealPositionable ;
49+ import net .imglib2 .loops .IntervalChunks ;
50+ import net .imglib2 .parallel .Parallelization ;
51+ import net .imglib2 .parallel .TaskExecutor ;
5252import net .imglib2 .type .numeric .RealType ;
5353import net .imglib2 .util .Intervals ;
5454import Jama .LUDecomposition ;
5959 * {@link #refinePeaks(List, RandomAccessible, Interval, boolean, int, boolean, float, boolean[], int)}
6060 * method to do this, but this has a lot of parameters. Therefore, this class
6161 * can also be instantiated to encapsulate the parameter settings.
62- *
62+ *
6363 * <p>
6464 * A List {@link RefinedPeak} for the given list of {@link Localizable} is
6565 * computed by, for each peak, fitting a quadratic function to the image and
6868 * repeated at the corresponding integer coordinates. This is repeated to
6969 * convergence, for a maximum number of iterations, or until the integer
7070 * coordinates move out of the valid image.
71- *
71+ *
7272 * @author Stephan Preibisch
7373 * @author Tobias Pietzsch
7474 */
@@ -93,8 +93,6 @@ public SubpixelLocalization( final int numDimensions )
9393 // principally one can move in any dimension
9494 allowedToMoveInDim = new boolean [ numDimensions ];
9595 Arrays .fill ( allowedToMoveInDim , true );
96-
97- numThreads = Runtime .getRuntime ().availableProcessors ();
9896 }
9997
10098 public void setAllowMaximaTolerance ( final boolean allowMaximaTolerance )
@@ -164,14 +162,14 @@ public boolean getReturnInvalidPeaks()
164162
165163 public int getNumThreads ()
166164 {
167- return numThreads ;
165+ return numThreads == 0 ? Parallelization . getTaskExecutor (). getParallelism () : numThreads ;
168166 }
169167
170168 /**
171169 * Refine a set of peaks to subpixel coordinates. Calls
172170 * {@link #refinePeaks(List, RandomAccessible, Interval, boolean, int, boolean, float, boolean[], int)}
173171 * with the parameters set to this object.
174- *
172+ *
175173 * @param peaks
176174 * List of integer peaks.
177175 * @param img
@@ -184,7 +182,13 @@ public int getNumThreads()
184182 */
185183 public ArrayList < RefinedPeak < P > > process ( final List < P > peaks , final RandomAccessible < T > img , final Interval validInterval )
186184 {
187- return refinePeaks ( peaks , img , validInterval , returnInvalidPeaks , maxNumMoves , allowMaximaTolerance , maximaTolerance , allowedToMoveInDim , numThreads );
185+ if ( numThreads != 0 )
186+ return Parallelization .runWithNumThreads ( numThreads ,
187+ () -> refinePeaks ( peaks , img , validInterval , returnInvalidPeaks , maxNumMoves ,
188+ allowMaximaTolerance , maximaTolerance , allowedToMoveInDim ) );
189+ else
190+ return refinePeaks ( peaks , img , validInterval , returnInvalidPeaks , maxNumMoves ,
191+ allowMaximaTolerance , maximaTolerance , allowedToMoveInDim );
188192 }
189193
190194 /**
@@ -197,7 +201,7 @@ public ArrayList< RefinedPeak< P > > process( final List< P > peaks, final Rando
197201 * fit is repeated at the corresponding integer coordinates. This is
198202 * repeated to convergence, for a maximum number of iterations, or until the
199203 * integer coordinates move out of the valid image.
200- *
204+ *
201205 * @param peaks
202206 * List of integer peaks.
203207 * @param img
@@ -231,45 +235,9 @@ public static < T extends RealType< T >, P extends Localizable > ArrayList< Refi
231235 final int maxNumMoves , final boolean allowMaximaTolerance , final float maximaTolerance , final boolean [] allowedToMoveInDim ,
232236 final int numThreads )
233237 {
234- final int numPeaks = peaks .size ();
235- final ArrayList < RefinedPeak < P > > allRefinedPeaks = new ArrayList < RefinedPeak < P > >( numPeaks );
236-
237- if ( numPeaks == 0 )
238- return allRefinedPeaks ;
239-
240- final int numTasks = numThreads <= 1 ? 1 : ( int ) Math .min ( numPeaks , numThreads * 20 );
241- final int taskSize = numPeaks / numTasks ;
242-
243- final ExecutorService ex = Executors .newFixedThreadPool ( numThreads );
244- final List < RefinedPeak < P > > synchronizedAllRefinedPeaks = Collections .synchronizedList ( allRefinedPeaks );
245- for ( int taskNum = 0 ; taskNum < numTasks ; ++taskNum )
246- {
247- final int fromIndex = taskNum * taskSize ;
248- final int toIndex = ( taskNum == numTasks - 1 ) ? numPeaks : fromIndex + taskSize ;
249- final Runnable r = new Runnable ()
250- {
251- @ Override
252- public void run ()
253- {
254- final ArrayList < RefinedPeak < P > > refinedPeaks = refinePeaks (
255- peaks .subList ( fromIndex , toIndex ),
256- img , validInterval , returnInvalidPeaks , maxNumMoves , allowMaximaTolerance , maximaTolerance , allowedToMoveInDim );
257- synchronizedAllRefinedPeaks .addAll ( refinedPeaks );
258- }
259- };
260- ex .execute ( r );
261- }
262- ex .shutdown ();
263- try
264- {
265- ex .awaitTermination ( 1000 , TimeUnit .DAYS );
266- }
267- catch ( final InterruptedException e )
268- {
269- e .printStackTrace ();
270- }
271-
272- return allRefinedPeaks ;
238+ return Parallelization .runWithNumThreads ( numThreads ,
239+ () -> refinePeaks ( peaks , img , validInterval , returnInvalidPeaks , maxNumMoves , allowMaximaTolerance , maximaTolerance ,
240+ allowedToMoveInDim ) );
273241 }
274242
275243 /**
@@ -282,7 +250,7 @@ public void run()
282250 * fit is repeated at the corresponding integer coordinates. This is
283251 * repeated to convergence, for a maximum number of iterations, or until the
284252 * integer coordinates move out of the valid image.
285- *
253+ *
286254 * @param peaks
287255 * List of integer peaks.
288256 * @param img
@@ -313,7 +281,38 @@ public static < T extends RealType< T >, P extends Localizable > ArrayList< Refi
313281 final List < P > peaks , final RandomAccessible < T > img , final Interval validInterval , final boolean returnInvalidPeaks ,
314282 final int maxNumMoves , final boolean allowMaximaTolerance , final float maximaTolerance , final boolean [] allowedToMoveInDim )
315283 {
316- final ArrayList < RefinedPeak < P >> refinedPeaks = new ArrayList < RefinedPeak < P > >();
284+ final int numPeaks = peaks .size ();
285+
286+ if ( numPeaks == 0 )
287+ return new ArrayList <>();
288+
289+ TaskExecutor taskExecutor = Parallelization .getTaskExecutor ();
290+
291+ List < Interval > chunks = IntervalChunks .chunkInterval ( new FinalInterval ( numPeaks ), taskExecutor .suggestNumberOfTasks () );
292+
293+ List < ArrayList < RefinedPeak < P > > > result = taskExecutor .forEachApply ( chunks , chunk ->
294+ refinePeaksChunk (
295+ peaks .subList ( ( int ) chunk .min ( 0 ), ( int ) chunk .max ( 0 ) + 1 ),
296+ img , validInterval , returnInvalidPeaks , maxNumMoves , allowMaximaTolerance ,
297+ maximaTolerance , allowedToMoveInDim )
298+ );
299+
300+ return concatenate ( result );
301+ }
302+
303+ private static < P > ArrayList < P > concatenate ( List < ? extends List < ? extends P > > lists )
304+ {
305+ int size = lists .stream ().mapToInt ( List ::size ).sum ();
306+ ArrayList < P > result = new ArrayList <>( size );
307+ lists .forEach ( result ::addAll );
308+ return result ;
309+ }
310+
311+ public static < T extends RealType < T >, P extends Localizable > ArrayList < RefinedPeak < P > > refinePeaksChunk (
312+ final List < P > peaks , final RandomAccessible < T > img , final Interval validInterval , final boolean returnInvalidPeaks ,
313+ final int maxNumMoves , final boolean allowMaximaTolerance , final float maximaTolerance , final boolean [] allowedToMoveInDim )
314+ {
315+ final ArrayList < RefinedPeak < P > > refinedPeaks = new ArrayList < RefinedPeak < P > >();
317316
318317 final int n = img .numDimensions ();
319318
@@ -420,7 +419,7 @@ else if ( returnInvalidPeaks )
420419 /**
421420 * Estimate subpixel {@code offset} of extremum of quadratic function
422421 * fitted at {@code p}.
423- *
422+ *
424423 * @param p
425424 * integer position at which to fit quadratic.
426425 * @param access
0 commit comments