imglib / imglib2-algorithm

Image processing algorithms for ImgLib2
http://imglib2.net/
Other
22 stars 20 forks source link

ImgMath: math operations can now be viewed without having to copy the result into an image #76

Closed acardona closed 5 years ago

acardona commented 5 years ago

The first two commits are cosmetic changes that can be ignored.

The second commit updates the IFunction interface with 3 new methods, all called view. These methods return an IterableRandomAccessibleFunction, which is both an IterableInterval and a RandomAccessible, and also a View given that its data should be cached when planning to do multiple accesses on the same positions. When iterating its data with IterableRandomAccessibleFunction.cursor() or IterableRandomAccessibleFunction.randomAccess(), the computation described by the IFunction is done on the fly, returning the result as the numeric content of the RealType outputType. Underlying the cursor and randomAccess methods are the corresponding methods in the Compute class, which does the validation of operations and included images.

The 3 new view methods of IFunction are:

  1. view(), returning a View (an IterableRandomAccessibleFunction) of the same Type as the first RandomAccessibleInterval found wrapped in the IFunction and its nested IFunction instances, if any.
  2. view(RealType outputType), like above but specifies the RealType to use for the computations, as well as for the return value RealType. An implict generic Converter uses RealType.setReal(RealType.getRealDouble()) for the conversion from input to output.
  3. view(RealType outputType, Converter converter), where a explicit Converter mediates the transformation from any RealType subclass in the input "images" (RandomAccessibleInterval) wrapped in the IFunction.

In other words, the view methods enable code such as:

from net.imglib2.algorithm.math.ImgMath import add
from net.imglib2.view import Views
from net.imglib2.img.array import ArrayImgs

img = ArrayImgs.unsignedBytes([100, 100, 100])

# See the input img with the pixels within the specified ROI having their values + 100:
region = Views.interval( add(img, 100).view(), [20, 20, 20], [39, 39, 39] )

... without altering the original img image in anyway.

Before, one had to copy the result of the computation into a new image in order to see it.

Along with the changes in the IFunction interface, there're several related changes in e.g. OFunction (new children() method to collect nested OFunction instances), and to ease the implementation, most classes implementing IFunction also extend ViewableFunction, an abstract class that implements these 3 methods.

The IFunction subclasses NumberSource and Var do not extend ViewableFunction and their view methods throw UnsupportedOperationException. These two classes represent single values. If an IFunction is constructed to compute using only NumberSource and Var, invoking view will throw an Exception.

imagejan commented 5 years ago

According to SemVer, this PR should have included a version bump in pom.xml before being merged into master, as it introduces new public API.