Skip to content

Commit e8c7e43

Browse files
committed
ImgMath: refactor to enable all views and computations to run on a computeType
that can differ from the outputType. When both are the same, avoids additional performance costs by removing the need for a Converter.
1 parent ed7cf27 commit e8c7e43

10 files changed

+358
-196
lines changed

src/main/java/net/imglib2/algorithm/math/Compute.java

Lines changed: 93 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,11 @@
77
import java.util.LinkedList;
88
import java.util.List;
99

10-
import net.imglib2.AbstractWrappedInterval;
11-
import net.imglib2.AbstractWrappedPositionableLocalizable;
1210
import net.imglib2.Cursor;
1311
import net.imglib2.Interval;
14-
import net.imglib2.Localizable;
15-
import net.imglib2.Positionable;
1612
import net.imglib2.RandomAccess;
13+
import net.imglib2.RandomAccessible;
1714
import net.imglib2.RandomAccessibleInterval;
18-
import net.imglib2.Sampler;
1915
import net.imglib2.algorithm.math.abstractions.IBinaryFunction;
2016
import net.imglib2.algorithm.math.abstractions.IFunction;
2117
import net.imglib2.algorithm.math.abstractions.ITrinaryFunction;
@@ -36,6 +32,7 @@
3632
import net.imglib2.img.array.ArrayImgFactory;
3733
import net.imglib2.loops.LoopBuilder;
3834
import net.imglib2.type.NativeType;
35+
import net.imglib2.type.numeric.IntegerType;
3936
import net.imglib2.type.numeric.RealType;
4037
import net.imglib2.view.Views;
4138

@@ -232,10 +229,16 @@ public < O extends RealType< O >, C extends RealType< C > > RandomAccessibleInte
232229
if ( null == inConverter )
233230
inConverter = Util.genericRealTypeConverter();
234231

235-
final boolean are_same_type = computingType.getClass() == target.randomAccess().get().createVariable().getClass();
232+
final O outputType = target.randomAccess().get().createVariable();
233+
final boolean are_same_type = computingType.getClass() == outputType.getClass();
236234

237235
if ( null == outConverter && !are_same_type )
238-
outConverter = ( Converter< C, O > )Util.genericRealTypeConverter();
236+
{
237+
if ( computingType instanceof IntegerType && outputType instanceof IntegerType )
238+
outConverter = ( Converter< C, O > )Util.genericIntegerTypeConverter();
239+
else
240+
outConverter = ( Converter< C, O > )Util.genericRealTypeConverter();
241+
}
239242

240243
// Recursive copy: initializes interval iterators and sets temporary computation holder
241244
final OFunction< C > f = this.operation.reInit(
@@ -294,128 +297,78 @@ public < O extends RealType< O >, C extends RealType< C > > RandomAccessibleInte
294297
return target;
295298
}
296299

297-
/**
298-
* View the result of the computations as a {@code RandomAccessibleInterval}, i.e. there is no target image,
299-
* instead any pixel can be viewed as the result of the computation applied to it, dynamically.
300-
*
301-
* Conversion between the input and computing type is done with a {@code Util#genericRealTypeConverter()},
302-
* as is the conversion from computing to output type.
303-
*
304-
* See also {@code ViewableFunction} and methods below related to {@code Compute#randomAccess()} and {@code Compute#cursor()}.
305-
* The key difference is that, here, the computing and the output type can be different.
306-
*
307-
* @param computingType The {@code Type} that defines the math to use.
308-
* @param outputType The @{code Type} of the constructed and returned {@code RandomAccessibleInterval}.
309-
*
310-
* return A {@code RandomAccessibleInterval} view of the result of the computations.
311-
*/
312300
public < O extends RealType< O >, C extends RealType< C > > RandomAccessibleInterval< O > view(
301+
final Interval interval,
302+
final Converter< ? extends RealType< ? >, C > inConverter,
313303
final C computingType,
314-
final O outputType)
304+
final O outputType,
305+
final Converter< C, O > outConverter )
315306
{
316-
return view( null, computingType, outputType, null);
307+
return Views.interval( new RandomAccessible< O >()
308+
{
309+
@Override
310+
public int numDimensions()
311+
{
312+
return interval.numDimensions();
313+
}
314+
315+
@Override
316+
public RandomAccess< O > randomAccess()
317+
{
318+
return Compute.this.randomAccess();
319+
}
320+
321+
@Override
322+
public RandomAccess< O > randomAccess( final Interval interval )
323+
{
324+
return Compute.this.randomAccess();
325+
}
326+
}, interval );
317327
}
318328

319329
/**
320330
* View the result of the computations as a {@code RandomAccessibleInterval}, i.e. there is no target image,
321331
* instead any pixel can be viewed as the result of the computation applied to it, dynamically.
322332
*
333+
* Conversion between the input and computing type is done with an appropriate converter or none when types are the same.
334+
*
323335
* See also {@code ViewableFunction} and methods below related to {@code Compute#randomAccess()} and {@code Compute#cursor()}.
324336
* The key difference is that, here, the computing and the output type can be different.
325337
*
326-
* @param inConverter_ To convert input images into the {@code computingType}. Can be null, defaults to a {@code Util#genericRealTypeConverter()}.
327338
* @param computingType The {@code Type} that defines the math to use.
328339
* @param outputType The @{code Type} of the constructed and returned {@code RandomAccessibleInterval}.
329-
* @param outConverter_ To convert from the {@code computingType} to the {@code outputType}. Can be null, defaults to a {@code Util#genericRealTypeConverter()}.
330340
*
331341
* return A {@code RandomAccessibleInterval} view of the result of the computations.
332342
*/
333-
@SuppressWarnings("unchecked")
334343
public < O extends RealType< O >, C extends RealType< C > > RandomAccessibleInterval< O > view(
335-
final Converter< RealType< ? >, C > inConverter_,
336344
final C computingType,
337-
final O outputType,
338-
final Converter< C, O > outConverter_)
345+
final O outputType )
339346
{
340-
final Converter< RealType< ? >, C > inConverter = null != inConverter_ ? inConverter_ : Util.genericRealTypeConverter();
341-
342-
final Converter< C, O > outConverter;
343-
if ( null == outConverter_ )
344-
{
345-
final boolean are_same_type = computingType.getClass() == outputType.getClass();
346-
if ( are_same_type )
347-
{
348-
outConverter = ( Converter< C, O > )new Converter< C, C >() {
349-
@Override
350-
public final void convert( final C comp, final C out) {
351-
out.set( comp );
352-
}
353-
};
354-
}
355-
else
356-
{
357-
outConverter = ( Converter< C, O > )Util.genericRealTypeConverter();
358-
}
359-
}
360-
else
361-
outConverter = outConverter_;
362-
363-
class RandomAccessCompute< PL extends Positionable & Localizable > extends AbstractWrappedPositionableLocalizable< PL > implements RandomAccess< O >
364-
{
365-
private final O result;
366-
private final OFunction< C > f;
367-
private final RandomAccessibleInterval< O > sourceInterval;
368-
369-
public RandomAccessCompute( final O outputType, final RandomAccessibleInterval< O > sourceInterval ) {
370-
super( ( PL )sourceInterval.randomAccess() );
371-
this.result = outputType.createVariable();
372-
this.sourceInterval = sourceInterval;
373-
// Recursive copy: initializes interval iterators and sets temporary computation holder
374-
this.f = Compute.this.operation.reInit(
375-
computingType,
376-
new HashMap< String, LetBinding< C > >(),
377-
inConverter, null );
378-
}
379-
380-
@Override
381-
public final O get() {
382-
outConverter.convert( f.eval( this ), result );
383-
return result;
384-
}
385-
386-
@Override
387-
public Sampler< O > copy() {
388-
return new RandomAccessCompute< PL >( this.result, this.sourceInterval );
389-
}
390-
391-
@Override
392-
public RandomAccess< O > copyRandomAccess() {
393-
return new RandomAccessCompute< PL >( this.result, this.sourceInterval );
394-
}
395-
}
396-
397-
class RandomAccessIntervalCompute extends AbstractWrappedInterval< RandomAccessibleInterval< O > > implements RandomAccessibleInterval< O >
398-
{
399-
public RandomAccessIntervalCompute()
400-
{
401-
super( ( RandomAccessibleInterval< O > )Views.zeroMin( Util.findImg( operation ).iterator().next() ) );
402-
}
403-
404-
@Override
405-
public RandomAccess< O > randomAccess()
406-
{
407-
return randomAccess( this.sourceInterval );
408-
}
409-
410-
@SuppressWarnings("rawtypes")
411-
@Override
412-
public RandomAccess< O > randomAccess( final Interval interval )
413-
{
414-
return new RandomAccessCompute( outputType.createVariable(), this.sourceInterval ); // Generic type inescrutable
415-
}
416-
}
417-
418-
return new RandomAccessIntervalCompute();
347+
return view( Util.findFirstInterval( this.operation ), null, computingType, outputType, null);
348+
}
349+
350+
public < O extends RealType< O > > RandomAccessibleInterval< O > view( final O outputType )
351+
{
352+
return view( outputType.createVariable(), outputType );
353+
}
354+
355+
public < O extends RealType< O > > RandomAccessibleInterval< O > view()
356+
{
357+
@SuppressWarnings("unchecked")
358+
final O outputType = ( ( O )Util.findFirstImg( this.operation ).randomAccess().get() ).createVariable();
359+
return view( outputType.createVariable(), outputType );
360+
}
361+
362+
public < O extends RealType< O > > RandomAccessibleInterval< O > view( final Interval interval )
363+
{
364+
@SuppressWarnings("unchecked")
365+
final O outputType = ( ( O )Util.findFirstImg( this.operation ).randomAccess().get() ).createVariable();
366+
return view( interval, null, outputType.createVariable(), outputType, null );
367+
}
368+
369+
public < O extends RealType< O > > RandomAccessibleInterval< O > view( final Interval interval, final O outputType )
370+
{
371+
return view( interval, null, outputType.createVariable(), outputType, null );
419372
}
420373

421374
/**
@@ -511,7 +464,7 @@ public RandomAccess< O > randomAccess( final Interval interval )
511464
final RandomAccessibleInterval< O > target
512465
)
513466
{
514-
final RandomAccessibleInterval< O > source = view( inConverter, computeType, outputType, outConverter );
467+
final RandomAccessibleInterval< O > source = view( Util.findFirstInterval( this.operation ), inConverter, computeType, outputType, outConverter );
515468
LoopBuilder.setImages( source, target ).forEachPixel( O::set );
516469
return target;
517470
}
@@ -584,7 +537,7 @@ else if ( op instanceof Var )
584537
else if ( op instanceof RandomAccessOnly )
585538
{
586539
if ( !p.must_run_as_RandomAccess )
587-
p.must_run_as_RandomAccess = ( ( RandomAccessOnly )op ).isRandomAccessOnly();
540+
p.must_run_as_RandomAccess = ( ( RandomAccessOnly< ? > )op ).isRandomAccessOnly();
588541
}
589542
}
590543

@@ -629,14 +582,26 @@ else if ( op instanceof RandomAccessOnly )
629582
return p;
630583
}
631584

632-
public < O extends RealType< O > > RandomAccess< O > randomAccess( final O outputType, final Converter< RealType< ? >, O > converter )
585+
public < C extends RealType< C >, O extends RealType< O > > RandomAccess< O > randomAccess(
586+
final Converter< RealType< ? >, C > inConverter,
587+
final C computeType,
588+
final O outputType,
589+
final Converter< C, O > outConverter )
590+
{
591+
return new FunctionRandomAccess< C, O >( this.operation, inConverter, computeType, outputType, outConverter );
592+
}
593+
594+
public < C extends RealType< C >, O extends RealType< O > > RandomAccess< O > randomAccess(
595+
final C computeType,
596+
final O outputType,
597+
final Converter< C, O > outConverter )
633598
{
634-
return new FunctionRandomAccess< O >( this.operation, outputType, converter );
599+
return randomAccess( null, computeType, outputType, outConverter );
635600
}
636601

637602
public < O extends RealType< O > > RandomAccess< O > randomAccess( final O outputType )
638603
{
639-
return new FunctionRandomAccess< O >( this.operation, outputType, Util.genericRealTypeConverter() );
604+
return randomAccess( outputType.createVariable(), outputType, null );
640605
}
641606

642607
/** Returns a {@link RandomAccess} with the same type as the first input image found. */
@@ -645,19 +610,28 @@ public < O extends RealType< O > > RandomAccess< O > randomAccess()
645610
@SuppressWarnings("unchecked")
646611
final RandomAccessibleInterval< O > img = ( RandomAccessibleInterval< O > )Util.findFirstImg( operation );
647612
final O outputType = img.randomAccess().get().createVariable();
648-
return new FunctionRandomAccess< O >( this.operation, outputType, Util.genericRealTypeConverter() );
613+
return randomAccess( outputType.createVariable(), outputType, null );
649614
}
650615

651-
public < O extends RealType< O > > Cursor< O > cursor( final O outputType, final Converter< RealType< ? >, O > converter )
616+
public < C extends RealType< C >, O extends RealType< O > > Cursor< O > cursor(
617+
final Converter< RealType< ? >, C > inConverter,
618+
final C computeType,
619+
final O outputType,
620+
final Converter< C, O > outConverter )
652621
{
653622
if ( this.params.compatible_iteration_order )
654-
return new FunctionCursor< O >( this.operation, outputType, converter );
655-
return new FunctionCursorIncompatibleOrder< O >( this.operation, outputType, converter );
623+
return new FunctionCursor< C, O >( this.operation, inConverter, computeType, outputType, outConverter );
624+
return new FunctionCursorIncompatibleOrder< C, O >( this.operation, inConverter, computeType, outputType, outConverter );
625+
}
626+
627+
public < C extends RealType< C >, O extends RealType< O > > Cursor< O > cursor( final C computeType, final O outputType )
628+
{
629+
return this.cursor( null, computeType, outputType, null );
656630
}
657631

658632
public < O extends RealType< O > > Cursor< O > cursor( final O outputType )
659633
{
660-
return this.cursor( outputType, Util.genericRealTypeConverter() );
634+
return this.cursor( null, outputType.createVariable(), outputType, null );
661635
}
662636

663637
/** Returns a {@link Cursor} with the same type as the first input image found. */
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package net.imglib2.algorithm.math.abstractions;
22

3-
public interface RandomAccessOnly
3+
import net.imglib2.RandomAccessible;
4+
5+
public interface RandomAccessOnly< I >
46
{
57
public default boolean isRandomAccessOnly()
68
{
79
return true;
810
}
11+
12+
public RandomAccessible< I > getRandomAccessible();
913
}

src/main/java/net/imglib2/algorithm/math/abstractions/ViewableFunction.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,24 @@
77

88
public abstract class ViewableFunction implements IFunction
99
{
10-
public < O extends RealType< O > > IterableRandomAccessibleFunction< O > view()
10+
public < C extends RealType< C >, O extends RealType< O > > IterableRandomAccessibleFunction< C, O > view()
1111
{
12-
return new IterableRandomAccessibleFunction< O >( this );
12+
return new IterableRandomAccessibleFunction< C, O >( this );
1313
}
1414

15-
public < O extends RealType< O > > IterableRandomAccessibleFunction< O > view( final O outputType )
15+
public < C extends RealType< C >, O extends RealType< O > > IterableRandomAccessibleFunction< C, O > view( final O outputType )
1616
{
17-
return new IterableRandomAccessibleFunction< O >( this, outputType );
17+
return new IterableRandomAccessibleFunction< C, O >( this, outputType );
1818
}
1919

20-
public < O extends RealType< O > > IterableRandomAccessibleFunction< O > view( final O outputType, final Converter< RealType< ? >, O > converter )
20+
public < C extends RealType< C >, O extends RealType< O > > IterableRandomAccessibleFunction< C, O > view( final C computeType, final O outputType )
2121
{
22-
return new IterableRandomAccessibleFunction< O >( this, outputType, converter );
22+
return new IterableRandomAccessibleFunction< C, O >( this, null, computeType, outputType, null );
23+
}
24+
25+
public < C extends RealType< C >, O extends RealType< O > > IterableRandomAccessibleFunction< C, O > view( final O outputType, final Converter< C, O > converter )
26+
{
27+
return new IterableRandomAccessibleFunction< C, O >( this, outputType, converter );
2328
}
2429

2530
public < O extends RealType< O > > IterableRandomAccessibleFunctionDouble< O > viewDouble()

0 commit comments

Comments
 (0)