# Examples of usage of imglib2-roi

#1

Hi all,

I am looking for real-world examples of usage of imglib2-roi. In particular, I have the following image processing task: a set of 3D `RealPoint` with a radius (same radius for all), and a 4D data set.

What I envision is the following:

``````img4D = ... # a 4-dimensional RandomAccessibleInterval
points = ... # list of 3-dimensional RealPoint
table = [[] for p in points] # list of lists: one list per point, each list as long as the time axis

for t in xrange(img4D.dimension(3)):
img3D = Views.hyperSlice(img4D, 3, t)
for i, point in enumerate(points):
# TODO: measure average pixel value at point + radius
average = ...
table[i].append(average)
``````

How would one accomplish this with imglib2-roi?

The trivial way would be using the reverse: build a KDTree with the points, and iterate over all pixels in `img3D` asking, with a radius neighbor search, for the nearest point, and summing pixel readings at each point and then dividing by the total to get the average. The disadvantage is that all pixels need to be iterated. Iâ€™d rather only iterate the pixels within radius distance of each `RealPoint` of interest.

Thanks for any suggestions.

#2

Iâ€™ve gotten as far as finding the class `ClosedWritableSphere`, and the static utility methods in `GeomMasks` to construct them. But how do I get the `Iterable` over all the positions that are inside the `ClosedWritableSphere`? Google says: nothing, no examples of usage of this anywhere.

The `IterableRandomAccessibleRegion` reads promising:

``````Make a boolean {@link RandomAccessibleInterval} iterable. The resulting
* {@link IterableInterval} contains all samples of the source interval that
* evaluate to {@code true}.
``````

â€¦ but canâ€™t find a way to relate it to the `ClosedWritableSphere` yet.

Looks like imglib2-roi is in dire need of more publicly discoverable examples. Are they somewhere and I just canâ€™t stumble upon them?

#3

Hi @tpietzsch, how does one get an integer mask, whose positions are iterable, from a `ClosedWritableSphere`? So that I can use to read the pixel values inside the sphere in a `RealRandomAccessible`?

#4

Itâ€™s surprising that none of the tests in imglib2-roi include any use of `RandomAccessibleRegionCursor`, which I gather is what Iâ€™d want, if only I knew how to get one for a `ClosedWritableSphere`.

#5

Was happy to have found a class that looks usable, like subclasses of `AbstractIterableRegionOfInterest`, but they are unfortunately labeled as `@Deprecated`. Bummer.

#6

Eureka: looks like `net.imglib2.roi.Masks` has static methods to wrap a `RealMaskRealInterval` like a `ClosedWritableSphere` into a `RealRandomAccessibleRealInterval`. The latter can be rasterized with `Views.raster` into a `RandomAccessibleInterval`, because a `RealRandomAccessibleRealInterval` is just a `RealRandomAccessible` that is defined within a `RealInterval`. Finally.

The `Masks` class should appear in github and in the javadoc as Masks, or similarly, perhaps all other classes of that package should go into a subpackage to highlight the top-level entry point that `Masks` is. At least now I found it. Onward to writing test code.

#7

By the way, Iâ€™d am thankful for `Masks.toRealMaskRealInterval` hiding the monster class `RealRandomAccessibleRealIntervalAsRealMaskRealInterval`. At least the name is self-documenting.

#8

On the rasterizing to get an iterable mask, surely there is an easier way than this?

``````sphere = GeomMasks.closedSphere(center, radius)
Views.interval(
Intervals.largestContainedInterval(sphere)))
``````

#9

Almost. Thereâ€™s `net.imglib2.roi.Regions`, in particular `Regions.iterable`, which will return an iterable over the `true` values of a given `RandomAccessibleInterval` of boolean type like a mask. Basically, it uses the very desirable `IterableRandomAccessibleRegion`.

Except, the `Masks.toRealRandomAccessible(sphere)` is a `RealRandomAccessible` and not a `RandomAccessibleInterval`, so conversions are still needed via `Views` or some other yet-to-be-discovered method.

#10

So this works, except the result is slightly different than ImageJâ€™s:

``````from net.imglib2.roi import Masks, Regions
from net.imglib2.img.display.imagej import ImageJFunctions as IL
from net.imglib2.view import Views
from net.imglib2.util import Intervals
from ij import IJ

# Open the embryos sample image, and turn it into 16-bit grayscale
imp = IJ.getImage()
IJ.run(imp, "16-bit", "")
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
print center

img = IL.wrap(imp)
sphere = GeomMasks.closedSphere(center, 61 / 2.0)
inside = Regions.iterable(
Views.interval(
Intervals.largestContainedInterval(sphere)))

pixels = []
ra = img.randomAccess()
cursor = inside.cursor() # only True pixels of the sphere mask

while cursor.hasNext():
cursor.fwd()
ra.setPosition(cursor)
pixels.append(ra.get().get())

print "Average:", sum(pixels) / float(len(pixels))

# prints: 68.91
# whereas ImageJ "measure" prints: 69.285 for the EllipseRoi
``````

#11

Turns out @imagejan had provided a similar solution for @Christian_Tischer : https://github.com/imagej/i2k-2018/blob/af72ef16984a8c16d965b5e1bec98613e90b9d01/ImageJ_Scripting.groovy#L194-L241

To the authors of imglib2-roi newest classes, including `Regions` and `Masks`: would you welcome a PR with this:

``````inside = Regions.iterable(
Views.interval(
Intervals.largestContainedInterval(sphere)))
``````

â€¦ packed into a convenient static method, e.g. something like `Regions.iterable(RealMask)`, and also parts of it into a `Masks.toRandomAccessibleInterval(RealMask)` ? Would ease the pain a lot.

#12

@albertcardona Did you see `Regions.sample()` ?
It binds an `IterableRegion` to a `RandomAccessible<T>`.
The result is an `IterableInterval<T>` that iterates the img pixels â€śunder the regionâ€ť.

So the above would not need the RandomAccess and could be something like this:

``````...
cursor = Regions.sample(inside,img).cursor()
while cursor.hasNext():
pixels.append(cursor.next().get())
...
``````

#13

Thanks @tpietzsch, but `Regions.sample(IterableInterval, RandomAccessible)` doesnâ€™t quite do itâ€“unless I am misunderstanding somethingâ€“because `ClosedWritableSphere` doesnâ€™t implement `IterableInterval`:

``````net.imglib2.roi.geom.real
Class ClosedWritableSphere
java.lang.Object
net.imglib2.AbstractEuclideanSpace
net.imglib2.roi.geom.real.AbstractWritableSphere
net.imglib2.roi.geom.real.ClosedWritableSphere
All Implemented Interfaces:
Predicate<RealLocalizable>, EuclideanSpace, RealInterval, Ellipsoid,
Sphere, SuperEllipsoid, WritableEllipsoid, WritableSphere,
``````

So I am not sure how I would use `Regions.sample`?

Also, where is the `IterableRegion`? Itâ€™s not an interface that `ClosedWritableSphere` implements. Did you mean `IterableInterval` (which it doesnâ€™t implement either)?

It is not helping here that `Region`'s methods have zero documentation: https://javadoc.scijava.org/ImgLib2/net/imglib2/roi/Regions.html#sample-net.imglib2.IterableInterval-net.imglib2.RandomAccessible-

#14

Wait: I finally got it. You mean, I can iterate directly the pixels of the target `RandomAccessibleInterval` using `Region.sample`, rather than having to use a `RandomAccess` and its `setPosition` from the `Cursor` over the `ClosedWritableSphere`.

Thanks! It does remove some noise:

``````from net.imglib2.roi import Masks, Regions
from net.imglib2.img.display.imagej import ImageJFunctions as IL
from net.imglib2.view import Views
from net.imglib2.util import Intervals
from ij import IJ

# Open the embryos sample image, and turn it into 16-bit grayscale
imp = IJ.getImage()
IJ.run(imp, "16-bit", "")
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
print center

img = IL.wrap(imp)
sphere = GeomMasks.closedSphere(center, 61 / 2.0)
inside = Regions.iterable(
Views.interval(
Intervals.largestContainedInterval(sphere)))

# Try with Region.sample
cursor = Regions.sample(inside, img).cursor()
pixels = []
while cursor.hasNext():
pixels.append(cursor.next().get())

print "Average:", sum(pixels) / float(len(pixels))
``````

Notice, though:
Still missing a way to simplify the generation of the `inside` from a `ClosedWritableSphere`, or any `RealMask`. A method in `Masks` would be most welcome. What would you call it? Happy to write it myself.

#15

Also: can I translate these spheres, of do I need to generate a sphere for every point in space I want to measure? What is the most efficient way, given that there are thousands of such points + radius, and the radius is identical for all?

#16

Also missing from `Masks` or `Regions`: statistics. Methods similar to `Regions.sample` (taking as arguments a `RealMask` and a `RandomAccessibleInterval`) that digest the pixel data inside the ROI. Like â€śmeanâ€ť, â€śsumâ€ť, â€śmaxâ€ť, â€śminâ€ť, â€śstdDevâ€ť, and another one named e.g. â€śstatisticsâ€ť that returns them all as a `Map`, so as to traverse the data only once.

If I add these, @tpietzsch, would you merge them?

#17

Yes, `Regions` is still work in progress. I have more stuff in this direction lying around for > two years now, that I work on a bit at hackathons every year. Documentation will come eventually

#18

I think these belong in algorithm, not here. And I would just make them take one `IterabelInterval<T>` parameter. I would prefer writing `Statistics.max(Regions.sample(region, img))` to `Statistics.max(region, img)`.

#19

`IterableRegion Masks.toIterableRegion(RealMaskRealInterval)`?
@awalter17 any ideas/preferences?

You can translate the spheres. They have `center()` which is `Localizable` and `Positionable`.
Iâ€™m not sure whether the updates carry through rasterization etc. To find out, I would have to try / dig through the code myselfâ€¦

#20

@albertcardona I agree, a method which converts/wraps a `RealMaskRealInterval` to an `IterableRegion` would be very helpful! Thank you for bringing this up, and volunteering to write it

Regarding the naming, Iâ€™m fine with `Masks.toIterableRegion`. But I could also see another method in `Regions` i.e. `IterableRegion Regions.iterable(RealMaskRealInterval)`. This is kind of nice because it keeps all the â€śiterableâ€ť methods together.