Examples of usage of imglib2-roi

Thanks very much! Looking forward to it. So far, I am glad that I was nonetheless capable to waddle through the code and get good usage out of it.

A quick test would tell us this: nope, it seems that I need a new Regions.iterable over the Views.raster, etc. for each location.

In the work I mentioned above, I’m almost done with cleaning up Regions.positionable(), which would let you take the result of Views.raster, and make it into a PositionableIterableRegion which can be moved around. If this would be helpful, I can bump the priority of that and get it done this week for sure.
However, this is moving the rasterized sphere on the integer grid. Not sure if that is enough.

It would be of course nice to be able to not bake in anything in the Regions.iterable() (optionally, for efficiency reasons…), and be able to re-position the sphere and have the rasterization adapt. I need to think more about that.


Hi @tpietzsch,
thanks very much for your work and for letting me know about what you have in store for imgli2-roi.
At the moment, I was able to measure ~250,000 spheres (597 at each of 400 time points) in less than 5 minutes with a 7-year-old computer (including lots of I/O time, which likely dominates) over a ~100 GB 4D volume stored as GZIP in N5. This was done with 597 distinct sphere instances, each independently rasterized and wrapped. So the performance is not bad, but of course I don’t know how much better it could be.

In the near future we are going to be doing hundreds of these measurements, so indeed an efficient imglib2-roi would be a boon to us, but like I said, what exists now is already good enough (for each data set, computation time is dominated by I/O and image registration across time).

Would be very happy though to test out Regions.positionable().



6 posts were split to a new topic: Contains interface of imglib2-roi is gone

Following the conversation, @awalter17 @tpietzsch, here is a PR https://github.com/imglib/imglib2-roi/pull/48 with two methods that simplify lots the usage of ROIs in imglib2-roi:

Masks.toIterableInterval( RealMaskRealInterval ) returning an IterableRegion.

Regions.sample( RealMaskRealInterval, RandomAccessible ) returning an IterableInterval over the samples of the RandomAccessible that fall within the true parts of the mask.

1 Like

I revive this thread, because I wrote an approximate translation of your script to groovy, in case somebody’s interested:

import net.imglib2.roi.Masks
import net.imglib2.roi.Regions
import net.imglib2.roi.geom.GeomMasks
import net.imglib2.img.display.imagej.ImageJFunctions //IL
import net.imglib2.view.Views
import net.imglib2.util.Intervals
import ij.IJ

// Get the image, and turns it into 16-bit grayscale
#@ImagePlus(label="Image") imp

IJ.run(imp, "Specify...", "width=61 height=61 x=1037 y=83 oval")
circle = imp.getRoi()
bounds = circle.getBounds()

center = [bounds.x + bounds.width / 2.0, bounds.y + bounds.height / 2.0, 6] as double[]

println("center = "+center)

img = ImageJFunctions.wrap(imp)
sphere = GeomMasks.closedSphere(center, 6.0)
inside = Regions.iterable(

// with Region.sample
cursor = Regions.sample(inside, img).cursor()

long sum=0
long nPixels=0

while (cursor.hasNext()) {

println("nPixels = "+nPixels)
println("AvgValue = "+(double)((double)sum/(double)nPixels))

Also I saw a merged PR related to this thread (https://github.com/imglib/imglib2-roi/pull/48). Should the script be different now ?

Hi @NicoKiaru,

In short, this mouthful:

inside = Regions.iterable(

… now becomes:

inside = Masks.toIterableRegion(sphere)

That’s all.


Nice! However it’s not working yet for me. Has the PR reached FIJI yet ?

Possibly not. Before, it was merged with a different method name. Try using Masks.toIterableInterval instead of Masks.toIterableRegion for the time being.


1 Like

Hmm still failing. I’ll keep the long version for now.

This means @tpietzsch or @ctrueden haven’t yet cut a release of imglib2-roi with the new changes.

I released imglib2-roi-0.8.1, but the method has been renamed to Masks.toIterableRegion because that reflects more accurately what it does.

1 Like

Here’s the repo of a roi-course by @maarzt.

1 Like

I’m playing around with this and have a question. I am iterating over the pixels of a polygon and the number of pixels does not match my expectations. Here is my example:

ImageJ ij = new ImageJ();

//create image, set all pixels to one
ArrayImg<BitType, ?> image2d = new ArrayImgFactory<>(new BitType()).create(3, 3);
image2d.forEach(pixel -> pixel.setOne());

//get contour
Polygon2D poly = ij.op().geom().contour( image2d, false );

System.out.println("Contour: ");
for (RealLocalizable vertex : poly.vertices()) {

System.out.println("\nPixels of iterable region: ");

Cursor<BitType> cursor = Regions.sample(Masks.toIterableRegion(poly), image2d).localizingCursor();
while(cursor.hasNext()) {

This is the output:


Pixels of iterable region: 
[0, 0]
[1, 0]
[0, 1]
[1, 1]

I somehow would have expected that the contour is either part of the region or not part of the region, but it’s partly part of the region. Is that just the convention? Is it documented somewhere? Or is something wrong with my code?

EDIT since the contour coming from ops sits on the border pixels belonging to the foreground, the contour pixels should be part of the region, no?


To put things into context, I link to some related discussions here:

I fully agree that we should try to make the behavior of the contour op consistent with the imglib2-roi behavior. :slightly_smiling_face:


Did you check the ROI’s boundary type?


If you need a polygon excluding the boundary, use GeomMasks.openPolygon2D. If you need one including the boundary, use GeomMasks.closedPolygon2D. If you don’t care, use GeomMasks.polygon2D, which has the mixed boundary behavior you observed (because it has convenient mathematical properties I think—@awalter17 correct me if I’m wrong).

Be aware of the following from the open and closed 2D polygon implementations:

This implementation of a polygon does not support creating a single polygon object which is actually multiple polygons. It does support self-intersecting polygons with even-odd winding.

The DefaultContour implementation in ImageJ Ops currently uses the unspecified boundary type of Polygon2D:

@awalter17 It looks like you updated ImageJ Ops to use the new imglib2-roi with this commit:

Did you choose the unspecified boundary polygon on purpose? Or would a different one be better? What do you think?

1 Like


You are correct! The Polygon2D implementation with unspecified boundary behavior is also more efficient then the open or closed implementations.

The unspecified boundary behavior was intentional. When I updated imagej-ops to use the new ROIs, I wanted to preserve the functionality of any Ops using the “old” ROIs. And the contour(...) Op was previously using the “old” imglib2-roi Polygon, which had unspecified boundary behavior.

I would leave the current DefaultContour implementation as is, since the resulting Polygon2D is the most efficient implementation. But I would modify the Java doc to state that the resulting polygon has unspecified boundary behavior.

And then I think it would be good to have a second *Contour Op which accepts either a BoundaryType or an instance of WritablePolygon2D (though we’d probably want to add a setVertices(...) method to WritablePolygon2D if we went this route). That way users have the option of specifying the boundary behavior.




@awalter17 Thanks for your reply!

The new SciJava Ops has the power to make any computer op into a function op automatically, as long as a factory is available for constructing new objects of the given type. We can leverage this in the new versions of the geom2d ops to make all those ops computers only, with the Polygon2D factory producing a DefaultWritablePolygon2D.

@gselzer Here are the ops currently hardcoding construction of Polygon2D objects:

git grep 'new DefaultWritablePolygon'
src/main/java/net/imagej/ops/geom/geom2d/DefaultBoundingBox.java:               return new DefaultWritablePolygon2D(bounds);
src/main/java/net/imagej/ops/geom/geom2d/DefaultContour.java:           return new DefaultWritablePolygon2D(p);
src/main/java/net/imagej/ops/geom/geom2d/DefaultConvexHull2D.java:              return new DefaultWritablePolygon2D(L);
src/main/java/net/imagej/ops/geom/geom2d/DefaultSmallestEnclosingRectangle.java:                return new DefaultWritablePolygon2D(out);
src/test/java/net/imagej/ops/features/AbstractFeatureTest.java:         return new DefaultWritablePolygon2D(vertices);

Please change those all to computers typed on WritablePolygon2D.

We can look at the efficiency of calling addVertex repeatedly to build up polygons. If it’s bad, then I agree that adding a mass vertex insertion method makes sense.

1 Like

I really appreciate the ongoing discussion and would like to add a question for the usage of net.imglib2.roi. How to do an operation similar to IJ1 /Edit/Clear Outside with a LabelRegion?

My initial approach was to use Views.interval(image, region). However this does not exactly what I want. I would like to blank all pixels outside the region. In fact even keep the size of the original image.

Second option would be to use a cursor an go through all points that do not belong to region and set them to 0. This seems not very elegant and what is the best way to do a NOT operation with a region?