3434
3535package net .imglib2 .algorithm .fill ;
3636
37+ import java .util .function .BiPredicate ;
38+ import java .util .function .Consumer ;
39+
3740import gnu .trove .list .TLongList ;
3841import gnu .trove .list .array .TLongArrayList ;
3942import net .imglib2 .Cursor ;
@@ -58,6 +61,182 @@ public class FloodFill
5861 // int or long? current TLongList cannot store more than Integer.MAX_VALUE
5962 private static final int CLEANUP_THRESHOLD = ( int ) 1e5 ;
6063
64+ /**
65+ * Iterative n-dimensional flood fill for arbitrary neighborhoods: Starting
66+ * at seed location, write fillLabel into target at current location and
67+ * continue for each pixel in neighborhood defined by shape if neighborhood
68+ * pixel is in the same connected component and fillLabel has not been
69+ * written into that location yet (comparator evaluates to 0).
70+ *
71+ * Convenience call to
72+ * {@link FloodFill#fill(RandomAccessible, RandomAccessible, Localizable, Object, Type, Shape, BiPredicate)}.
73+ * seedLabel is extracted from source at seed location.
74+ *
75+ * @param source
76+ * input
77+ * @param target
78+ * {@link RandomAccessible} to be written into. May be the same
79+ * as input.
80+ * @param seed
81+ * Start flood fill at this location.
82+ * @param fillLabel
83+ * Immutable. Value to be written into valid flood fill
84+ * locations.
85+ * @param shape
86+ * Defines neighborhood that is considered for connected
87+ * components, e.g.
88+ * {@link net.imglib2.algorithm.neighborhood.DiamondShape}
89+ * @param <T>
90+ * input pixel type
91+ * @param <U>
92+ * fill label type
93+ */
94+ public static < T extends Type < T >, U extends Type < U > > void fill (
95+ final RandomAccessible < T > source ,
96+ final RandomAccessible < U > target ,
97+ final Localizable seed ,
98+ final U fillLabel ,
99+ final Shape shape )
100+ {
101+ final RandomAccess < T > access = source .randomAccess ();
102+ access .setPosition ( seed );
103+ final T seedValue = access .get ().copy ();
104+ final BiPredicate < T , U > filter = ( t , u ) -> t .valueEquals ( seedValue ) && !u .valueEquals ( fillLabel );
105+ fill ( source , target , seed , fillLabel , shape , filter );
106+ }
107+
108+ /**
109+ * Iterative n-dimensional flood fill for arbitrary neighborhoods: Starting
110+ * at seed location, write fillLabel into target at current location and
111+ * continue for each pixel in neighborhood defined by shape if neighborhood
112+ * pixel is in the same connected component and fillLabel has not been
113+ * written into that location yet (comparator evaluates to 0).
114+ *
115+ * Convenience call to
116+ * {@link FloodFill#fill(RandomAccessible, RandomAccessible, Localizable, Object, Object, Shape, BiPredicate, Consumer)}
117+ * with {@link TypeWriter} as writer.
118+ *
119+ * @param source
120+ * input
121+ * @param target
122+ * {@link RandomAccessible} to be written into. May be the same
123+ * as input.
124+ * @param seed
125+ * Start flood fill at this location.
126+ * @param fillLabel
127+ * Immutable. Value to be written into valid flood fill
128+ * locations.
129+ * @param shape
130+ * Defines neighborhood that is considered for connected
131+ * components, e.g.
132+ * {@link net.imglib2.algorithm.neighborhood.DiamondShape}
133+ * @param filter
134+ * Returns true if pixel has not been visited yet and should be
135+ * written into. Returns false if target pixel has been visited
136+ * or source pixel is not part of the same connected component.
137+ * @param <T>
138+ * input pixel type
139+ * @param <U>
140+ * fill label type
141+ */
142+ public static < T , U extends Type < U > > void fill (
143+ final RandomAccessible < T > source ,
144+ final RandomAccessible < U > target ,
145+ final Localizable seed ,
146+ final U fillLabel ,
147+ final Shape shape ,
148+ final BiPredicate < T , U > filter )
149+ {
150+ fill ( source , target , seed , shape , filter , targetPixel -> targetPixel .set ( fillLabel ) );
151+ }
152+
153+ /**
154+ *
155+ * Iterative n-dimensional flood fill for arbitrary neighborhoods: Starting
156+ * at seed location, write fillLabel into target at current location and
157+ * continue for each pixel in neighborhood defined by shape if neighborhood
158+ * pixel is in the same connected component and fillLabel has not been
159+ * written into that location yet (comparator evaluates to 0).
160+ *
161+ * @param source
162+ * input
163+ * @param target
164+ * {@link RandomAccessible} to be written into. May be the same
165+ * as input.
166+ * @param seed
167+ * Start flood fill at this location.
168+ * @param shape
169+ * Defines neighborhood that is considered for connected
170+ * components, e.g.
171+ * {@link net.imglib2.algorithm.neighborhood.DiamondShape}
172+ * @param filter
173+ * Returns true if pixel has not been visited yet and should be
174+ * written into. Returns false if target pixel has been visited
175+ * or source pixel is not part of the same connected component.
176+ * @param writer
177+ * Defines how fill label is written into target at current
178+ * location.
179+ * @param <T>
180+ * input pixel type
181+ * @param <U>
182+ * fill label type
183+ */
184+ public static < T , U > void fill (
185+ final RandomAccessible < T > source ,
186+ final RandomAccessible < U > target ,
187+ final Localizable seed ,
188+ final Shape shape ,
189+ final BiPredicate < T , U > filter ,
190+ final Consumer < U > writer )
191+ {
192+ final int n = source .numDimensions ();
193+
194+ final RandomAccessible < Pair < T , U > > paired = Views .pair ( source , target );
195+
196+ TLongList coordinates = new TLongArrayList ();
197+ for ( int d = 0 ; d < n ; ++d )
198+ {
199+ coordinates .add ( seed .getLongPosition ( d ) );
200+ }
201+
202+ final int cleanupThreshold = n * CLEANUP_THRESHOLD ;
203+
204+ final RandomAccessible < Neighborhood < Pair < T , U > > > neighborhood = shape .neighborhoodsRandomAccessible ( paired );
205+ final RandomAccess < Neighborhood < Pair < T , U > > > neighborhoodAccess = neighborhood .randomAccess ();
206+
207+ final RandomAccess < U > targetAccess = target .randomAccess ();
208+ targetAccess .setPosition ( seed );
209+ writer .accept ( targetAccess .get () );
210+
211+ for ( int i = 0 ; i < coordinates .size (); i += n )
212+ {
213+ for ( int d = 0 ; d < n ; ++d )
214+ neighborhoodAccess .setPosition ( coordinates .get ( i + d ), d );
215+
216+ final Cursor < Pair < T , U > > neighborhoodCursor = neighborhoodAccess .get ().cursor ();
217+
218+ while ( neighborhoodCursor .hasNext () )
219+ {
220+ final Pair < T , U > p = neighborhoodCursor .next ();
221+ if ( filter .test ( p .getA (), p .getB () ) )
222+ {
223+ writer .accept ( p .getB () );
224+ for ( int d = 0 ; d < n ; ++d )
225+ coordinates .add ( neighborhoodCursor .getLongPosition ( d ) );
226+ }
227+ }
228+
229+ if ( i > cleanupThreshold )
230+ {
231+ // TODO should it start from i + n?
232+ coordinates = coordinates .subList ( i , coordinates .size () );
233+ i = 0 ;
234+ }
235+
236+ }
237+
238+ }
239+
61240 /**
62241 * Iterative n-dimensional flood fill for arbitrary neighborhoods: Starting
63242 * at seed location, write fillLabel into target at current location and
@@ -84,10 +263,11 @@ public class FloodFill
84263 * written into. Returns false if target pixel has been visited
85264 * or source pixel is not part of the same connected component.
86265 * @param <T>
87- * T implements {@code Type<U>}.
266+ * input pixel type
88267 * @param <U>
89- * U implements {@code Type<U>}.
268+ * fill label type
90269 */
270+ @ Deprecated
91271 public static < T extends Type < T >, U extends Type < U > > void fill ( final RandomAccessible < T > source , final RandomAccessible < U > target , final Localizable seed , final U fillLabel , final Shape shape , final Filter < Pair < T , U >, Pair < T , U > > filter )
92272 {
93273 final RandomAccess < T > access = source .randomAccess ();
@@ -123,10 +303,11 @@ public static < T extends Type< T >, U extends Type< U > > void fill( final Rand
123303 * written into. Returns false if target pixel has been visited
124304 * or source pixel is not part of the same connected component.
125305 * @param <T>
126- * No restrictions on {@link T}.
306+ * input pixel type
127307 * @param <U>
128- * {@link U} implements {@code Type<U>}.
308+ * fill label type
129309 */
310+ @ Deprecated
130311 public static < T , U extends Type < U > > void fill ( final RandomAccessible < T > source , final RandomAccessible < U > target , final Localizable seed , final T seedLabel , final U fillLabel , final Shape shape , final Filter < Pair < T , U >, Pair < T , U > > filter )
131312 {
132313 fill ( source , target , seed , seedLabel , fillLabel , shape , filter , new TypeWriter < U >() );
@@ -164,17 +345,16 @@ public static < T, U extends Type< U > > void fill( final RandomAccessible< T >
164345 * Defines how fillLabel is written into target at current
165346 * location.
166347 * @param <T>
167- * No restrictions on T. Appropriate comparator is the only
168- * requirement.
348+ * input pixel type
169349 * @param <U>
170- * No restrictions on U. Appropriate comparator and writer is the
171- * only requirement.
350+ * fill label type
172351 */
352+ @ Deprecated
173353 public static < T , U > void fill ( final RandomAccessible < T > source , final RandomAccessible < U > target , final Localizable seed , final T seedLabel , final U fillLabel , final Shape shape , final Filter < Pair < T , U >, Pair < T , U > > filter , final Writer < U > writer )
174354 {
175355 final int n = source .numDimensions ();
176356
177- final ValuePair < T , U > reference = new ValuePair < T , U >( seedLabel , fillLabel );
357+ final ValuePair < T , U > reference = new ValuePair <>( seedLabel , fillLabel );
178358
179359 final RandomAccessible < Pair < T , U > > paired = Views .pair ( source , target );
180360
0 commit comments