Implement lazy binning in imglib2

imglib2

#1

@bogovicj @ASHISRAVINDRAN

We would like to implement a function:

binned = lazyBin( input, new int[]{3,3,3} );

The point would be that this should work lazy.

  • One way to do this should be using a CachedCellImg with an appropriate load method, which takes the relevant pixels of input in order to produce the binned output cell.

  • Alternatively, we were wondering if it is possible (and advisable) to somehow use Converters.convert( A, B )? For example, maybe A could be of type Neighborhood such that all values needed for computing the local average are available. The issue with this would be that the output image would have the same number of pixels as the input image, but I thought if one puts Views.subsample after the conversion it might work.

  • Another way that just occurred to us is using Views.interpolate combined with Views.subsample; maybe the easiest?


#2

Hi @Christian_Tischer,

Adding @tpietzsch, I’d trust his advice more than my own.

For CachedCellImg to work as you intend, it may need each cell to be the size of the window the function needs for computation, which is pretty small (maybe too small to be practical). Main advantage is that the results are cached.

Second options should work fine. Computation will indeed be lazy, but efficiency would be my main concern (are Neighborhoods fast?).

Your third option is probably how I would go about doing it.

John


#3

Thanks! I thought so, too. I guess this means to implement a BinningInterpolator ?!


#4

Yep.

Though could you explain what you mean by “Binning” here. (I’m just imagining you have some arbitrary function of a 3-cubed window.

I thought I may have a useful example to help you get started, but I don’t. What I had in mind was what is below which generates an image from points not images (it basically puts a gaussian blob around every point). I’ll link to it anyway just in case.


Forum search doesn't find code fragments?
#5

I was thinking of computing the average intensity in an NxNxN window, where N would be configurable.


#6

I don’t see how the third option would give you the average intensity over a window. Instead, I would probably go with option (1) with an appropriate CellLoader or CacheLoader. You could always invalidate the cache, whenever you change the window size. For an example (with a disk cache, which might not be necessary for you), checkout example 6 in the imglib2-cache-examples.


#7

@hanslovsky,

Interpolators generate a RealRandomAccessible from a “thing” usually a RandomAccessible. Does it help to think of an interpolator as a function from a RandomAccessible to a value : in general the intensity at a pixel is a function of the whole RandomAccessible?

That example in imglib2-cache-examples is great, btw. :+1:

John


#8

I’m not really following the technical details here. I just want to point out, that using CachedCellImg is not mutually exclusive with the other options. For example, if you implement a Converter over Neighborhoods or your BinningInterpolator, you can just put a CachedCellImg around the result. (This would help in the case where the lazy operations are slow)


#9

@Christian_Tischer I don’t understand what exactly you want to do. Is the output image of the same size as the input? Is binning another name for mean filter with square window?


#10

I discussed with @Christian_Tischer at the ImageJ Hackathon in Ostrava 2019. A “straight forward” solution for a lazy view could be constructed from the following layers

  1. a neighborhood view with a NxNxN window
  2. than a sub sampling view by NxNxN
  3. than a Converters.convert() to calculate mean for each neighborhood
  4. (optionally) CachedCellImg to cache the results

That are many layers. The performance might not be the best, but it’s easy to implement. Give it a try!


#11

Good day Matthias,

your question is a valid one and has consequences concerning the results. Thank you!

The rest of this post is addressed to those who are interested in the reduction of the spatial resolution of images.

Not knowing which exact aspect leads to the qualifier “lazy”, I should like to point out that if binning were used for the reduction of samples, the lazy (i.e. not a reasonable and in any case not an exact) bandwidth-reduction would require a running window of two times the linear size of the reduction factor.

For example, if an image is to be reduced to consist of only every second pixel, one must at least use a 4x4 running window.

If “lazy” means to just use a running window size that equals the linear reduction factor (i.e. 2x2 for the above example), then the resulting image willl show pronounced aliasing. (Aliasing may occur with the 4x4 window as well, but less pronounced.)

Regards

Herbie


#12

I assume @Christian_Tischer refers to the computer-science term of lazy evaluation, i.e the binned result is computed on demand only when it’s accessed, not for the whole image at once.


To my knowledge, binning is mostly used for the combination (by average or sum) of N*N pixels, to gain sensitivity at the cost of resolution (usually at acquisition time, directly at camera readout).

See also this post:

and the comment by @chalkie666 on @dnmason’s blog post.


#13

Thanks Jan,

I wasn’t aware of this meaning, “call-by-need” would be more instructive though.

Binning in a camera is a slightly different affair, because it delegates the problem of bandwidth limitation to the user (optical lowpass) not the coder.

Best

Herbie


#14

I implemented the Neighborhood and Converter based solution and it works :slight_smile:


#15

In case someone would like to use the code here is a re-usable version: