Skip to content

Commit 65abb18

Browse files
committed
KernelConvolverFactory: Use FloatType for all convolutions on RealType except DoubleType
This is required for higher precision when blurring for example ByteType images.
1 parent e48dd73 commit 65abb18

File tree

7 files changed

+60
-3
lines changed

7 files changed

+60
-3
lines changed

src/main/java/net/imglib2/algorithm/convolution/LineConvolution.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import net.imglib2.RandomAccess;
1717
import net.imglib2.RandomAccessible;
1818
import net.imglib2.RandomAccessibleInterval;
19+
import net.imglib2.type.Type;
20+
import net.imglib2.type.numeric.RealType;
21+
import net.imglib2.type.numeric.real.DoubleType;
22+
import net.imglib2.type.numeric.real.FloatType;
1923
import net.imglib2.util.IntervalIndexer;
2024
import net.imglib2.util.Intervals;
2125
import net.imglib2.view.Views;
@@ -51,7 +55,7 @@ public Interval requiredSourceInterval( final Interval targetInterval )
5155
@Override
5256
public T preferredSourceType( final T targetType )
5357
{
54-
return targetType;
58+
return (T) factory.preferredSourceType( targetType );
5559
}
5660

5761
@Override

src/main/java/net/imglib2/algorithm/convolution/LineConvolverFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.imglib2.algorithm.convolution;
22

33
import net.imglib2.RandomAccess;
4+
import net.imglib2.type.Type;
45

56
/**
67
* The interesting part of a separable convolution is how one line of the image
@@ -54,4 +55,6 @@ public interface LineConvolverFactory< T >
5455
* getBorderAfter())
5556
*/
5657
Runnable getConvolver( RandomAccess< ? extends T > in, RandomAccess< ? extends T > out, int d, long lineLength );
58+
59+
T preferredSourceType( T targetType );
5760
}

src/main/java/net/imglib2/algorithm/convolution/fast_gauss/FastGaussConvolverRealType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import net.imglib2.algorithm.convolution.LineConvolverFactory;
77
import net.imglib2.loops.ClassCopyProvider;
88
import net.imglib2.type.numeric.RealType;
9+
import net.imglib2.type.numeric.real.DoubleType;
10+
import net.imglib2.type.numeric.real.FloatType;
911

1012
/**
1113
* Implementation of {@link LineConvolverFactory} that uses
@@ -44,6 +46,12 @@ public Runnable getConvolver( final RandomAccess< ? extends RealType< ? > > in,
4446
return provider.newInstanceForKey( key, d, fc, in, out, lineLength );
4547
}
4648

49+
@Override
50+
public RealType< ? > preferredSourceType( RealType< ? > targetType )
51+
{
52+
return (targetType instanceof DoubleType) ? targetType : new FloatType();
53+
}
54+
4755
public static class MyConvolver implements Runnable
4856
{
4957
private final int d;

src/main/java/net/imglib2/algorithm/convolution/kernel/KernelConvolverFactory.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import net.imglib2.type.numeric.NumericType;
1212
import net.imglib2.type.numeric.RealType;
1313
import net.imglib2.type.numeric.real.DoubleType;
14+
import net.imglib2.type.numeric.real.FloatType;
1415

1516
/**
1617
* Used by {@link SeparableKernelConvolution} as {@link LineConvolverFactory}
@@ -56,6 +57,16 @@ public Runnable getConvolver( final RandomAccess< ? extends NumericType< ? > > i
5657
return provider.newInstanceForKey( key, kernel, in, out, d, lineLength );
5758
}
5859

60+
@Override
61+
public NumericType< ? > preferredSourceType( NumericType< ? > targetType )
62+
{
63+
if (targetType instanceof DoubleType)
64+
return targetType;
65+
if (targetType instanceof RealType)
66+
return new FloatType();
67+
return targetType;
68+
}
69+
5970
private ClassCopyProvider< Runnable > getProvider( final NumericType< ? > sourceType, final NumericType< ? > targetType )
6071
{
6172
for ( final Entry entry : factories )

src/main/java/net/imglib2/algorithm/convolution/kernel/SeparableKernelConvolution.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class SeparableKernelConvolution
3737
*
3838
* @see Convolution
3939
*/
40-
public static Convolution< NumericType< ? > > convolution( final Kernel1D[] kernels )
40+
public static Convolution< NumericType< ? > > convolution( final Kernel1D... kernels )
4141
{
4242
final List< Convolution< NumericType< ? > > > steps = IntStream.range( 0, kernels.length )
4343
.mapToObj( i -> convolution1d( kernels[ i ], i ) )

src/test/java/net/imglib2/algorithm/convolution/LineConvolutionTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,11 @@ static class ForwardDifferenceConvolverFactory implements LineConvolverFactory<
7171
}
7272
};
7373
}
74+
75+
@Override
76+
public UnsignedByteType preferredSourceType( UnsignedByteType targetType )
77+
{
78+
return new UnsignedByteType();
79+
}
7480
}
7581
}

src/test/java/net/imglib2/algorithm/convolution/kernel/SeparableKernelConvolutionTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import net.imglib2.Interval;
55
import net.imglib2.RandomAccessible;
66
import net.imglib2.RandomAccessibleInterval;
7-
import net.imglib2.exception.IncompatibleTypeException;
7+
import net.imglib2.algorithm.convolution.Convolution;
88
import net.imglib2.img.Img;
99
import net.imglib2.img.array.ArrayImgs;
1010
import net.imglib2.type.numeric.ARGBType;
11+
import net.imglib2.type.numeric.NumericType;
12+
import net.imglib2.type.numeric.integer.UnsignedByteType;
1113
import net.imglib2.type.numeric.real.DoubleType;
1214
import net.imglib2.type.numeric.real.FloatType;
1315
import net.imglib2.util.Intervals;
@@ -19,6 +21,7 @@
1921
import java.util.stream.IntStream;
2022
import java.util.stream.Stream;
2123

24+
import static org.junit.Assert.assertArrayEquals;
2225
import static org.junit.Assert.assertEquals;
2326
import static org.junit.Assert.assertTrue;
2427

@@ -122,4 +125,26 @@ private static void assertImagesEqual( RandomAccessibleInterval< DoubleType > ex
122125
Views.interval( Views.pair( expected, actual ), expected ).forEach( p -> assertEquals( p.getA().getRealDouble(), p.getB().getRealDouble(), delta ) );
123126
}
124127

128+
@Test
129+
public void testPrecisionOfTemporaryImages() {
130+
// NB: This test assures that for convolution on UnsignedByteType,
131+
// the pixel type to store intermediate results can store 0.1, hence
132+
// is FloatType or DoubleType.
133+
final byte[] inputPixels = { 1 };
134+
final byte[] outputPixels = new byte[ 1 ];
135+
final Kernel1D[] kernels = { Kernel1D.symmetric( 0.1 ), Kernel1D.symmetric( 10 ) };
136+
Img< UnsignedByteType > input = ArrayImgs.unsignedBytes( inputPixels, 1, 1 );
137+
Img< UnsignedByteType > output = ArrayImgs.unsignedBytes( outputPixels, 1, 1 );
138+
SeparableKernelConvolution.convolution( kernels ).process( input, output );
139+
assertArrayEquals( inputPixels, outputPixels );
140+
}
141+
142+
@Test
143+
public void testPreferredSourceType() {
144+
Convolution< NumericType< ? > > convolution = SeparableKernelConvolution.convolution( Kernel1D.symmetric( 1.0 ) );
145+
assertTrue( convolution.preferredSourceType( new UnsignedByteType() ) instanceof FloatType );
146+
assertTrue( convolution.preferredSourceType( new DoubleType() ) instanceof DoubleType );
147+
assertTrue( convolution.preferredSourceType( new FloatType() ) instanceof FloatType );
148+
assertTrue( convolution.preferredSourceType( new ARGBType() ) instanceof ARGBType );
149+
}
125150
}

0 commit comments

Comments
 (0)