Skip to content

Commit ce8f984

Browse files
bogovicjaxtimwalde
andauthored
feat: bounding box estimation for RealTransformed RealIntervals (#37)
* feat: bounding box estimation for RealTransformed RealIntervals default implementation in RealTransform with extensible interface for sampling method override trivial cases in Translations, scales, and affine transformations --------- Co-authored-by: Stephan Saalfeld <[email protected]>
1 parent a62d90a commit ce8f984

File tree

14 files changed

+990
-34
lines changed

14 files changed

+990
-34
lines changed

src/main/java/net/imglib2/realtransform/AbstractAffineTransform.java

Lines changed: 17 additions & 9 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
@@ -34,17 +34,19 @@
3434

3535
package net.imglib2.realtransform;
3636

37+
import Jama.Matrix;
38+
import net.imglib2.RealInterval;
3739
import net.imglib2.RealLocalizable;
3840
import net.imglib2.RealPoint;
3941
import net.imglib2.RealPositionable;
40-
import Jama.Matrix;
42+
import net.imglib2.realtransform.interval.IntervalSamplingMethod;
4143

4244
/**
4345
* An abstract implementation of an affine transformation that returns default
4446
* values referring to the identity transformation for all fields. This
4547
* implementation is not thread safe. Create a {@link #copy()} for each
4648
* consumer.
47-
*
49+
*
4850
* @author Stephan Saalfeld
4951
*/
5052
public abstract class AbstractAffineTransform implements AffineGet, AffineSet
@@ -136,7 +138,7 @@ public int numTargetDimensions()
136138
{
137139
return n;
138140
}
139-
141+
140142
@Override
141143
public void apply( final double[] source, final double[] target )
142144
{
@@ -148,11 +150,11 @@ public void apply( final double[] source, final double[] target )
148150
for ( int c = 0; c < n; ++c )
149151
tmp[ r ] += source[ c ] * a.get( r, c );
150152
}
151-
153+
152154
for ( int r = 0; r < n; ++r )
153155
target[ r ] = tmp[ r ] + t[ r ];
154156
}
155-
157+
156158
@Override
157159
public void apply( final float[] source, final float[] target )
158160
{
@@ -164,7 +166,7 @@ public void apply( final float[] source, final float[] target )
164166
for ( int c = 0; c < n; ++c )
165167
tmp[ r ] += source[ c ] * a.get( r, c );
166168
}
167-
169+
168170
for ( int r = 0; r < n; ++r )
169171
target[ r ] = ( float )( tmp[ r ] + t[ r ] );
170172
}
@@ -180,7 +182,7 @@ public void apply( final RealLocalizable source, final RealPositionable target )
180182
for ( int c = 0; c < n; ++c )
181183
tmp[ r ] += source.getDoublePosition( c ) * a.get( r, c );
182184
}
183-
185+
184186
for ( int r = 0; r < n; ++r )
185187
target.setPosition( tmp[ r ] + t[ r ], r );
186188
}
@@ -215,4 +217,10 @@ public RealLocalizable d( final int d )
215217

216218
return ds[ d ];
217219
}
220+
221+
@Override
222+
public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod )
223+
{
224+
return AffineGet.super.boundingInterval( interval, IntervalSamplingMethod.CORNERS );
225+
}
218226
}

src/main/java/net/imglib2/realtransform/AbstractScale.java

Lines changed: 37 additions & 15 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
@@ -34,9 +34,12 @@
3434

3535
package net.imglib2.realtransform;
3636

37+
import net.imglib2.FinalRealInterval;
38+
import net.imglib2.RealInterval;
3739
import net.imglib2.RealLocalizable;
3840
import net.imglib2.RealPoint;
3941
import net.imglib2.RealPositionable;
42+
import net.imglib2.realtransform.interval.IntervalSamplingMethod;
4043

4144
/**
4245
* <em>n</em>-d arbitrary scaling. Abstract base implementation.
@@ -63,7 +66,7 @@ public AbstractScale( final double... s )
6366

6467
/**
6568
* Set the scale vector.
66-
*
69+
*
6770
* @param s
6871
* s.length &lt;= the number of dimensions of this
6972
* {@link AbstractScale}
@@ -74,7 +77,7 @@ public AbstractScale( final double... s )
7477
public void applyInverse( final double[] source, final double[] target )
7578
{
7679
assert source.length >= s.length && target.length >= s.length : "Input dimensions too small.";
77-
80+
7881
for ( int d = 0; d < s.length; ++d )
7982
source[ d ] = target[ d ] / s[ d ];
8083
}
@@ -83,17 +86,17 @@ public void applyInverse( final double[] source, final double[] target )
8386
public void applyInverse( final float[] source, final float[] target )
8487
{
8588
assert source.length >= s.length && target.length >= s.length : "Input dimensions too small.";
86-
89+
8790
for ( int d = 0; d < s.length; ++d )
8891
source[ d ] = ( float )( target[ d ] / s[ d ] );
89-
92+
9093
}
9194

9295
@Override
9396
public void applyInverse( final RealPositionable source, final RealLocalizable target )
9497
{
9598
assert source.numDimensions() >= s.length && target.numDimensions() >= s.length : "Input dimensions too small.";
96-
99+
97100
for ( int d = 0; d < s.length; ++d )
98101
source.setPosition( target.getDoublePosition( d ) / s[ d ], d );
99102
}
@@ -123,7 +126,7 @@ public int numTargetDimensions()
123126
public void apply( final double[] source, final double[] target )
124127
{
125128
assert source.length >= s.length && target.length >= s.length : "Input dimensions too small.";
126-
129+
127130
for ( int d = 0; d < s.length; ++d )
128131
target[ d ] = source[ d ] * s[ d ];
129132
}
@@ -132,7 +135,7 @@ public void apply( final double[] source, final double[] target )
132135
public void apply( final float[] source, final float[] target )
133136
{
134137
assert source.length >= s.length && target.length >= s.length : "Input dimensions too small.";
135-
138+
136139
for ( int d = 0; d < s.length; ++d )
137140
target[ d ] = ( float )( source[ d ] * s[ d ] );
138141
}
@@ -141,7 +144,7 @@ public void apply( final float[] source, final float[] target )
141144
public void apply( final RealLocalizable source, final RealPositionable target )
142145
{
143146
assert source.numDimensions() >= s.length && target.numDimensions() >= s.length : "Input dimensions too small.";
144-
147+
145148
for ( int d = 0; d < s.length; ++d )
146149
target.setPosition( source.getDoublePosition( d ) * s[ d ], d );
147150
}
@@ -150,7 +153,7 @@ public void apply( final RealLocalizable source, final RealPositionable target )
150153
public double get( final int row, final int column )
151154
{
152155
assert row >= 0 && row < numDimensions() : "Dimension index out of bounds.";
153-
156+
154157
return row == column ? s[ row ] : 0;
155158
}
156159

@@ -168,7 +171,7 @@ public double[] getRowPackedCopy()
168171
public RealLocalizable d( final int d )
169172
{
170173
assert d >= 0 && d < numDimensions() : "Dimension index out of bounds.";
171-
174+
172175
return ds[ d ];
173176
}
174177

@@ -186,14 +189,33 @@ public double[] getScaleCopy()
186189
{
187190
return s.clone();
188191
}
189-
192+
190193
@Override
191-
public double getTranslation( final int d ) {
194+
public double getTranslation( final int d )
195+
{
192196
return 0.0;
193197
}
194198

195199
@Override
196-
public double[] getTranslationCopy() {
200+
public double[] getTranslationCopy()
201+
{
197202
return new double[ s.length ];
198203
}
204+
205+
@Override
206+
public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod )
207+
{
208+
assert interval.numDimensions() >= s.length : "Interval does not have enough dimensions.";
209+
210+
final double[] min = interval.minAsDoubleArray();
211+
final double[] max = interval.maxAsDoubleArray();
212+
213+
for ( int d = 0; d < s.length; ++d )
214+
{
215+
min[ d ] *= s[ d ];
216+
max[ d ] *= s[ d ];
217+
}
218+
219+
return new FinalRealInterval( min, max, false );
220+
}
199221
}

src/main/java/net/imglib2/realtransform/AbstractTranslation.java

Lines changed: 26 additions & 6 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
@@ -34,13 +34,16 @@
3434

3535
package net.imglib2.realtransform;
3636

37+
import net.imglib2.FinalRealInterval;
38+
import net.imglib2.RealInterval;
3739
import net.imglib2.RealLocalizable;
3840
import net.imglib2.RealPoint;
3941
import net.imglib2.RealPositionable;
42+
import net.imglib2.realtransform.interval.IntervalSamplingMethod;
4043

4144
/**
4245
* <em>n</em>-d translation. Abstract base implementation.
43-
*
46+
*
4447
* @author Stephan Saalfeld
4548
*/
4649
abstract public class AbstractTranslation implements TranslationGet
@@ -77,7 +80,7 @@ public AbstractTranslation( final double... t )
7780

7881
/**
7982
* Set the translation vector.
80-
*
83+
*
8184
* @param t
8285
* t.length &lt;= the number of dimensions of this
8386
* {@link AbstractTranslation}
@@ -86,7 +89,7 @@ public AbstractTranslation( final double... t )
8689

8790
/**
8891
* Set one value of the translation vector.
89-
*
92+
*
9093
* @param t
9194
* t.length &lt;= the number of dimensions of this
9295
* {@link AbstractTranslation}
@@ -197,7 +200,7 @@ public RealLocalizable d( final int d )
197200

198201
return ds[ d ];
199202
}
200-
203+
201204
@Override
202205
public double getScale( final int d ) {
203206
return 0.0;
@@ -224,4 +227,21 @@ public double[] getTranslationCopy()
224227

225228
@Override
226229
abstract public AbstractTranslation inverse();
230+
231+
@Override
232+
public RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethdod )
233+
{
234+
assert interval.numDimensions() >= t.length : "Interval does not have enough dimensions.";
235+
236+
final double[] min = interval.minAsDoubleArray();
237+
final double[] max = interval.maxAsDoubleArray();
238+
239+
for ( int d = 0; d < t.length; ++d )
240+
{
241+
min[ d ] += t[ d ];
242+
max[ d ] += t[ d ];
243+
}
244+
245+
return new FinalRealInterval( min, max, false );
246+
}
227247
}

src/main/java/net/imglib2/realtransform/RealTransform.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434

3535
package net.imglib2.realtransform;
3636

37+
import net.imglib2.RealInterval;
3738
import net.imglib2.RealLocalizable;
3839
import net.imglib2.RealPoint;
3940
import net.imglib2.RealPositionable;
41+
import net.imglib2.realtransform.interval.IntervalSamplingMethod;
4042

4143
/**
4244
* Transformation from R<sup><em>n</em></sup> to R<sup><em>m</em></sup>.
@@ -257,4 +259,26 @@ default boolean isIdentity()
257259
{
258260
return false;
259261
}
262+
263+
/**
264+
* Estimate the {@link RealInterval} that bounds the given RealInterval
265+
* after being transformed by a {@link RealTransform}.
266+
* <p>
267+
* For arbitrary transformations, it is not necessarily possible to
268+
* directly calculate the resulting bounding box trivially, therefore,
269+
* a sampling methods for coordinates in the source interval must be
270+
* provided. {@link RealTransform}s that can calculate the bounding
271+
* interval more efficiently than by sampling coordinates are encouraged
272+
* to override this method and to ignore the provided sampling method.
273+
*
274+
* @param interval
275+
* the real interval
276+
* @param samplingMethod
277+
* the method used to sample coordinates of the source interval
278+
* @return the bounding interval
279+
*/
280+
default RealInterval boundingInterval( final RealInterval interval, final IntervalSamplingMethod samplingMethod )
281+
{
282+
return samplingMethod.bounds( interval, this );
283+
}
260284
}

0 commit comments

Comments
 (0)