Skip to content

Commit cf1c74b

Browse files
committed
Use new imglib2 parallelization approach
1 parent f20e472 commit cf1c74b

23 files changed

+853
-1435
lines changed

Diff for: pom.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.scijava</groupId>
77
<artifactId>pom-scijava</artifactId>
8-
<version>27.0.1</version>
8+
<version>28.0.0</version>
99
<relativePath />
1010
</parent>
1111

@@ -202,6 +202,7 @@ Jean-Yves Tinevez and Michael Zinsmaier.</license.copyrightOwners>
202202
<releaseProfiles>deploy-to-scijava</releaseProfiles>
203203

204204
<imglib2-roi.version>0.9.0</imglib2-roi.version>
205+
<imglib2.version>5.9.0</imglib2.version>
205206
</properties>
206207

207208
<repositories>

Diff for: src/main/java/net/imglib2/algorithm/binary/Thresholder.java

+34-94
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,12 @@
3333
*/
3434
package net.imglib2.algorithm.binary;
3535

36-
import java.util.Vector;
36+
import java.util.function.BiConsumer;
3737

38-
import net.imglib2.Cursor;
39-
import net.imglib2.RandomAccess;
40-
import net.imglib2.converter.Converter;
41-
import net.imglib2.exception.IncompatibleTypeException;
4238
import net.imglib2.img.Img;
4339
import net.imglib2.img.ImgFactory;
44-
import net.imglib2.multithreading.Chunk;
45-
import net.imglib2.multithreading.SimpleMultiThreading;
40+
import net.imglib2.loops.LoopBuilder;
41+
import net.imglib2.parallel.Parallelization;
4642
import net.imglib2.type.Type;
4743
import net.imglib2.type.logic.BitType;
4844

@@ -73,95 +69,39 @@ public class Thresholder
7369
*/
7470
public static final < T extends Type< T > & Comparable< T >> Img< BitType > threshold( final Img< T > source, final T threshold, final boolean above, final int numThreads )
7571
{
76-
final ImgFactory< T > factory = source.factory();
77-
try
78-
{
79-
final ImgFactory< BitType > bitFactory = factory.imgFactory( new BitType() );
80-
final Img< BitType > target = bitFactory.create( source );
81-
82-
final Converter< T, BitType > converter;
83-
if ( above )
84-
{
85-
converter = new Converter< T, BitType >()
86-
{
87-
@Override
88-
public void convert( final T input, final BitType output )
89-
{
90-
output.set( input.compareTo( threshold ) > 0 );
91-
}
92-
};
93-
}
94-
else
95-
{
96-
converter = new Converter< T, BitType >()
97-
{
98-
@Override
99-
public void convert( final T input, final BitType output )
100-
{
101-
output.set( input.compareTo( threshold ) < 0 );
102-
}
103-
};
104-
}
105-
106-
final Vector< Chunk > chunks = SimpleMultiThreading.divideIntoChunks( target.size(), numThreads );
107-
final Thread[] threads = SimpleMultiThreading.newThreads( numThreads );
72+
return Parallelization.runWithNumThreads( numThreads,
73+
() -> threshold( source, threshold, above ) );
74+
}
10875

109-
if ( target.iterationOrder().equals( source.iterationOrder() ) )
110-
{
111-
for ( int i = 0; i < threads.length; i++ )
112-
{
113-
final Chunk chunk = chunks.get( i );
114-
threads[ i ] = new Thread( "Thresholder thread " + i )
115-
{
116-
@Override
117-
public void run()
118-
{
119-
final Cursor< BitType > cursorTarget = target.cursor();
120-
cursorTarget.jumpFwd( chunk.getStartPosition() );
121-
final Cursor< T > cursorSource = source.cursor();
122-
cursorSource.jumpFwd( chunk.getStartPosition() );
123-
for ( long steps = 0; steps < chunk.getLoopSize(); steps++ )
124-
{
125-
cursorTarget.fwd();
126-
cursorSource.fwd();
127-
converter.convert( cursorSource.get(), cursorTarget.get() );
128-
}
129-
}
130-
};
131-
}
132-
}
133-
else
134-
{
135-
for ( int i = 0; i < threads.length; i++ )
136-
{
137-
final Chunk chunk = chunks.get( i );
138-
threads[ i ] = new Thread( "Thresholder thread " + i )
139-
{
140-
@Override
141-
public void run()
142-
{
143-
final Cursor< BitType > cursorTarget = target.cursor();
144-
cursorTarget.jumpFwd( chunk.getStartPosition() );
145-
final RandomAccess< T > ra = source.randomAccess( target );
146-
for ( long steps = 0; steps < chunk.getLoopSize(); steps++ )
147-
{
148-
cursorTarget.fwd();
149-
ra.setPosition( cursorTarget );
150-
converter.convert( ra.get(), cursorTarget.get() );
151-
}
152-
}
153-
};
154-
}
155-
}
76+
/**
77+
* Returns a new boolean {@link Img} generated by thresholding the values of
78+
* the source image.
79+
*
80+
* @param source
81+
* the image to threshold.
82+
* @param threshold
83+
* the threshold.
84+
* @param above
85+
* if {@code true}, the target value will be true for source
86+
* values above the threshold, {@code false} otherwise.
87+
* @return a new {@link Img} of type {@link BitType} and of same dimension
88+
* that the source image.
89+
*/
90+
public static < T extends Type< T > & Comparable< T > > Img< BitType > threshold( Img< T > source, T threshold, boolean above )
91+
{
92+
final ImgFactory< BitType > factory = source.factory().imgFactory( new BitType() );
93+
final Img< BitType > target = factory.create( source );
94+
final BiConsumer< T, BitType > converter = getThresholdConverter( threshold, above );
95+
LoopBuilder.setImages( source, target ).multiThreaded().forEachPixel( converter );
96+
return target;
97+
}
15698

157-
SimpleMultiThreading.startAndJoin( threads );
158-
return target;
159-
}
160-
catch ( final IncompatibleTypeException e )
161-
{
162-
e.printStackTrace();
163-
return null;
164-
}
99+
private static < T extends Type< T > & Comparable< T > > BiConsumer< T, BitType > getThresholdConverter( T threshold, boolean above )
100+
{
101+
if ( above )
102+
return ( input, output ) -> output.set( input.compareTo( threshold ) > 0 );
103+
else
104+
return ( input, output ) -> output.set( input.compareTo( threshold ) < 0 );
165105
}
166106

167107
}

Diff for: src/main/java/net/imglib2/algorithm/convolution/AbstractMultiThreadedConvolution.java

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*
1919
* @author Matthias Arzt
2020
*/
21+
@Deprecated
2122
public abstract class AbstractMultiThreadedConvolution< T > implements Convolution< T >
2223
{
2324

Diff for: src/main/java/net/imglib2/algorithm/convolution/Concatenation.java

-6
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@ class Concatenation< T > implements Convolution< T >
3131
this.steps = new ArrayList<>( steps );
3232
}
3333

34-
@Override
35-
public void setExecutor( final ExecutorService executor )
36-
{
37-
steps.forEach( step -> step.setExecutor( executor ) );
38-
}
39-
4034
@Override
4135
public Interval requiredSourceInterval( final Interval targetInterval )
4236
{

Diff for: src/main/java/net/imglib2/algorithm/convolution/Convolution.java

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public interface Convolution< T >
3434
/**
3535
* Set the {@link ExecutorService} to be used for convolution.
3636
*/
37+
@Deprecated
3738
default void setExecutor( final ExecutorService executor )
3839
{}
3940

Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
package net.imglib2.algorithm.convolution;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
5-
import java.util.concurrent.Callable;
6-
import java.util.concurrent.ExecutionException;
7-
import java.util.concurrent.ExecutorService;
8-
import java.util.concurrent.Future;
9-
import java.util.function.Consumer;
10-
import java.util.function.Supplier;
11-
123
import net.imglib2.FinalInterval;
134
import net.imglib2.Interval;
145
import net.imglib2.Localizable;
15-
import net.imglib2.Point;
166
import net.imglib2.RandomAccess;
177
import net.imglib2.RandomAccessible;
188
import net.imglib2.RandomAccessibleInterval;
19-
import net.imglib2.util.IntervalIndexer;
9+
import net.imglib2.loops.LoopBuilder;
2010
import net.imglib2.util.Intervals;
11+
import net.imglib2.util.Localizables;
2112
import net.imglib2.view.Views;
2213

2314
/**
@@ -26,7 +17,7 @@
2617
*
2718
* @author Matthias Arzt
2819
*/
29-
public class LineConvolution< T > extends AbstractMultiThreadedConvolution< T >
20+
public class LineConvolution< T > implements Convolution<T>
3021
{
3122
private final LineConvolverFactory< ? super T > factory;
3223

@@ -55,100 +46,33 @@ public T preferredSourceType( final T targetType )
5546
}
5647

5748
@Override
58-
protected void process( final RandomAccessible< ? extends T > source, final RandomAccessibleInterval< ? extends T > target, final ExecutorService executorService, final int numThreads )
49+
public void process( RandomAccessible< ? extends T > source, RandomAccessibleInterval< ? extends T > target )
5950
{
6051
final RandomAccessibleInterval< ? extends T > sourceInterval = Views.interval( source, requiredSourceInterval( target ) );
6152
final long[] sourceMin = Intervals.minAsLongArray( sourceInterval );
6253
final long[] targetMin = Intervals.minAsLongArray( target );
6354

64-
final Supplier< Consumer< Localizable > > actionFactory = () -> {
65-
66-
final RandomAccess< ? extends T > in = sourceInterval.randomAccess();
67-
final RandomAccess< ? extends T > out = target.randomAccess();
68-
final Runnable convolver = factory.getConvolver( in, out, direction, target.dimension( direction ) );
69-
70-
return position -> {
71-
in.setPosition( sourceMin );
72-
out.setPosition( targetMin );
73-
in.move( position );
74-
out.move( position );
75-
convolver.run();
76-
};
77-
};
78-
7955
final long[] dim = Intervals.dimensionsAsLongArray( target );
8056
dim[ direction ] = 1;
8157

82-
final int numTasks = numThreads > 1 ? timesFourAvoidOverflow(numThreads) : 1;
83-
LineConvolution.forEachIntervalElementInParallel( executorService, numTasks, new FinalInterval( dim ), actionFactory );
84-
}
58+
RandomAccessibleInterval< Localizable > positions = Localizables.randomAccessibleInterval( new FinalInterval( dim ) );
59+
LoopBuilder.setImages( positions ).multiThreaded().forEachChunk(
60+
chunk -> {
8561

86-
private int timesFourAvoidOverflow( int x )
87-
{
88-
return (int) Math.min((long) x * 4, Integer.MAX_VALUE);
89-
}
62+
final RandomAccess< ? extends T > in = sourceInterval.randomAccess();
63+
final RandomAccess< ? extends T > out = target.randomAccess();
64+
final Runnable convolver = factory.getConvolver( in, out, direction, target.dimension( direction ) );
9065

91-
/**
92-
* {@link #forEachIntervalElementInParallel(ExecutorService, int, Interval, Supplier)}
93-
* executes a given action for each position in a given interval. Therefor
94-
* it starts the specified number of tasks. Each tasks calls the action
95-
* factory once, to get an instance of the action that should be executed.
96-
* The action is then called multiple times by the task.
97-
*
98-
* @param service
99-
* {@link ExecutorService} used to create the tasks.
100-
* @param numTasks
101-
* number of tasks to use.
102-
* @param interval
103-
* interval to iterate over.
104-
* @param actionFactory
105-
* factory that returns the action to be executed.
106-
*/
107-
// TODO: move to a better place
108-
public static void forEachIntervalElementInParallel( final ExecutorService service, final int numTasks, final Interval interval,
109-
final Supplier< Consumer< Localizable > > actionFactory )
110-
{
111-
final long[] min = Intervals.minAsLongArray( interval );
112-
final long[] dim = Intervals.dimensionsAsLongArray( interval );
113-
final long size = Intervals.numElements( dim );
114-
final int boundedNumTasks = (int) Math.max( 1, Math.min(size, numTasks ));
115-
final long taskSize = ( size - 1 ) / boundedNumTasks + 1; // taskSize = roundUp(size / boundedNumTasks);
116-
final ArrayList< Callable< Void > > callables = new ArrayList<>();
66+
chunk.forEachPixel( position -> {
67+
in.setPosition( sourceMin );
68+
out.setPosition( targetMin );
69+
in.move( position );
70+
out.move( position );
71+
convolver.run();
72+
} );
11773

118-
for ( int taskNum = 0; taskNum < boundedNumTasks; ++taskNum )
119-
{
120-
final long myStartIndex = taskNum * taskSize;
121-
final long myEndIndex = Math.min( size, myStartIndex + taskSize );
122-
final Callable< Void > r = () -> {
123-
final Consumer< Localizable > action = actionFactory.get();
124-
final long[] position = new long[ dim.length ];
125-
final Localizable localizable = Point.wrap( position );
126-
for ( long index = myStartIndex; index < myEndIndex; ++index )
127-
{
128-
IntervalIndexer.indexToPositionWithOffset( index, dim, min, position );
129-
action.accept( localizable );
74+
return null;
13075
}
131-
return null;
132-
};
133-
callables.add( r );
134-
}
135-
execute( service, callables );
136-
}
137-
138-
private static void execute( final ExecutorService service, final ArrayList< Callable< Void > > callables )
139-
{
140-
try
141-
{
142-
final List< Future< Void > > futures = service.invokeAll( callables );
143-
for ( final Future< Void > future : futures )
144-
future.get();
145-
}
146-
catch ( final InterruptedException | ExecutionException e )
147-
{
148-
final Throwable cause = e.getCause();
149-
if ( cause instanceof RuntimeException )
150-
throw ( RuntimeException ) cause;
151-
throw new RuntimeException( e );
152-
}
76+
);
15377
}
15478
}

0 commit comments

Comments
 (0)