Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new imglib2 parallelization approach #83

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
630a8cb
Add utility class to simplify the creation of test images
maarzt Dec 6, 2022
31f054a
Add unit test for class Thresholder
maarzt Dec 6, 2022
6fdf423
Add unit test for class DifferenceOfGaussian
maarzt Dec 1, 2022
481bf0f
Refactor ConnectedComponentsTest and test more methods
maarzt Dec 2, 2022
f5ff37a
Add unit tests for Dilation and Erosion
maarzt Dec 2, 2022
bfaa8bd
Add unit test for class MorphologyUtils
maarzt Dec 2, 2022
6a4f3a2
Add unit test for class ComputeMinMax
maarzt Dec 6, 2022
3184e2f
POM: pin imglib2 version to 5.13.0
maarzt Nov 10, 2021
ac3b901
Change Thresholder implementation to multi-threaded LoopBuilder
maarzt Nov 10, 2021
8397118
Update DifferenceOfGaussian to use multi-threaded LoopBuilder and img…
maarzt Nov 10, 2021
7e28716
Update ConntectedComponenets to make use of the Parallelization context.
maarzt Nov 10, 2021
791c47f
Change TensorEigenValues to use multi-threaded LoopBuilder.
maarzt Nov 10, 2021
4873a47
Change Dilation to use IterableLoopBuilder
maarzt Dec 2, 2022
f294d06
Change Erosion to use IterableLoopBuilder
maarzt Dec 2, 2022
ddba38a
Update MorphologyUtils to use Parallelization framework
maarzt Dec 2, 2022
fe79678
Update DistanceTransform to use parallelization framework
maarzt Dec 2, 2022
3dd9ecd
Chang PartialDerivative to use multi-threaded LoopBuilder
maarzt Dec 2, 2022
23ea534
Update LocalExtrema to use parallelization framework
maarzt Dec 2, 2022
7fe1eaf
Change SubpixelLocalization to use the Parallelization framework
maarzt Dec 6, 2022
5c81783
Update ComputeMinMax to use parallelization framework
maarzt Dec 2, 2022
6d4f829
Add benchmark for LocalExtrema
maarzt Dec 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Change SubpixelLocalization to use the Parallelization framework
maarzt committed Dec 6, 2022
commit 7fe1eaf9cf41fa9ff047274033010496c7b39a3d
Original file line number Diff line number Diff line change
@@ -36,19 +36,19 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import net.imglib2.FinalInterval;
import net.imglib2.Interval;
import net.imglib2.Localizable;
import net.imglib2.Point;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessible;
import net.imglib2.RealPoint;
import net.imglib2.RealPositionable;
import net.imglib2.loops.IntervalChunks;
import net.imglib2.parallel.Parallelization;
import net.imglib2.parallel.TaskExecutor;
import net.imglib2.type.numeric.RealType;
import net.imglib2.util.Intervals;
import Jama.LUDecomposition;
@@ -59,7 +59,7 @@
* {@link #refinePeaks(List, RandomAccessible, Interval, boolean, int, boolean, float, boolean[], int)}
* method to do this, but this has a lot of parameters. Therefore, this class
* can also be instantiated to encapsulate the parameter settings.
*
*
* <p>
* A List {@link RefinedPeak} for the given list of {@link Localizable} is
* computed by, for each peak, fitting a quadratic function to the image and
@@ -68,7 +68,7 @@
* repeated at the corresponding integer coordinates. This is repeated to
* convergence, for a maximum number of iterations, or until the integer
* coordinates move out of the valid image.
*
*
* @author Stephan Preibisch
* @author Tobias Pietzsch
*/
@@ -93,8 +93,6 @@ public SubpixelLocalization( final int numDimensions )
// principally one can move in any dimension
allowedToMoveInDim = new boolean[ numDimensions ];
Arrays.fill( allowedToMoveInDim, true );

numThreads = Runtime.getRuntime().availableProcessors();
}

public void setAllowMaximaTolerance( final boolean allowMaximaTolerance )
@@ -164,14 +162,14 @@ public boolean getReturnInvalidPeaks()

public int getNumThreads()
{
return numThreads;
return numThreads == 0 ? Parallelization.getTaskExecutor().getParallelism() : numThreads;
}

/**
* Refine a set of peaks to subpixel coordinates. Calls
* {@link #refinePeaks(List, RandomAccessible, Interval, boolean, int, boolean, float, boolean[], int)}
* with the parameters set to this object.
*
*
* @param peaks
* List of integer peaks.
* @param img
@@ -184,7 +182,13 @@ public int getNumThreads()
*/
public ArrayList< RefinedPeak< P > > process( final List< P > peaks, final RandomAccessible< T > img, final Interval validInterval )
{
return refinePeaks( peaks, img, validInterval, returnInvalidPeaks, maxNumMoves, allowMaximaTolerance, maximaTolerance, allowedToMoveInDim, numThreads );
if ( numThreads != 0 )
return Parallelization.runWithNumThreads( numThreads,
() -> refinePeaks( peaks, img, validInterval, returnInvalidPeaks, maxNumMoves,
allowMaximaTolerance, maximaTolerance, allowedToMoveInDim ) );
else
return refinePeaks( peaks, img, validInterval, returnInvalidPeaks, maxNumMoves,
allowMaximaTolerance, maximaTolerance, allowedToMoveInDim );
}

/**
@@ -197,7 +201,7 @@ public ArrayList< RefinedPeak< P > > process( final List< P > peaks, final Rando
* fit is repeated at the corresponding integer coordinates. This is
* repeated to convergence, for a maximum number of iterations, or until the
* integer coordinates move out of the valid image.
*
*
* @param peaks
* List of integer peaks.
* @param img
@@ -231,45 +235,9 @@ public static < T extends RealType< T >, P extends Localizable > ArrayList< Refi
final int maxNumMoves, final boolean allowMaximaTolerance, final float maximaTolerance, final boolean[] allowedToMoveInDim,
final int numThreads )
{
final int numPeaks = peaks.size();
final ArrayList< RefinedPeak< P > > allRefinedPeaks = new ArrayList< RefinedPeak< P > >( numPeaks );

if ( numPeaks == 0 )
return allRefinedPeaks;

final int numTasks = numThreads <= 1 ? 1 : ( int ) Math.min( numPeaks, numThreads * 20 );
final int taskSize = numPeaks / numTasks;

final ExecutorService ex = Executors.newFixedThreadPool( numThreads );
final List< RefinedPeak< P > > synchronizedAllRefinedPeaks = Collections.synchronizedList( allRefinedPeaks );
for ( int taskNum = 0; taskNum < numTasks; ++taskNum )
{
final int fromIndex = taskNum * taskSize;
final int toIndex = ( taskNum == numTasks - 1 ) ? numPeaks : fromIndex + taskSize;
final Runnable r = new Runnable()
{
@Override
public void run()
{
final ArrayList< RefinedPeak< P > > refinedPeaks = refinePeaks(
peaks.subList( fromIndex, toIndex ),
img, validInterval, returnInvalidPeaks, maxNumMoves, allowMaximaTolerance, maximaTolerance, allowedToMoveInDim );
synchronizedAllRefinedPeaks.addAll( refinedPeaks );
}
};
ex.execute( r );
}
ex.shutdown();
try
{
ex.awaitTermination( 1000, TimeUnit.DAYS );
}
catch ( final InterruptedException e )
{
e.printStackTrace();
}

return allRefinedPeaks;
return Parallelization.runWithNumThreads( numThreads,
() -> refinePeaks( peaks, img, validInterval, returnInvalidPeaks, maxNumMoves, allowMaximaTolerance, maximaTolerance,
allowedToMoveInDim ) );
}

/**
@@ -282,7 +250,7 @@ public void run()
* fit is repeated at the corresponding integer coordinates. This is
* repeated to convergence, for a maximum number of iterations, or until the
* integer coordinates move out of the valid image.
*
*
* @param peaks
* List of integer peaks.
* @param img
@@ -313,7 +281,38 @@ public static < T extends RealType< T >, P extends Localizable > ArrayList< Refi
final List< P > peaks, final RandomAccessible< T > img, final Interval validInterval, final boolean returnInvalidPeaks,
final int maxNumMoves, final boolean allowMaximaTolerance, final float maximaTolerance, final boolean[] allowedToMoveInDim )
{
final ArrayList< RefinedPeak< P >> refinedPeaks = new ArrayList< RefinedPeak< P > >();
final int numPeaks = peaks.size();

if ( numPeaks == 0 )
return new ArrayList<>();

TaskExecutor taskExecutor = Parallelization.getTaskExecutor();

List< Interval > chunks = IntervalChunks.chunkInterval( new FinalInterval( numPeaks ), taskExecutor.suggestNumberOfTasks() );

List< ArrayList< RefinedPeak< P > > > result = taskExecutor.forEachApply( chunks, chunk ->
refinePeaksChunk(
peaks.subList( ( int ) chunk.min( 0 ), ( int ) chunk.max( 0 ) + 1 ),
img, validInterval, returnInvalidPeaks, maxNumMoves, allowMaximaTolerance,
maximaTolerance, allowedToMoveInDim )
);

return concatenate( result );
}

private static < P > ArrayList< P > concatenate( List< ? extends List< ? extends P > > lists )
{
int size = lists.stream().mapToInt( List::size ).sum();
ArrayList< P > result = new ArrayList<>( size );
lists.forEach( result::addAll );
return result;
}

public static < T extends RealType< T >, P extends Localizable > ArrayList< RefinedPeak< P > > refinePeaksChunk(
final List< P > peaks, final RandomAccessible< T > img, final Interval validInterval, final boolean returnInvalidPeaks,
final int maxNumMoves, final boolean allowMaximaTolerance, final float maximaTolerance, final boolean[] allowedToMoveInDim )
{
final ArrayList< RefinedPeak< P > > refinedPeaks = new ArrayList< RefinedPeak< P > >();

final int n = img.numDimensions();

@@ -420,7 +419,7 @@ else if ( returnInvalidPeaks )
/**
* Estimate subpixel {@code offset} of extremum of quadratic function
* fitted at {@code p}.
*
*
* @param p
* integer position at which to fit quadratic.
* @param access