-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add affine transform UnaryBlockOperator
- Loading branch information
Showing
6 changed files
with
1,246 additions
and
0 deletions.
There are no files selected for viewing
143 changes: 143 additions & 0 deletions
143
src/main/java/net/imglib2/algorithm/blocks/transform/AbstractTransformProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package net.imglib2.algorithm.blocks.transform; | ||
|
||
import java.util.Arrays; | ||
import java.util.function.Supplier; | ||
import net.imglib2.Interval; | ||
import net.imglib2.RealInterval; | ||
import net.imglib2.algorithm.blocks.BlockProcessor; | ||
import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval; | ||
import net.imglib2.blocks.TempArray; | ||
import net.imglib2.type.PrimitiveType; | ||
import net.imglib2.util.CloseableThreadLocal; | ||
import net.imglib2.util.Intervals; | ||
|
||
/** | ||
* Abstract base class for {@link Affine3DProcessor} and {@link | ||
* Affine2DProcessor}. Implements source/target interval computation, and {@code | ||
* TempArray} and thread-safe setup. | ||
* | ||
* @param <T> | ||
* recursive type of this {@code AbstractTransformProcessor} (for {@link #threadSafeSupplier}) | ||
* @param <P> | ||
* input/output primitive array type (i.e., float[] or double[]) | ||
*/ | ||
abstract class AbstractTransformProcessor< T extends AbstractTransformProcessor< T, P >, P > implements BlockProcessor< P, P > | ||
{ | ||
PrimitiveType primitiveType; | ||
|
||
Transform.Interpolation interpolation; | ||
|
||
final int n; | ||
|
||
final long[] destPos; | ||
|
||
final int[] destSize; | ||
|
||
final long[] sourcePos; | ||
|
||
final int[] sourceSize; | ||
|
||
private int sourceLength; | ||
|
||
private final BlockProcessorSourceInterval sourceInterval; | ||
|
||
private final TempArray< P > tempArray; | ||
|
||
Supplier< T > threadSafeSupplier; | ||
|
||
AbstractTransformProcessor( final int n, final Transform.Interpolation interpolation, final PrimitiveType primitiveType ) | ||
{ | ||
this.primitiveType = primitiveType; | ||
this.interpolation = interpolation; | ||
this.n = n; | ||
destPos = new long[ n ]; | ||
destSize = new int[ n ]; | ||
sourcePos = new long[ n ]; | ||
sourceSize = new int[ n ]; | ||
sourceInterval = new BlockProcessorSourceInterval( this ); | ||
tempArray = TempArray.forPrimitiveType( primitiveType ); | ||
} | ||
|
||
AbstractTransformProcessor( T transform ) | ||
{ | ||
// re-use | ||
primitiveType = transform.primitiveType; | ||
interpolation = transform.interpolation; | ||
n = transform.n; | ||
threadSafeSupplier = transform.threadSafeSupplier; | ||
|
||
// init empty | ||
destPos = new long[ n ]; | ||
destSize = new int[ n ]; | ||
sourcePos = new long[ n ]; | ||
sourceSize = new int[ n ]; | ||
|
||
// init new instance | ||
sourceInterval = new BlockProcessorSourceInterval( this ); | ||
tempArray = TempArray.forPrimitiveType( primitiveType ); | ||
} | ||
|
||
abstract T newInstance(); | ||
|
||
@Override | ||
public Supplier< T > threadSafeSupplier() | ||
{ | ||
if ( threadSafeSupplier == null ) | ||
threadSafeSupplier = CloseableThreadLocal.withInitial( this::newInstance )::get; | ||
return threadSafeSupplier; | ||
} | ||
|
||
abstract RealInterval estimateBounds( Interval interval ); | ||
|
||
@Override | ||
public void setTargetInterval( final Interval interval ) | ||
{ | ||
interval.min( destPos ); | ||
Arrays.setAll( destSize, d -> ( int ) interval.dimension( d ) ); | ||
|
||
final RealInterval bounds = estimateBounds( interval ); | ||
switch ( interpolation ) | ||
{ | ||
case NEARESTNEIGHBOR: | ||
Arrays.setAll( sourcePos, d -> Math.round( bounds.realMin( d ) - 0.5 ) ); | ||
Arrays.setAll( sourceSize, d -> ( int ) ( Math.round( bounds.realMax( d ) + 0.5 ) - sourcePos[ d ] ) + 1 ); | ||
break; | ||
case NLINEAR: | ||
Arrays.setAll( sourcePos, d -> ( long ) Math.floor( bounds.realMin( d ) - 0.5 ) ); | ||
Arrays.setAll( sourceSize, d -> ( int ) ( ( long ) Math.floor( bounds.realMax( d ) + 0.5 ) - sourcePos[ d ] ) + 2 ); | ||
break; | ||
} | ||
sourceLength = safeInt( Intervals.numElements( sourceSize ) ); | ||
} | ||
|
||
static int safeInt( final long value ) | ||
{ | ||
if ( value > Integer.MAX_VALUE ) | ||
throw new IllegalArgumentException( "value too large" ); | ||
return ( int ) value; | ||
} | ||
|
||
@Override | ||
public long[] getSourcePos() | ||
{ | ||
return sourcePos; | ||
} | ||
|
||
@Override | ||
public int[] getSourceSize() | ||
{ | ||
return sourceSize; | ||
} | ||
|
||
@Override | ||
public Interval getSourceInterval() | ||
{ | ||
return sourceInterval; | ||
} | ||
|
||
@Override | ||
public P getSourceBuffer() | ||
{ | ||
return tempArray.get( sourceLength ); | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
src/main/java/net/imglib2/algorithm/blocks/transform/Affine2DProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package net.imglib2.algorithm.blocks.transform; | ||
|
||
import net.imglib2.Interval; | ||
import net.imglib2.RealInterval; | ||
import net.imglib2.algorithm.blocks.BlockProcessor; | ||
import net.imglib2.realtransform.AffineTransform2D; | ||
import net.imglib2.type.PrimitiveType; | ||
|
||
/** | ||
* A {@link BlockProcessor} for interpolation and affine transform, using {@link | ||
* AffineTransform2D} and 2D source/target. | ||
* | ||
* @param <P> | ||
* input/output primitive array type (i.e., float[] or double[]) | ||
*/ | ||
class Affine2DProcessor< P > extends AbstractTransformProcessor< Affine2DProcessor< P >, P > | ||
{ | ||
private final AffineTransform2D transformToSource; | ||
|
||
private final TransformLine2D< P > transformLine; | ||
|
||
private final double pdest[] = new double[ 2 ]; | ||
|
||
private final double psrc[] = new double[ 2 ]; | ||
|
||
Affine2DProcessor( | ||
final AffineTransform2D transformToSource, | ||
final Transform.Interpolation interpolation, | ||
final PrimitiveType primitiveType ) | ||
{ | ||
this( transformToSource, interpolation, primitiveType, TransformLine2D.of( interpolation, primitiveType ) ); | ||
} | ||
|
||
private Affine2DProcessor( | ||
final AffineTransform2D transformToSource, | ||
final Transform.Interpolation interpolation, | ||
final PrimitiveType primitiveType, | ||
final TransformLine2D< P > transformLine ) | ||
{ | ||
super( 2, interpolation, primitiveType ); | ||
this.transformToSource = transformToSource; | ||
this.transformLine = transformLine; | ||
} | ||
|
||
private Affine2DProcessor( Affine2DProcessor< P > processor ) | ||
{ | ||
super( processor ); | ||
transformToSource = processor.transformToSource; | ||
transformLine = processor.transformLine; | ||
} | ||
|
||
@Override | ||
Affine2DProcessor newInstance() | ||
{ | ||
return new Affine2DProcessor( this ); | ||
} | ||
|
||
@Override | ||
RealInterval estimateBounds( final Interval interval ) | ||
{ | ||
return transformToSource.estimateBounds( interval ); | ||
} | ||
|
||
// specific to 3D | ||
@Override | ||
public void compute( final P src, final P dest ) | ||
{ | ||
final float d0 = transformToSource.d( 0 ).getFloatPosition( 0 ); | ||
final float d1 = transformToSource.d( 0 ).getFloatPosition( 1 ); | ||
final int ds0 = destSize[ 0 ]; | ||
final int ss0 = sourceSize[ 0 ]; | ||
pdest[ 0 ] = destPos[ 0 ]; | ||
int i = 0; | ||
for ( int y = 0; y < destSize[ 1 ]; ++y ) | ||
{ | ||
pdest[ 1 ] = y + destPos[ 1 ]; | ||
transformToSource.apply( pdest, psrc ); | ||
float sf0 = ( float ) ( psrc[ 0 ] - sourcePos[ 0 ] ); | ||
float sf1 = ( float ) ( psrc[ 1 ] - sourcePos[ 1 ] ); | ||
transformLine.apply( src, dest, i, ds0, d0, d1, ss0, sf0, sf1 ); | ||
i += ds0; | ||
} | ||
} | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
src/main/java/net/imglib2/algorithm/blocks/transform/Affine3DProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package net.imglib2.algorithm.blocks.transform; | ||
|
||
import net.imglib2.Interval; | ||
import net.imglib2.RealInterval; | ||
import net.imglib2.algorithm.blocks.BlockProcessor; | ||
import net.imglib2.realtransform.AffineTransform3D; | ||
import net.imglib2.type.PrimitiveType; | ||
|
||
/** | ||
* A {@link BlockProcessor} for interpolation and affine transform, using {@link | ||
* AffineTransform3D} and 3D source/target. | ||
* | ||
* @param <P> | ||
* input/output primitive array type (i.e., float[] or double[]) | ||
*/ | ||
class Affine3DProcessor< P > extends AbstractTransformProcessor< Affine3DProcessor< P >, P > | ||
{ | ||
private final AffineTransform3D transformToSource; | ||
|
||
private final TransformLine3D< P > transformLine; | ||
|
||
private final double pdest[] = new double[ 3 ]; | ||
|
||
private final double psrc[] = new double[ 3 ]; | ||
|
||
Affine3DProcessor( | ||
final AffineTransform3D transformToSource, | ||
final Transform.Interpolation interpolation, | ||
final PrimitiveType primitiveType ) | ||
{ | ||
this( transformToSource, interpolation, primitiveType, TransformLine3D.of( interpolation, primitiveType ) ); | ||
} | ||
|
||
private Affine3DProcessor( | ||
final AffineTransform3D transformToSource, | ||
final Transform.Interpolation interpolation, | ||
final PrimitiveType primitiveType, | ||
final TransformLine3D< P > transformLine ) | ||
{ | ||
super( 3, interpolation, primitiveType ); | ||
this.transformToSource = transformToSource; | ||
this.transformLine = transformLine; | ||
} | ||
|
||
private Affine3DProcessor( Affine3DProcessor< P > processor ) | ||
{ | ||
super( processor ); | ||
transformToSource = processor.transformToSource; | ||
transformLine = processor.transformLine; | ||
} | ||
|
||
@Override | ||
Affine3DProcessor newInstance() | ||
{ | ||
return new Affine3DProcessor( this ); | ||
} | ||
|
||
@Override | ||
RealInterval estimateBounds( final Interval interval ) | ||
{ | ||
return transformToSource.estimateBounds( interval ); | ||
} | ||
|
||
// specific to 3D | ||
@Override | ||
public void compute( final P src, final P dest ) | ||
{ | ||
final float d0 = transformToSource.d( 0 ).getFloatPosition( 0 ); | ||
final float d1 = transformToSource.d( 0 ).getFloatPosition( 1 ); | ||
final float d2 = transformToSource.d( 0 ).getFloatPosition( 2 ); | ||
final int ds0 = destSize[ 0 ]; | ||
final int ss0 = sourceSize[ 0 ]; | ||
final int ss1 = sourceSize[ 1 ] * ss0; | ||
pdest[ 0 ] = destPos[ 0 ]; | ||
int i = 0; | ||
for ( int z = 0; z < destSize[ 2 ]; ++z ) | ||
{ | ||
pdest[ 2 ] = z + destPos[ 2 ]; | ||
for ( int y = 0; y < destSize[ 1 ]; ++y ) | ||
{ | ||
pdest[ 1 ] = y + destPos[ 1 ]; | ||
transformToSource.apply( pdest, psrc ); | ||
float sf0 = ( float ) ( psrc[ 0 ] - sourcePos[ 0 ] ); | ||
float sf1 = ( float ) ( psrc[ 1 ] - sourcePos[ 1 ] ); | ||
float sf2 = ( float ) ( psrc[ 2 ] - sourcePos[ 2 ] ); | ||
transformLine.apply( src, dest, i, ds0, d0, d1, d2, ss0, ss1, sf0, sf1, sf2 ); | ||
i += ds0; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.