Skip to content

Commit a1dd545

Browse files
committed
Transform: add operator factories, refactor, javadoc
1 parent dca339c commit a1dd545

File tree

3 files changed

+59
-29
lines changed

3 files changed

+59
-29
lines changed

src/main/java/net/imglib2/algorithm/blocks/transform/Transform.java

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
* %%
1212
* Redistribution and use in source and binary forms, with or without
1313
* modification, are permitted provided that the following conditions are met:
14-
*
14+
*
1515
* 1. Redistributions of source code must retain the above copyright notice,
1616
* this list of conditions and the following disclaimer.
1717
* 2. Redistributions in binary form must reproduce the above copyright notice,
1818
* this list of conditions and the following disclaimer in the documentation
1919
* and/or other materials provided with the distribution.
20-
*
20+
*
2121
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2222
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2323
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -33,6 +33,7 @@
3333
*/
3434
package net.imglib2.algorithm.blocks.transform;
3535

36+
import net.imglib2.algorithm.blocks.BlockSupplier;
3637
import net.imglib2.algorithm.blocks.DefaultUnaryBlockOperator;
3738
import net.imglib2.algorithm.blocks.UnaryBlockOperator;
3839
import net.imglib2.algorithm.blocks.ClampType;
@@ -46,6 +47,8 @@
4647

4748
import static net.imglib2.type.PrimitiveType.FLOAT;
4849

50+
import java.util.function.Function;
51+
4952
/**
5053
* Affine transform in 2D/3D with n-linear or nearest-neighbor interpolation.
5154
*/
@@ -69,26 +72,58 @@ public enum Interpolation
6972
}
7073

7174
/**
72-
* Create a {@code UnaryBlockOperator} to interpolate and affine-transform
73-
* blocks of the standard ImgLib2 {@code RealType}s.
75+
* Interpolate and affine-transform blocks of the standard ImgLib2 {@code
76+
* RealType}s.
7477
* <p>
7578
* Only 2D and 3D are supported currently!
79+
* <p>
80+
* The returned factory function creates an operator matching the type a
81+
* given input {@code BlockSupplier<T>}.
7682
*
77-
* @param type
78-
* instance of the input type
7983
* @param transformFromSource
8084
* a 2D or 3D affine transform
8185
* @param interpolation
8286
* which interpolation method to use
8387
* @param <T>
8488
* the input/output type
8589
*
86-
* @return {@code UnaryBlockOperator} to affine-transform blocks of type {@code T}
90+
* @return factory for {@code UnaryBlockOperator} to affine-transform blocks of type {@code T}
91+
*/
92+
public static < T extends NativeType< T > >
93+
Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > affine( final AffineGet transformFromSource, Interpolation interpolation )
94+
{
95+
return affine( transformFromSource, interpolation, ComputationType.AUTO );
96+
}
97+
98+
/**
99+
* Interpolate and affine-transform blocks of the standard ImgLib2 {@code
100+
* RealType}s.
101+
* <p>
102+
* Only 2D and 3D are supported currently!
103+
* <p>
104+
* The returned factory function creates an operator matching the type a
105+
* given input {@code BlockSupplier<T>}.
106+
*
107+
* @param transformFromSource
108+
* a 2D or 3D affine transform
109+
* @param interpolation
110+
* which interpolation method to use
111+
* @param computationType
112+
* For n-linear interpolation, this specifies in which precision
113+
* intermediate values should be computed. For {@code AUTO}, the type
114+
* that can represent the input/output type without loss of precision
115+
* is picked. That is, {@code FLOAT} for u8, i8, u16, i16, i32, f32,
116+
* and otherwise {@code DOUBLE} for u32, i64, f64. For nearest-neighbor
117+
* interpolation, {@code computationType} is not used.
118+
* @param <T>
119+
* the input/output type
120+
*
121+
* @return factory for {@code UnaryBlockOperator} to affine-transform blocks of type {@code T}
87122
*/
88123
public static < T extends NativeType< T > >
89-
UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSource, Interpolation interpolation )
124+
Function< BlockSupplier< T >, UnaryBlockOperator< T, T > > affine( final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType )
90125
{
91-
return affine( type, transformFromSource, interpolation, ComputationType.AUTO );
126+
return s -> createAffineOperator( s.getType(), transformFromSource, interpolation, computationType, ClampType.CLAMP );
92127
}
93128

94129
/**
@@ -116,7 +151,7 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo
116151
* @return {@code UnaryBlockOperator} to affine-transform blocks of type {@code T}
117152
*/
118153
public static < T extends NativeType< T > >
119-
UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType )
154+
UnaryBlockOperator< T, T > createAffineOperator( final T type, final AffineGet transformFromSource, Interpolation interpolation, final ComputationType computationType, final ClampType clampType )
120155
{
121156
final int n = transformFromSource.numDimensions();
122157
if ( n < 2 || n > 3 ) {
@@ -145,7 +180,7 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo
145180
final UnaryBlockOperator< ?, ? > op = processAsFloat
146181
? _affine( transformToSource, interpolation, new FloatType() )
147182
: _affine( transformToSource, interpolation, new DoubleType() );
148-
return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, ClampType.CLAMP );
183+
return op.adaptSourceType( type, ClampType.NONE ).adaptTargetType( type, clampType );
149184
}
150185
else // if ( interpolation == Interpolation.NEARESTNEIGHBOR )
151186
{
@@ -156,8 +191,6 @@ UnaryBlockOperator< T, T > affine( final T type, final AffineGet transformFromSo
156191
private static < T extends NativeType< T > > UnaryBlockOperator< T, T > _affine( final AffineGet transform, final Interpolation interpolation, final T type )
157192
{
158193
final int n = transform.numDimensions();
159-
if ( n < 2 || n > 3 )
160-
throw new IllegalArgumentException( "Only 2D and 3D affine transforms are supported currently" );
161194
return new DefaultUnaryBlockOperator<>( type, type, n, n,
162195
n == 2
163196
? new Affine2DProcessor<>( ( AffineTransform2D ) transform, interpolation, type.getNativeTypeFactory().getPrimitiveType() )

src/test/java/net/imglib2/algorithm/blocks/transform/TransformBenchmark3D.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import net.imglib2.RandomAccessibleInterval;
4444
import net.imglib2.RealRandomAccessible;
4545
import net.imglib2.algorithm.blocks.BlockProcessor;
46+
import net.imglib2.algorithm.blocks.ClampType;
47+
import net.imglib2.algorithm.blocks.transform.Transform.ComputationType;
4648
import net.imglib2.algorithm.blocks.transform.Transform.Interpolation;
4749
import net.imglib2.blocks.PrimitiveBlocks;
4850
import net.imglib2.converter.Converters;
@@ -151,15 +153,18 @@ public void blocksnaiveSetup()
151153
Views.extendZero( img ),
152154
new RealFloatConverter<>(),
153155
new FloatType() ) );
154-
processor = Transform.affine( new FloatType(), affine, Interpolation.NLINEAR ).blockProcessor();
156+
final FloatType type2 = new FloatType();
157+
processor = Transform.createAffineOperator( type2, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor();
155158
blocksDouble = PrimitiveBlocks.of(
156159
Converters.convert(
157160
Views.extendZero( img ),
158161
new RealDoubleConverter<>(),
159162
new DoubleType() ) );
160-
processorDouble = Transform.affine( new DoubleType(), affine, Interpolation.NLINEAR ).blockProcessor();
163+
final DoubleType type1 = new DoubleType();
164+
processorDouble = Transform.createAffineOperator( type1, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor();
161165
blocksUnsignedByte = PrimitiveBlocks.of( Views.extendZero( img ) );
162-
processorUnsignedByte = Transform.affine( new UnsignedByteType(), affine, Interpolation.NLINEAR ).blockProcessor();
166+
final UnsignedByteType type = new UnsignedByteType();
167+
processorUnsignedByte = Transform.createAffineOperator( type, affine, Interpolation.NLINEAR, ComputationType.AUTO, ClampType.CLAMP ).blockProcessor();
163168
blocksFloat();
164169
blocksDouble();
165170
blocksUnsignedByte();

src/test/java/net/imglib2/algorithm/blocks/transform/TransformPlayground3D.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,11 @@
4040
import ij.ImagePlus;
4141
import java.util.Arrays;
4242
import net.imglib2.Cursor;
43-
import net.imglib2.FinalInterval;
4443
import net.imglib2.RandomAccessible;
4544
import net.imglib2.RandomAccessibleInterval;
4645
import net.imglib2.RealRandomAccessible;
47-
import net.imglib2.algorithm.blocks.BlockProcessor;
46+
import net.imglib2.algorithm.blocks.BlockSupplier;
4847
import net.imglib2.algorithm.blocks.transform.Transform.Interpolation;
49-
import net.imglib2.blocks.PrimitiveBlocks;
5048
import net.imglib2.img.Img;
5149
import net.imglib2.img.array.ArrayImg;
5250
import net.imglib2.img.array.ArrayImgFactory;
@@ -105,19 +103,13 @@ public static void main( String[] args )
105103
final int[] size = { 64, 64, 64 };
106104
final RandomAccessibleInterval< UnsignedByteType > copy = copy( transformed, new UnsignedByteType(), min, size );
107105

108-
109-
final PrimitiveBlocks< UnsignedByteType > blocks = PrimitiveBlocks.of( Views.extendZero( img ) );
110-
BlockProcessor< byte[], byte[] > processor = Transform.affine( new UnsignedByteType(), affine, Interpolation.NLINEAR ).blockProcessor();
111-
long[] max = new long[ size.length ];
112-
Arrays.setAll( max, d -> min[ d ] + size[ d ] - 1 );
113-
processor.setTargetInterval( FinalInterval.wrap( min, max ) );
114-
blocks.copy( processor.getSourcePos(), processor.getSourceBuffer(), processor.getSourceSize() );
106+
final BlockSupplier< UnsignedByteType > blocks = BlockSupplier
107+
.of( Views.extendZero( img ) )
108+
.andThen( Transform.affine( affine, Interpolation.NLINEAR ) );
115109
final byte[] dest = new byte[ ( int ) Intervals.numElements( size ) ];
116-
processor.compute( processor.getSourceBuffer(), dest );
110+
blocks.copy( min, dest, size );
117111
final RandomAccessibleInterval< UnsignedByteType > destImg = ArrayImgs.unsignedBytes( dest, size[ 0 ], size[ 1 ], size[ 2 ] );
118112

119-
120-
121113
// ----------------------------------------------
122114

123115
final BdvSource bdv2 = BdvFunctions.show(

0 commit comments

Comments
 (0)