Skip to content, Skip to search

Changes

ImgLib2 Examples

65,591 bytes removed, 05:10, 13 December 2016
Use GitHubEmbed template instead of manually embedding the code
Internally, we use a compatibility '''Img''' to represent the data which is as fast as ImageJ but in the case of higher dimensionality (>2d) is slower than ImgLib2 can do with the '''ArrayImg'''. Furthermore you are limited in dimensionality (2d-5d), in the type of data ('''UnsignedByteType''', '''UnsignedShortType''', '''FloatType''' and '''ARGBType''') and maximal size of each 2d-plane (max. 46000x46000).
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example1a.java|label=Example1a.java}}'''<source lang="java">import ij.ImageJ;import ij.ImagePlus;import ij.io.Opener; import java.io.File; import net.imglib2.img.ImagePlusAdapter;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.NativeType;import net.imglib2.type.numeric.NumericType; /** * Opens a file with ImageJ and wraps it into an ImgLib {@link Img}. * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example1a{ // within this method we define <T> to be a NumericType (depends on the type of ImagePlus) // you might want to define it as RealType if you know it cannot be an ImageJ RGB Color image public < T extends NumericType< T > & NativeType< T > > Example1a() { // define the file to open File file = new File( "DrosophilaWing.tif" );  // open a file with ImageJ final ImagePlus imp = new Opener().openImage( file.getAbsolutePath() );  // display it via ImageJ imp.show();  // wrap it into an ImgLib image (no copying) final Img< T > image = ImagePlusAdapter.wrap( imp );  // display it via ImgLib using ImageJ ImageJFunctions.show( image ); }  public static void main( String[] args ) { // open an ImageJ window new ImageJ();  // run the example new Example1a(); }}</source>
=== Example 1b - Opening an ImgLib2 image ===
'''Important''': it does not matter which type of '''Img''' you use to hold the data as we will use '''Iterators''' and '''RandomAccesses''' to access the image content. It might be, however, important if you work on two '''Img''' at the same time using '''Iterators''', see Example2.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example1b.java|label=Example1b.java}}'''<source lang="java">import ij.ImageJ;import io.scif.config.SCIFIOConfig;import io.scif.config.SCIFIOConfig.ImgMode;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener; import java.io.File; import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.NativeType;import net.imglib2.type.numeric.RealType; /** * Opens a file with SCIFIO's ImgOpener as an ImgLib2 Img. */public class Example1b{ // within this method we define <T> to be a RealType and a NativeType which means the // Type is able to map the data into an java basic type array public < T extends RealType< T > & NativeType< T > > Example1b() throws ImgIOException { // define the file to open File file = new File( "DrosophilaWing.tif" ); String path = file.getAbsolutePath();  // create the ImgOpener ImgOpener imgOpener = new ImgOpener();  // open with ImgOpener. The type (e.g. ArrayImg, PlanarImg, CellImg) is // automatically determined. For a small image that fits in memory, this // should open as an ArrayImg. Img< T > image = (Img< T >) imgOpener.openImg( path );  // display it via ImgLib using ImageJ ImageJFunctions.show( image );  // create the SCIFIOConfig. This gives us configuration control over how // the ImgOpener will open its datasets. SCIFIOConfig config = new SCIFIOConfig();  // If we know what type of Img we want, we can encourage their use through // an SCIFIOConfig instance. CellImgs dynamically load image regions and are // useful when an image won't fit in memory config.imgOpenerSetImgModes( ImgMode.CELL );  // open with ImgOpener as a CellImg Img< T > imageCell = (Img< T >) imgOpener.openImg( path, config );  // display it via ImgLib using ImageJ. The Img type only affects how the // underlying data is accessed, so these images should look identical. ImageJFunctions.show( imageCell ); public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example1b(); }}</source>
=== Example 1c - Creating a new ImgLib2 image ===
Once you have one instance of an '''Img''', it is very easy to create another one using the same '''Type''' and '''ImgFactory''', even if it has a different size. Note that the call '''img.firstElement()''' returns the first pixel of any '''Iterable''', e.g. an '''Img'''.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example1c.java|label=Example1c.java}}'''<source lang="java">import ij.ImageJ;import net.imglib2.img.Img;import net.imglib2.img.ImgFactory;import net.imglib2.img.cell.CellImgFactory;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType; /** * Create a new ImgLib2 Img of Type FloatType */public class Example1c{ public Example1c() { // create the ImgFactory based on cells (cellsize = 5x5x5...x5) that will // instantiate the Img final ImgFactory< FloatType > imgFactory = new CellImgFactory< FloatType >( 5 );
// create an 3d-Img with dimensions 20x30x40 (here cellsize is 5x5x5)Ø
final Img< FloatType > img1 = imgFactory.create( new long[]{ 20, 30, 40 }, new FloatType() );
 
// create another image with the same size
// note that the input provides the size for the new image as it implements
// the Interval interface
final Img< FloatType > img2 = imgFactory.create( img1, img1.firstElement() );
 
// display both (but they are empty)
ImageJFunctions.show( img1 );
ImageJFunctions.show( img2 );
}
 
public static void main( String[] args )
{
// open an ImageJ window
new ImageJ();
 
// run the example
new Example1c();
}
}
</source>
=== Example 1d - Displaying images partly using Views ===
''Shows the original image, the View of an interval, as well as the by 90 degree rotated version of the view. Note that only the original image in kept in memory, both Views are completely virtual.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example1d.java|label=Example1d.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.RandomAccessibleInterval;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Open an ArrayImg< FloatType > and display partly and rotated */public class Example1d{ public Example1d() throws ImgIOException { // open file as float with ImgOpener Img< FloatType > img = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // display image ImageJFunctions.show( img );  // use a View to define an interval (min and max coordinate, inclusive) to display RandomAccessibleInterval< FloatType > view = Views.interval( img, new long[] { 200, 200 }, new long[]{ 500, 350 } );  // display only the part of the Img ImageJFunctions.show( view );  // or the same area rotated by 90 degrees (x-axis (0) and y-axis (1) switched) ImageJFunctions.show( Views.rotate( view, 0, 1 ) ); public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example1d(); }}</source>
== Example 2 - How to use Cursor, RandomAccess and Type ==
'''< T extends Type< T > >''' basically means that '''T''' can be anything that extends '''Type'''. These can be final implementations such as '''FloatType''' or also intermediate interfaces such as '''RealType'''. This, however, also means that in the method body only operations supported by '''Type''' will be available. Note that the method returns a '''T''', which also means that in the constructor from which we call method it will also return an '''Img<FloatType>''' as we provide it with one.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example2a.java|label=Example2a.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.Type;import net.imglib2.type.numeric.real.FloatType; /** * Here we want to copy an Image into another one using a generic method * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example2a{ public Example2a() throws ImgIOException { // open with ImgOpener as a FloatType Img< FloatType > img = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // copy the image, as it is a generic method it also works with FloatType Img< FloatType > duplicate = copyImage( img );  // display the copy ImageJFunctions.show( duplicate ); /** * Generic, type-agnostic method to create an identical copy of an Img * * @param input - the Img to copy * @return - the copy of the Img */ public < T extends Type< T > > Img< T > copyImage( final Img< T > input ) { // create a new Image with the same properties // note that the input provides the size for the new image as it implements // the Interval interface Img< T > output = input.factory().create( input, input.firstElement() );  // create a cursor for both images Cursor< T > cursorInput = input.cursor(); Cursor< T > cursorOutput = output.cursor();  // iterate over the input while ( cursorInput.hasNext()) { // move both cursors forward by one pixel cursorInput.fwd(); cursorOutput.fwd();  // set the value of this pixel of the output image to the same as the input, // every Type supports T.set( T type ) cursorOutput.get().set( cursorInput.get() ); }  // return the copy return output; }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example2a(); }}</source>
=== Example 2b - Duplicating an Img using a different ImgFactory ===
<span style="color:#FF0000">The correct code for the copy-method (in '''copyImageCorrect''') requires the use of a '''RandomAccess'''.</span> We use a '''Cursor''' to iterate over all pixels of the input and a '''RandomAccess''' which we set to the same location the output. Note that the ''setPosition()'' call of the '''RandomAccess''' directly takes the '''Cursor''' as input, which is possible because '''Cursor''' implements '''Localizable'''. Please also note that we use a '''LocalizingCursor''' instead of a normal '''Cursor''' because we need the location of the '''Cursor''' at every pixel.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example2b.java|label=Example2b.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.RandomAccess;import net.imglib2.img.Img;import net.imglib2.img.ImgFactory;import net.imglib2.img.array.ArrayImgFactory;import net.imglib2.img.cell.CellImgFactory;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.Type;import net.imglib2.type.numeric.real.FloatType; /** * Here we want to copy an ArrayImg into a CellImg using a generic method, * but we cannot do it with simple Cursors as they have a different iteration order. * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example2b{  public Example2b() throws ImgIOException { // open with ImgOpener. In addition to using ImgOptions, we can directly // pass an ImgFactory to the ImgOpener. This bypasses the Img selection // heuristic and allows custom ImgFactory implementations to be used Img< FloatType > img = (Img< FloatType >) new ImgOpener().openImg( "DrosophilaWing.tif", new ArrayImgFactory< FloatType >() );  // copy the image into a CellImg with a cellsize of 20x20// Img< FloatType > duplicate = copyImageWrong( img, new CellImgFactory< FloatType >( 20 ) ); Img< FloatType > duplicate = copyImageCorrect( img, new CellImgFactory< FloatType >( 20 ) );  // display the copy and the original ImageJFunctions.show( img ); ImageJFunctions.show( duplicate ); }  /** * WARNING: This method makes a mistake on purpose! */ public < T extends Type< T >> Img< T > copyImageWrong( final Img< T > input, final ImgFactory< T > imgFactory ) { // create a new Image with the same dimensions but the other imgFactory // note that the input provides the size for the new image as it // implements the Interval interface Img< T > output = imgFactory.create( input, input.firstElement() );  // create a cursor for both images Cursor< T > cursorInput = input.cursor(); Cursor< T > cursorOutput = output.cursor();  // iterate over the input cursor while ( cursorInput.hasNext()) { // move both forward cursorInput.fwd(); cursorOutput.fwd();  // set the value of this pixel of the output image, every Type supports T.set( T type ) cursorOutput.get().set( cursorInput.get() ); }  // return the copy return output; }  /** * This method copies the image correctly, using a RandomAccess. */ public < T extends Type< T >> Img< T > copyImageCorrect( final Img< T > input, final ImgFactory< T > imgFactory ) { // create a new Image with the same dimensions but the other imgFactory // note that the input provides the size for the new image by implementing the Interval interface Img< T > output = imgFactory.create( input, input.firstElement() );  // create a cursor that automatically localizes itself on every move Cursor< T > cursorInput = input.localizingCursor(); RandomAccess< T > randomAccess = output.randomAccess();  // iterate over the input cursor while ( cursorInput.hasNext()) { // move input cursor forward cursorInput.fwd();  // set the output cursor to the position of the input cursor randomAccess.setPosition( cursorInput );  // set the value of this pixel of the output image, every Type supports T.set( T type ) randomAccess.get().set( cursorInput.get() ); }  // return the copy return output; }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example2b(); }}</source>
=== Example 2c - Generic copying of image data ===
As the ''target'' needs to be an '''IterableInterval''', it is more confined. This, however does not necessarily mean that it can only be an '''Img''' or a '''View''' that is not infinite. It simply means it has to be something that is iterable and not infinite, which for example also applies to sparse data (e.g. a list of locations and their values).
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example2c.java|label=Example2c.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.IterableInterval;import net.imglib2.RandomAccess;import net.imglib2.RandomAccessible;import net.imglib2.RandomAccessibleInterval;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.Type;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Here we want to copy an Image into another with a different Container one using a generic method, * using a LocalizingCursor and a RandomAccess * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example2c{ public Example2c() throws ImgIOException { // open with ImgOpener as a float Img<FloatType> img = new ImgOpener().openImg("DrosophilaWing.tif", new FloatType());  // copy & display an image Img< FloatType > duplicate = img.factory().create( img, img.firstElement() ); copy( img, duplicate ); ImageJFunctions.show( duplicate );  // use a View to define an interval as source for copying // // Views.offsetInterval() does not only define where it is, but also adds a translation // so that the minimal coordinate (upper left) of the view maps to (0,0) RandomAccessibleInterval< FloatType > viewSource = Views.offsetInterval( img, new long[] { 100, 100 }, new long[]{ 250, 150 } );  // and as target RandomAccessibleInterval< FloatType > viewTarget = Views.offsetInterval( img, new long[] { 500, 200 }, new long[]{ 250, 150 } );  // now we make the target iterable // (which is possible because it is a RandomAccessibleInterval) IterableInterval< FloatType > iterableTarget = Views.iterable( viewTarget );  // copy it into the original image (overwriting part of img) copy( viewSource, iterableTarget );  // show the original image ImageJFunctions.show( img ); }  /** * Copy from a source that is just RandomAccessible to an IterableInterval. Latter one defines * size and location of the copy operation. It will query the same pixel locations of the * IterableInterval in the RandomAccessible. It is up to the developer to ensure that these * coordinates match. * * Note that both, input and output could be Views, Img or anything that implements * those interfaces. * * @param source - a RandomAccess as source that can be infinite * @param target - an IterableInterval as target */ public < T extends Type< T > > void copy( final RandomAccessible< T > source, final IterableInterval< T > target ) { // create a cursor that automatically localizes itself on every move Cursor< T > targetCursor = target.localizingCursor(); RandomAccess< T > sourceRandomAccess = source.randomAccess();  // iterate over the input cursor while ( targetCursor.hasNext()) { // move input cursor forward targetCursor.fwd();  // set the output cursor to the position of the input cursor sourceRandomAccess.setPosition( targetCursor );  // set the value of this pixel of the output image, every Type supports T.set( T type ) targetCursor.get().set( sourceRandomAccess.get() ); } }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example2c(); }}</source>
== Example 3 - Writing generic algorithms ==
==== Example 3a - Variation 1 ====
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example3a1.java|label=Example3a1.java}}'''<source lang="java"> import io.scif.img.ImgIOException;import io.scif.img.ImgOpener; import java.util.Iterator; import net.imglib2.Cursor;import net.imglib2.RandomAccess;import net.imglib2.img.Img;import net.imglib2.type.NativeType;import net.imglib2.type.Type;import net.imglib2.type.numeric.RealType; /** * Perform a generic min & max search * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example3a1{ public < T extends RealType< T > & NativeType< T > > Example3a1() throws ImgIOException { // open with ImgOpener (he will decide which Img is best) Img< T > img = (Img< T >) new ImgOpener().openImg( "DrosophilaWing.tif" );  // create two empty variables T min = img.firstElement().createVariable(); T max = img.firstElement().createVariable();  // compute min and max of the Image computeMinMax( img, min, max );  System.out.println( "minimum Value (img): " + min ); System.out.println( "maximum Value (img): " + max ); }  /** * Compute the min and max for any {@link Iterable}, like an {@link Img}. * * The only functionality we need for that is to iterate. Therefore we need no {@link Cursor} * that can localize itself, neither do we need a {@link RandomAccess}. So we simply use the * most simple interface in the hierarchy. * * @param input - the input that has to just be {@link Iterable} * @param min - the type that will have min * @param max - the type that will have max */ public < T extends Comparable< T > & Type< T > > void computeMinMax( final Iterable< T > input, final T min, final T max ) { // create a cursor for the image (the order does not matter) final Iterator< T > iterator = input.iterator();  // initialize min and max with the first image value T type = iterator.next();  min.set( type ); max.set( type );  // loop over the rest of the data and determine min and max value while ( iterator.hasNext() ) { // we need this type more than once type = iterator.next();  if ( type.compareTo( min ) < 0 ) min.set( type );  if ( type.compareTo( max ) > 0 ) max.set( type ); } }  public static void main( String[] args ) throws ImgIOException { // run the example new Example3a1(); }}</source>
==== Example 3a - Variation 2 ====
Note that this example works just the same way if the input is not an '''Img''', but for example just a standard Java '''ArrayList'''.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example3a2.java|label=Example3a2.java}}'''<source lang="java">import java.util.ArrayList;import java.util.Iterator; import net.imglib2.Cursor;import net.imglib2.RandomAccess;import net.imglib2.img.Img;import net.imglib2.type.Type;import net.imglib2.type.numeric.real.FloatType; /** * Perform a generic min & max search * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example3a2{ public Example3a2() { // it will work as well on a normal ArrayList ArrayList< FloatType > list = new ArrayList< FloatType >();  // put values 0 to 10 into the ArrayList for ( int i = 0; i <= 10; ++i ) list.add( new FloatType( i ) );  // create two empty variables FloatType min = new FloatType(); FloatType max = new FloatType();  // compute min and max of the ArrayList computeMinMax( list, min, max );  System.out.println( "minimum Value (arraylist): " + min ); System.out.println( "maximum Value (arraylist): " + max ); }  /** * Compute the min and max for any {@link Iterable}, like an {@link Img}. * * The only functionality we need for that is to iterate. Therefore we need no {@link Cursor} * that can localize itself, neither do we need a {@link RandomAccess}. So we simply use the * most simple interface in the hierarchy. * * @param input - the input that has to just be {@link Iterable} * @param min - the type that will have min * @param max - the type that will have max */ public < T extends Comparable< T > & Type< T > > void computeMinMax( final Iterable< T > input, final T min, final T max ) { // create a cursor for the image (the order does not matter) final Iterator< T > iterator = input.iterator();  // initialize min and max with the first image value T type = iterator.next();  min.set( type ); max.set( type );  // loop over the rest of the data and determine min and max value while ( iterator.hasNext() ) { // we need this type more than once type = iterator.next();  if ( type.compareTo( min ) < 0 ) min.set( type );  if ( type.compareTo( max ) > 0 ) max.set( type ); } }  public static void main( String[] args ) { // run the example new Example3a2(); }}</source>
==== Example 3a - Variation 3 ====
If we want to compute the location of the minimal and maximal pixel value, an '''Iterator''' will not be sufficient as we need location information. Instead the location search will demand an '''IterableInterval''' as input data which can create '''Cursors'''. Apart from that, the algorithm looks quite similar. Note that we do not use a '''LocalizingCursor''' but only a '''Cursor''' the location happens only when a new maximal or minimal value has been found while iterating the data.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example3a3.java|label=Example3a3.java}}'''<source lang="java">import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.IterableInterval;import net.imglib2.Point;import net.imglib2.img.Img;import net.imglib2.type.NativeType;import net.imglib2.type.Type;import net.imglib2.type.numeric.RealType; /** * Perform a generic min/max search. * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example3a3{ public < T extends RealType< T > & NativeType< T > > Example3a3() throws ImgIOException { // open with ImgOpener (he will decide which Img is best) Img< T > img = (Img< T >) new ImgOpener().openImg( "DrosophilaWing.tif" );  // create two location objects Point locationMin = new Point( img.numDimensions() ); Point locationMax = new Point( img.numDimensions() );  // compute location of min and max computeMinMaxLocation( img, locationMin, locationMax );  System.out.println( "location of minimum Value (img): " + locationMin ); System.out.println( "location of maximum Value (img): " + locationMax ); }  /** * Compute the location of the minimal and maximal intensity for any IterableInterval, * like an {@link Img}. * * The functionality we need is to iterate and retrieve the location. Therefore we need a * Cursor that can localize itself. * Note that we do not use a LocalizingCursor as localization just happens from time to time. * * @param input - the input that has to just be {@link IterableInterval} * @param minLocation - the location for the minimal value * @param maxLocation - the location of the maximal value */ public < T extends Comparable< T > & Type< T > > void computeMinMaxLocation( final IterableInterval< T > input, final Point minLocation, final Point maxLocation ) { // create a cursor for the image (the order does not matter) final Cursor< T > cursor = input.cursor();  // initialize min and max with the first image value T type = cursor.next(); T min = type.copy(); T max = type.copy();  // loop over the rest of the data and determine min and max value while ( cursor.hasNext() ) { // we need this type more than once type = cursor.next();  if ( type.compareTo( min ) < 0 ) { min.set( type ); minLocation.setPosition( cursor ); }  if ( type.compareTo( max ) > 0 ) { max.set( type ); maxLocation.setPosition( cursor ); } } }  public static void main( String[] args ) throws ImgIOException { // run the example new Example3a3(); }}</source>
=== Example 3b - Computing average ===
In a very similar way one can compute the average intensity for image data. Note that we restrict the '''Type''' of data to '''RealType'''. In theory, we could use '''NumericType''' as it offers the possibility to ''add'' up values. However, we cannot ensure that '''NumericType''' provided is capable of adding up millions of pixels without overflow. And even if we would ask for a second '''NumericType''' that is capable of adding values up, it might still have numerical instabilities. ''Note that actually every Java native type has those instabilities''. Therefore we use the '''RealSum''' class that offers correct addition of even very large amounts of pixels. As this implementation is only available for double values, we restrict the method here to '''RealType'''.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example3b.java|label=Example3b.java}}'''<source lang="java">import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.img.Img;import net.imglib2.type.NativeType;import net.imglib2.type.numeric.RealType;import net.imglib2.util.RealSum; /** * Perform a generic computation of average intensity * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example3b{ public < T extends RealType< T > & NativeType< T > > Example3b() throws ImgIOException { // open with ImgOpener final Img< T > img = (Img< T >) new ImgOpener().openImg( "DrosophilaWing.tif" );  // compute average of the image final double avg = computeAverage( img ); System.out.println( "average Value: " + avg ); /** * Compute the average intensity for an {@link Iterable}. * * @param input - the input data * @return - the average as double */ public < T extends RealType< T > > double computeAverage( final Iterable< T > input ) { // Count all values using the RealSum class. // It prevents numerical instabilities when adding up millions of pixels final RealSum realSum = new RealSum(); long count = 0;  for ( final T type : input ) { realSum.add( type.getRealDouble() ); ++count; }  return realSum.getSum() / count; }  public static void main( final String[] args ) throws ImgIOException { // run the example new Example3b(); }}</source>
== Example 4 - Specialized iterables ==
''Shows the result of example 4a for the (a) two-dimensional, (b) three-dimensional and (c) four-dimensional case. The image series in (c) represents a movie of a three-dimensional rendering. The images of (b) and (c) were rendered using the ImageJ 3d Viewer.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example4a.java|label=Example4a.java}}'''<source lang="java">import ij.ImageJ;import ij.ImagePlus; import java.util.Random; import net.imglib2.Point;import net.imglib2.RandomAccessibleInterval;import net.imglib2.algorithm.region.hypersphere.HyperSphere;import net.imglib2.algorithm.region.hypersphere.HyperSphereCursor;import net.imglib2.exception.ImgLibException;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.img.imageplus.ImagePlusImg;import net.imglib2.img.imageplus.ImagePlusImgFactory;import net.imglib2.type.numeric.RealType;import net.imglib2.type.numeric.integer.UnsignedByteType;import net.imglib2.util.Util; /** * Draw a sphere full of little spheres */public class Example4a{ public Example4a() { // open with ImgOpener using an ImagePlusImg ImagePlusImg< UnsignedByteType, ?> img = new ImagePlusImgFactory< UnsignedByteType >().create( new long[] { 256, 256, 256 }, new UnsignedByteType() );  // draw a small sphere for every pixel of a larger sphere drawSpheres( img, 0, 255 );  // display output and input try { ImagePlus imp = img.getImagePlus(); imp.show(); } catch ( ImgLibException e ) { System.out.println( "This ImagePlusImg does not hold a native " + "ImagePlus as container, either because the dimensionality is too " + "high or because the type is not supported." ); ImageJFunctions.show( img ); } }  /** * Draws a sphere that contains lots of small spheres into the center of the interval * * @param randomAccessible - the image data to write to * @param minValue - the minimal intensity of one of the small spheres * @param maxValue - the maximal intensity of one of the small spheres */ public < T extends RealType< T > > void drawSpheres( final RandomAccessibleInterval< T > randomAccessible, final double minValue, final double maxValue ) { // the number of dimensions int numDimensions = randomAccessible.numDimensions();  // define the center and radius Point center = new Point( randomAccessible.numDimensions() ); long minSize = randomAccessible.dimension( 0 );  for ( int d = 0; d < numDimensions; ++d ) { long size = randomAccessible.dimension( d );  center.setPosition( size / 2 , d ); minSize = Math.min( minSize, size ); }  // define the maximal radius of the small spheres int maxRadius = 5;  // compute the radius of the large sphere so that we do not draw // outside of the defined interval long radiusLargeSphere = minSize / 2 - maxRadius - 1;  // instantiate a random number generator Random rnd = new Random( System.currentTimeMillis() );  // define a hypersphere (n-dimensional sphere) HyperSphere< T > hyperSphere = new HyperSphere<T>( randomAccessible, center, radiusLargeSphere );  // create a cursor on the hypersphere HyperSphereCursor< T > cursor = hyperSphere.cursor();  while ( cursor.hasNext() ) { cursor.fwd();  // the random radius of the current small hypersphere int radius = rnd.nextInt( maxRadius ) + 1;  // instantiate a small hypersphere at the location of the current pixel // in the large hypersphere HyperSphere< T > smallSphere = new HyperSphere< T >( randomAccessible, cursor, radius );  // define the random intensity for this small sphere double randomValue = rnd.nextDouble();  // take only every 4^dimension'th pixel by chance so that it is not too crowded if ( Math.round( randomValue * 100 ) % Util.pow( 4, numDimensions ) == 0 ) { // scale to right range randomValue = rnd.nextDouble() * ( maxValue - minValue ) + minValue;  // set the value to all pixels in the small sphere if the intensity is // brighter than the existing one for ( final T value : smallSphere ) value.setReal( Math.max( randomValue, value.getRealDouble() ) ); } } }  public static void main( String[] args ) { // open an ImageJ window new ImageJ();  // run the example new Example4a(); }}</source>
=== Example 4b - Finding and displaying local minima ===
''Shows the result of the detection of local minima after the Gaussian blurring. (a) depicts the input image, (b) the blurred version (sigma=1) and (c) all local mimina drawn as circles with radius 1.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example4b.java|label=Example4b.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.Interval;import net.imglib2.RandomAccessibleInterval;import net.imglib2.algorithm.gauss.Gauss;import net.imglib2.algorithm.neighborhood.Neighborhood;import net.imglib2.algorithm.neighborhood.RectangleShape;import net.imglib2.algorithm.region.hypersphere.HyperSphere;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.ImgFactory;import net.imglib2.img.array.ArrayImgFactory;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.NativeType;import net.imglib2.type.logic.BitType;import net.imglib2.type.numeric.RealType;import net.imglib2.util.Intervals;import net.imglib2.view.Views; /** * Here we use special cursors to find the local minima and * display them with spheres in another image */public class Example4b{ public < T extends RealType< T > & NativeType< T > > Example4b() throws ImgIOException { // open with ImgOpener Img< T > img = (Img< T >) new ImgOpener().openImg( "DrosophilaWing.tif" );  // first we do a small in-place gaussian smoothing with a sigma of 1 Gauss.inDoubleInPlace( new double[]{ 1, 1 }, img );  // find local minima and paint them into another image as spheres Img< BitType > display = findAndDisplayLocalMinima( img, new ArrayImgFactory< BitType >(), new BitType() );  // display output and input ImageJFunctions.show( img ); ImageJFunctions.show( display ); /** * Checks all pixels in the image if they are a local minima and * draws a circle into the output if they are * * @param source - the image data to work on * @param imageFactory - the factory for the output img * @param outputType - the output type * @return - an Img with circles on locations of a local minimum */ public static < T extends Comparable< T >, U extends RealType< U > > Img< U > findAndDisplayLocalMinima( RandomAccessibleInterval< T > source, ImgFactory< U > imageFactory, U outputType ) { // Create a new image for the output Img< U > output = imageFactory.create( source, outputType );  // define an interval that is one pixel smaller on each side in each dimension, // so that the search in the 8-neighborhood (3x3x3...x3) never goes outside // of the defined interval Interval interval = Intervals.expand( source, -1 );  // create a view on the source with this interval source = Views.interval( source, interval );  // create a Cursor that iterates over the source and checks in a 8-neighborhood // if it is a minima final Cursor< T > center = Views.iterable( source ).cursor();  // instantiate a RectangleShape to access rectangular local neighborhoods // of radius 1 (that is 3x3x...x3 neighborhoods), skipping the center pixel // (this corresponds to an 8-neighborhood in 2d or 26-neighborhood in 3d, ...) final RectangleShape shape = new RectangleShape( 1, true );  // iterate over the set of neighborhoods in the image for ( final Neighborhood< T > localNeighborhood : shape.neighborhoods( source ) ) { // what is the value that we investigate? // (the center cursor runs over the image in the same iteration order as neighborhood) final T centerValue = center.next();  // keep this boolean true as long as no other value in the local neighborhood // is larger or equal boolean isMinimum = true;  // check if all pixels in the local neighborhood that are smaller for ( final T value : localNeighborhood ) { // test if the center is smaller than the current pixel value if ( centerValue.compareTo( value ) >= 0 ) { isMinimum = false; break; } }  if ( isMinimum ) { // draw a sphere of radius one in the new image HyperSphere< U > hyperSphere = new HyperSphere< U >( output, center, 1 );  // set every value inside the sphere to 1 for ( U value : hyperSphere ) value.setOne(); } }  return output; }  public static void main( String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example4b(); }}</source>
== Example 5 - Out of bounds ==
''Illustrates the effect of various OutOfBoundsStrategies. (a) shows out of bounds with a constant value, (b) shows a mirroring strategy, (c) shows the periodic strategy, and (d) shows a strategy that uses random values.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example5.java|label=Example5.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.FinalInterval;import net.imglib2.RandomAccessible;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.outofbounds.OutOfBoundsConstantValueFactory;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.ExtendedRandomAccessibleInterval;import net.imglib2.view.Views; /** * Illustrate outside strategies * */public class Example5{ public Example5() throws ImgIOException { // open with ImgOpener as a FloatType Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWingSmall.tif", new FloatType() );  // create an infinite view where all values outside of the Interval are 0 RandomAccessible< FloatType> infinite1 = Views.extendValue( image, new FloatType( 0 ) );  // create an infinite view where all values outside of the Interval are 128 RandomAccessible< FloatType> infinite2 = Views.extendValue( image, new FloatType( 128 ) );  // create an infinite view where all outside values are random in a range of 0-255 RandomAccessible< FloatType> infinite3 = Views.extendRandom( image, 0, 255 );  // create an infinite view where all values outside of the Interval are // the mirrored content, the mirror is the last pixel RandomAccessible< FloatType> infinite4 = Views.extendMirrorSingle( image );  // create an infinite view where all values outside of the Interval are // the mirrored content, the mirror is BEHIND the last pixel, // i.e. the first and last pixel are always duplicated RandomAccessible< FloatType> infinite5 = Views.extendMirrorDouble( image );  // all values outside of the Interval periodically repeat the image content // (like the Fourier space assumes) RandomAccessible< FloatType> infinite6 = Views.extendPeriodic( image );  // if you implemented your own strategy that you want to instantiate, it will look like this RandomAccessible< FloatType> infinite7 = new ExtendedRandomAccessibleInterval< FloatType, Img< FloatType > >( image, new OutOfBoundsConstantValueFactory< FloatType, Img< FloatType > >( new FloatType( 255 ) ) );  // visualize the outofbounds strategies  // in order to visualize them, we have to define a new interval // on them which can be displayed long[] min = new long[ image.numDimensions() ]; long[] max = new long[ image.numDimensions() ];  for ( int d = 0; d < image.numDimensions(); ++d ) { // we add/subtract another 30 pixels here to illustrate // that it is really infinite and does not only work once min[ d ] = -image.dimension( d ) - 90 ; max[ d ] = image.dimension( d ) * 2 - 1 + 90; // define the Interval on the infinite random accessibles FinalInterval interval = new FinalInterval( min, max );  // now define the interval on the infinite view and display ImageJFunctions.show( Views.interval( infinite1, interval ) ); ImageJFunctions.show( Views.interval( infinite2, interval ) ); ImageJFunctions.show( Views.interval( infinite3, interval ) ); ImageJFunctions.show( Views.interval( infinite4, interval ) ); ImageJFunctions.show( Views.interval( infinite5, interval ) ); ImageJFunctions.show( Views.interval( infinite6, interval ) ); ImageJFunctions.show( Views.interval( infinite7, interval ) ); }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example5(); }}</source>
== Example 6 - Basic built-in algorithms ==
Here, we simply apply a Gaussian convolution with a sigma of 8. Note that it could be applied in-place as well when calling ''Gauss.inFloatInPlace( ... )''. The Gaussian convolution uses by default the '''OutOfBoundsMirrorStrategy'''.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6a1.java|label=Example6a1.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.algorithm.gauss.Gauss;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType; /** * Use of Gaussian Convolution on the Image * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example6a1{ public Example6a1() throws ImgIOException { // open with ImgOpener as a FloatType Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // perform gaussian convolution with float precision double[] sigma = new double[ image.numDimensions() ];  for ( int d = 0; d < image.numDimensions(); ++d ) sigma[ d ] = 8;  // convolve & display ImageJFunctions.show( Gauss.toFloat( sigma, image ) ); }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example6a1(); }}</source>
==== Example 6a - Gaussian convolution (variation 2 - different OutOfBoundsStrategy) ====
Here we use an '''OutOfBoundsStrategyConstantValue''' instead. It results in continuously darker borders as the zero-values from outside of the image are used in the convolution. Note that the computation is done in-place here. However, we still need to provide an '''ImgFactory''' as the Gaussian convolution needs to create temporary image(s) - except for the one-dimensional case.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6a2.java|label=Example6a2.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.RandomAccessible;import net.imglib2.algorithm.gauss3.Gauss3;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Use of Gaussian Convolution on the Image * but convolve with a different outofboundsstrategy * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example6a2{ public Example6a2() throws ImgIOException, IncompatibleTypeException { // open with ImgOpener as a FloatType Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // perform gaussian convolution with float precision double[] sigma = new double[ image.numDimensions() ];  for ( int d = 0; d < image.numDimensions(); ++d ) sigma[ d ] = 8;  // first extend the image to infinity, zeropad RandomAccessible< FloatType > infiniteImg = Views.extendValue( image, new FloatType() );  // now we convolve the whole image manually in-place // note that is is basically the same as the call above, just called in a more generic way // // sigma .. the sigma // infiniteImg ... the RandomAccessible that is the source for the convolution // image ... defines the RandomAccessibleInterval that is the target of the convolution Gauss3.gauss( sigma, infiniteImg, image );  // show the in-place convolved image (note the different outofboundsstrategy at the edges) ImageJFunctions.show( image ); }  public static void main( String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example6a2(); }}</source>
==== Example 6a - Gaussian convolution (variation 3 - only part of an Interval) ====
Note: if you wanted, you could force him to use an '''OutOfBoundsStrategy''' directly outside of the '''Interval'''. For that you would have to create an '''RandomAccessibleInterval''' on the '''Img''', extend it by an '''OutOfBoundsStrategy''' and give this as input to the Gaussian convolution.
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6a3.java|label=Example6a3.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.FinalInterval;import net.imglib2.RandomAccessible;import net.imglib2.RandomAccessibleInterval;import net.imglib2.algorithm.gauss3.Gauss3;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.util.Intervals;import net.imglib2.view.Views; /** * Use of Gaussian Convolution on the Image * but convolve just a part of the image * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example6a3{ public Example6a3() throws ImgIOException, IncompatibleTypeException { // open with ImgOpener as a FloatType Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // perform gaussian convolution with float precision double sigma = 8;  // we need to extend it nevertheless as the algorithm needs more pixels from around // the convolved area and we are not sure how much exactly (altough we could compute // it with some effort from the sigma). // Here we let the Views framework take care of the details. The Gauss convolution // knows which area of the source image is required, and if the extension is not needed, // it will operate on the original image with no runtime overhead. RandomAccessible< FloatType> infiniteImg = Views.extendMirrorSingle( image );  // define the area of the image which we want to compute FinalInterval interval = Intervals.createMinMax( 100, 30, 500, 250 ); RandomAccessibleInterval< FloatType > region = Views.interval( image, interval );  // call the gauss, we convolve only a region and write it back to the exact same coordinates Gauss3.gauss( sigma, infiniteImg, region );  ImageJFunctions.show( image ); }  public static void main( String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example6a3(); }}</source>
==== Example 6a - Gaussian convolution (variation 4 - with a lower dimensionality) ====
Specifically, we apply 1-dimensional Gaussian convolution in 30-pixel wide stripes using a sigma of 16. ''Note that whenever you request an ''HyperSlice'' for a certain dimension, you will get back a '''View''' that contains all dimensions <span style="color:#FF0000">but</span> this one.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6a4.java|label=Example6a4.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.RandomAccessibleInterval;import net.imglib2.algorithm.gauss3.Gauss3;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Use of Gaussian Convolution on the Image * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example6a4{ public Example6a4() throws ImgIOException, IncompatibleTypeException { // open with ImgOpener as a FloatType Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  // perform all (n-1)-dimensional gaussian (in this case it means 1d) on // some of the row/columns double[] sigma = new double[ image.numDimensions() - 1 ];  for ( int d = 0; d < sigma.length; ++d ) sigma[ d ] = 16;  // iterate over all dimensions, take always a hyperslice for ( int dim = 0; dim < image.numDimensions(); ++dim ) // iterate over all possible hyperslices for ( long pos = 0; pos < image.dimension( dim ); ++pos ) // convolve a subset of the 1-dimensional views if ( pos/30 % 2 == 1 ) { // get the n-1 dimensional "slice" RandomAccessibleInterval< FloatType > view = Views.hyperSlice( image, dim, pos );  // compute the gauss in-place on the view Gauss3.gauss( sigma, Views.extendMirrorSingle( view ), view ); }  // show the result ImageJFunctions.show( image ); }  public static void main( String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example6a4(); }}</source>
=== Example 6b - Convolution in Fourier space ===
<span style="color:#FF0000">''Important: This source code is only GPLv2!''</span>
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6b.java|label=Example6b.java}}'''<source lang="java">/** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * An exception is the 1D FFT implementation of Dave Hale which we use as a * library, which is released under the terms of the Common Public License - * v1.0, which is available at http://www.eclipse.org/legal/cpl-v10.html * * @author Stephan Preibisch (stephan.preibisch@gmx.de) */import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.algorithm.fft2.FFTConvolution;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.RealType;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.util.RealSum; /** * Perform a gaussian convolution using fourier convolution */public class Example6b{ public Example6b() throws ImgIOException, IncompatibleTypeException { // open with ImgOpener using an ArrayImgFactory final Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() ); final Img< FloatType > kernel = new ImgOpener().openImg( "kernelRing.tif", new FloatType() );  // normalize the kernel, otherwise we add energy to the image norm( kernel );  // display image & kernel ImageJFunctions.show( kernel ).setTitle( "kernel" ); ImageJFunctions.show( image ).setTitle( "drosophila wing");  // compute & show fourier convolution (in-place) new FFTConvolution<FloatType>( image, kernel ).convolve(); ImageJFunctions.show( image ) .setTitle( "convolution" ); }  /** * Computes the sum of all pixels in an iterable using RealSum * * @param iterable - the image data * @return - the sum of values */ public static < T extends RealType< T > > double sumImage( final Iterable< T > iterable ) { final RealSum sum = new RealSum();  for ( final T type : iterable ) sum.add( type.getRealDouble() );  return sum.getSum(); }  /** * Norms all image values so that their sum is 1 * * @param iterable - the image data */ public static void norm( final Iterable< FloatType > iterable ) { final double sum = sumImage( iterable );  for ( final FloatType type : iterable ) type.setReal( type.get() / sum ); }  public static void main( final String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example6b(); }}</source>
=== Example 6c - Complex numbers and Fourier transforms ===
<span style="color:#FF0000">''Important: This source code is only GPLv2!''</span>
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example6c.java|label=Example6c.java}}'''<source lang="java">/** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * An exception is the 1D FFT implementation of Dave Hale which we use as a * library, which is released under the terms of the Common Public License - * v1.0, which is available at http://www.eclipse.org/legal/cpl-v10.html */import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.algorithm.fft.FourierConvolution;import net.imglib2.algorithm.fft.FourierTransform;import net.imglib2.algorithm.fft.InverseFourierTransform;import net.imglib2.converter.ComplexImaginaryFloatConverter;import net.imglib2.converter.ComplexPhaseFloatConverter;import net.imglib2.converter.ComplexRealFloatConverter;import net.imglib2.exception.IncompatibleTypeException;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.type.numeric.RealType;import net.imglib2.type.numeric.complex.ComplexFloatType;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.util.RealSum; /** * Perform template matching by convolution in the Fourier domain * * @author Stephan Preibisch & Stephan Saalfeld * */public class Example6c{ public Example6c() throws ImgIOException, IncompatibleTypeException { // open with ImgOpener as FloatTypes final Img< FloatType > image = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() ); final Img< FloatType > template = new ImgOpener().openImg( "WingTemplate.tif", new FloatType() );  // display image and template ImageJFunctions.show( image ).setTitle( "input" ); ImageJFunctions.show( template ).setTitle( "template" );  // compute fourier transform of the template final FourierTransform< FloatType, ComplexFloatType > fft = new FourierTransform< FloatType, ComplexFloatType >( template, new ComplexFloatType() ); fft.process(); final Img< ComplexFloatType > templateFFT = fft.getResult();  // display fft (by default in generalized log power spectrum ImageJFunctions.show( templateFFT ).setTitle( "fft power spectrum" ); // display fft phase spectrum ImageJFunctions.show( templateFFT, new ComplexPhaseFloatConverter< ComplexFloatType >() ) .setTitle( "fft phase spectrum" ); // display fft real values ImageJFunctions.show( templateFFT, new ComplexRealFloatConverter< ComplexFloatType >() ) .setTitle( "fft real values" ); // display fft imaginary values ImageJFunctions.show( templateFFT, new ComplexImaginaryFloatConverter< ComplexFloatType >() ) .setTitle( "fft imaginary values" );  // complex invert the kernel final ComplexFloatType c = new ComplexFloatType(); for ( final ComplexFloatType t : templateFFT ) { c.set( t ); t.complexConjugate(); c.mul( t ); t.div( c ); }  // compute inverse fourier transform of the template final InverseFourierTransform< FloatType, ComplexFloatType > ifft = new InverseFourierTransform< FloatType, ComplexFloatType >( templateFFT, fft ); ifft.process(); final Img< FloatType > templateInverse = ifft.getResult();  // display the inverse template ImageJFunctions.show( templateInverse ).setTitle( "inverse template" );  // normalize the inverse template norm( templateInverse );  // compute fourier convolution of the inverse template and the image and display it ImageJFunctions.show( FourierConvolution.convolve( image, templateInverse ) ); } /** * Computes the sum of all pixels in an iterable using RealSum * * @param iterable - the image data * @return - the sum of values */ public static < T extends RealType< T > > double sumImage( final Iterable< T > iterable ) { final RealSum sum = new RealSum();  for ( final T type : iterable ) sum.add( type.getRealDouble() );  return sum.getSum(); }  /** * Norms all image values so that their sum is 1 * * @param iterable - the image data */ public static void norm( final Iterable< FloatType > iterable ) { final double sum = sumImage( iterable );  for ( final FloatType type : iterable ) type.setReal( type.get() / sum ); }  public static void main( final String[] args ) throws ImgIOException, IncompatibleTypeException { // open an ImageJ window new ImageJ();  // run the example new Example6c(); }}</source>
== Example 7 - Interpolation ==
''Shows the result for three different interpolators when magnifying a small part of the image by 10x. The nearest neighbor interpolation is computed fastest and is the most versatile as it requires no computation but just a lookout. The result is, however, very pixelated. The linear interpolation produces reasonable results and computes quite fast. The Lanczos interpolation shows visually most pleasing results but also introduces slight artifacts in the background.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example7.java|label=Example7.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener;import net.imglib2.Cursor;import net.imglib2.FinalRealInterval;import net.imglib2.RealInterval;import net.imglib2.RealRandomAccess;import net.imglib2.RealRandomAccessible;import net.imglib2.img.Img;import net.imglib2.img.ImgFactory;import net.imglib2.img.array.ArrayImgFactory;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.interpolation.randomaccess.LanczosInterpolatorFactory;import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory;import net.imglib2.interpolation.randomaccess.NearestNeighborInterpolatorFactory;import net.imglib2.type.Type;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.util.Util;import net.imglib2.view.Views; /** * Use three different interpolators to 10x magnify a small area */public class Example7{ public Example7() throws ImgIOException { // open with ImgOpener using an ArrayImgFactory Img< FloatType > img = new ImgOpener().openImg( "DrosophilaWing.tif", new FloatType() );  ImageJFunctions.show( img );  // create an InterpolatorFactory RealRandomAccessible using nearst neighbor interpolation NearestNeighborInterpolatorFactory< FloatType > factory1 = new NearestNeighborInterpolatorFactory< FloatType >();  // create an InterpolatorFactory RealRandomAccessible using linear interpolation NLinearInterpolatorFactory< FloatType > factory2 = new NLinearInterpolatorFactory< FloatType >();  // create an InterpolatorFactory RealRandomAccessible using lanczos interpolation LanczosInterpolatorFactory< FloatType > factory3 = new LanczosInterpolatorFactory< FloatType >();  // create a RandomAccessible using the factory and views method // it is important to extend the image first, the interpolation scheme might // grep pixels outside of the boundaries even when locations inside are queried // as they integrate pixel information in a local neighborhood - the size of // this neighborhood depends on which interpolator is used RealRandomAccessible< FloatType > interpolant1 = Views.interpolate( Views.extendMirrorSingle( img ), factory1 ); RealRandomAccessible< FloatType > interpolant2 = Views.interpolate( Views.extendMirrorSingle( img ), factory2 ); RealRandomAccessible< FloatType > interpolant3 = Views.interpolate( Views.extendMirrorSingle( img ), factory3 );  // define the area in the interpolated image double[] min = new double[]{ 105.12, 40.43 }; double[] max = new double[]{ 129.56, 74.933 };  FinalRealInterval interval = new FinalRealInterval( min, max );  ImageJFunctions.show( magnify( interpolant1, interval, new ArrayImgFactory< FloatType >(), 10 ) ).setTitle( "Nearest Neighbor Interpolation" ); ImageJFunctions.show( magnify( interpolant2, interval, new ArrayImgFactory< FloatType >(), 10 ) ).setTitle( "Linear Interpolation" ); ImageJFunctions.show( magnify( interpolant3, interval, new ArrayImgFactory< FloatType >(), 10 ) ).setTitle( "Lanczos Interpolation" ); /** * Compute a magnified version of a given real interval * * @param source - the input data * @param interval - the real interval on the source that should be magnified * @param factory - the image factory for the output image * @param magnification - the ratio of magnification * @return - an Img that contains the magnified image content */ public static < T extends Type< T > > Img< T > magnify( RealRandomAccessible< T > source, RealInterval interval, ImgFactory< T > factory, double magnification ) { int numDimensions = interval.numDimensions();  // compute the number of pixels of the output and the size of the real interval long[] pixelSize = new long[ numDimensions ]; double[] intervalSize = new double[ numDimensions ];  for ( int d = 0; d < numDimensions; ++d ) { intervalSize[ d ] = interval.realMax( d ) - interval.realMin( d ); pixelSize[ d ] = Math.round( intervalSize[ d ] * magnification ) + 1; }  // create the output image Img< T > output = factory.create( pixelSize, source.realRandomAccess().get() );  // cursor to iterate over all pixels Cursor< T > cursor = output.localizingCursor();  // create a RealRandomAccess on the source (interpolator) RealRandomAccess< T > realRandomAccess = source.realRandomAccess();  // the temporary array to compute the position double[] tmp = new double[ numDimensions ];  // for all pixels of the output image while ( cursor.hasNext() ) { cursor.fwd();  // compute the appropriate location of the interpolator for ( int d = 0; d < numDimensions; ++d ) tmp[ d ] = cursor.getDoublePosition( d ) / output.realMax( d ) * intervalSize[ d ] + interval.realMin( d );  // set the position realRandomAccess.setPosition( tmp );  // set the new value cursor.get().set( realRandomAccess.get() ); }  return output; }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example7(); }}</source>
== Example 8 - Working with sparse data ==
''On the left hand side it shows nearest-neighbor rendered random sparse data as created in example 8a. The right hand side shows the result of a Gaussian convolution, run directly on the virtual RandomAccessibleInterval.''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example8a.java|label=Example8a.java}}'''<source lang="java">import ij.ImageJ; import java.util.Random; import net.imglib2.FinalInterval;import net.imglib2.IterableRealInterval;import net.imglib2.KDTree;import net.imglib2.Point;import net.imglib2.RandomAccessible;import net.imglib2.RandomAccessibleInterval;import net.imglib2.RealInterval;import net.imglib2.RealPoint;import net.imglib2.RealPointSampleList;import net.imglib2.RealRandomAccessible;import net.imglib2.algorithm.gauss.Gauss;import net.imglib2.img.Img;import net.imglib2.img.array.ArrayImgFactory;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.interpolation.neighborsearch.NearestNeighborSearchInterpolatorFactory;import net.imglib2.neighborsearch.NearestNeighborSearch;import net.imglib2.neighborsearch.NearestNeighborSearchOnKDTree;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Working with sparse data * * Create some random points with random values, display them and perform * a Gaussian convolution on the VIRTUAL data */public class Example8a{ public Example8a() { // the interval in which to create random points FinalInterval interval = new FinalInterval( new long[] { 375, 200 } );  // create an IterableRealInterval IterableRealInterval< FloatType > realInterval = createRandomPoints( interval, 250 );  // using nearest neighbor search we will be able to return a value an any position in space NearestNeighborSearch< FloatType > search = new NearestNeighborSearchOnKDTree<FloatType>( new KDTree< FloatType> ( realInterval ) );  // make it into RealRandomAccessible using nearest neighbor search RealRandomAccessible< FloatType > realRandomAccessible = Views.interpolate( search, new NearestNeighborSearchInterpolatorFactory< FloatType >() );  // convert it into a RandomAccessible which can be displayed RandomAccessible< FloatType > randomAccessible = Views.raster( realRandomAccessible );  // set the initial interval as area to view RandomAccessibleInterval< FloatType > view = Views.interval( randomAccessible, interval );  // display the view ImageJFunctions.show( view );  // compute a gauss on it Img< FloatType > convolved = new ArrayImgFactory< FloatType >().create( interval, new FloatType() );  Gauss.inFloat( new double[] { 3, 3 }, view, interval, convolved, new Point( view.numDimensions() ), convolved.factory() );  // display the view ImageJFunctions.show( convolved ); }  /** * Create a number of n-dimensional random points in a certain interval * having a random intensity 0...1 * * @param interval - the interval in which points are created * @param numPoints - the amount of points * * @return a RealPointSampleList (which is an IterableRealInterval) */ public static RealPointSampleList< FloatType > createRandomPoints( RealInterval interval, int numPoints ) { // the number of dimensions int numDimensions = interval.numDimensions();  // a random number generator Random rnd = new Random( System.currentTimeMillis() );  // a list of Samples with coordinates RealPointSampleList< FloatType > elements = new RealPointSampleList<FloatType>( numDimensions );  for ( int i = 0; i < numPoints; ++i ) { RealPoint point = new RealPoint( numDimensions );  for ( int d = 0; d < numDimensions; ++d ) point.setPosition( rnd.nextDouble() * ( interval.realMax( d ) - interval.realMin( d ) ) + interval.realMin( d ), d );  // add a new element with a random intensity in the range 0...1 elements.add( point, new FloatType( rnd.nextFloat() ) ); }  return elements; }  public static void main( String[] args ) { // open an ImageJ window new ImageJ();  // run the example new Example8a(); }}</source>
=== Example 8b - Randomly sample an existing image and display it ===
''Shows the result of sparse sampling of an existing image using a varying number of random samples. The upper panel shows the rendering using nearest neighbor interpolation, the lower panel uses an interpolated, distance-weighted value of the k nearest neighbors relative to each sampled location (i.e. each pixel).''
'''{{GitHubGitHubEmbed|org=imglib|repo=imglib-tutorials|source=Example8b.java|label=Example8b.java}}'''<source lang="java">import ij.ImageJ;import io.scif.img.ImgIOException;import io.scif.img.ImgOpener; import java.util.Random; import net.imglib2.Interval;import net.imglib2.IterableRealInterval;import net.imglib2.KDTree;import net.imglib2.RandomAccessible;import net.imglib2.RandomAccessibleInterval;import net.imglib2.RealInterval;import net.imglib2.RealPoint;import net.imglib2.RealPointSampleList;import net.imglib2.RealRandomAccess;import net.imglib2.RealRandomAccessible;import net.imglib2.img.Img;import net.imglib2.img.display.imagej.ImageJFunctions;import net.imglib2.interpolation.neighborsearch.InverseDistanceWeightingInterpolatorFactory;import net.imglib2.interpolation.neighborsearch.NearestNeighborSearchInterpolatorFactory;import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory;import net.imglib2.neighborsearch.KNearestNeighborSearch;import net.imglib2.neighborsearch.KNearestNeighborSearchOnKDTree;import net.imglib2.neighborsearch.NearestNeighborSearch;import net.imglib2.neighborsearch.NearestNeighborSearchOnKDTree;import net.imglib2.type.Type;import net.imglib2.type.numeric.RealType;import net.imglib2.type.numeric.real.FloatType;import net.imglib2.view.Views; /** * Working with sparse data, sample an existing image at random locations * and render it again using an increasing number of samples */public class Example8b{ public Example8b() throws ImgIOException { // open with ImgOpener using a FloatType Img< FloatType > img = new ImgOpener().openImg( "DrosophilaWingSmall.tif", new FloatType() );  // show the image ImageJFunctions.show( img );  // use linear interpolation to convert the input into a RealRandomAccessible RealRandomAccessible< FloatType > realRandomAccessible = Views.interpolate( Views.extendMirrorSingle( img ), new NLinearInterpolatorFactory< FloatType >() );  // sample the image with an increasing number of random points and display the result for ( int numPoints = 2; numPoints <= 32768; numPoints = numPoints * 4 ) { // the result when we use nearest neighbor interpolation ImageJFunctions.show( randomSampling( realRandomAccessible, img, numPoints ), numPoints +" points (NN)" );  // the result when use a distance weighted interpolation of the 20 nearest neighbors ImageJFunctions.show( randomSamplingKNearest( realRandomAccessible, img, numPoints ), numPoints + " points (KNN)" ); } /** * Sample randomly n points from the input and display the interpolated result * using nearest neighbors * * @param input - the input data * @param interval - the size of the input (where to collect random samples) * @param numPoints - how many points to sample * * @return - a RandomAccessibleInterval of the same size as the input, * rendered from the sparse data */ public < T extends Type< T > > RandomAccessibleInterval< T > randomSampling( RealRandomAccessible< T > input, Interval interval, int numPoints ) { // create an IterableRealInterval IterableRealInterval< T > realInterval = sampleRandomPoints( input, interval, numPoints );  // using nearest neighbor search we will be able to return a value an any position in space NearestNeighborSearch< T > search = new NearestNeighborSearchOnKDTree< T >( new KDTree< T > ( realInterval ) );  // make it into RealRandomAccessible using nearest neighbor search RealRandomAccessible< T > realRandomAccessible = Views.interpolate( search, new NearestNeighborSearchInterpolatorFactory< T >() );  // convert it into a RandomAccessible which can be displayed RandomAccessible< T > randomAccessible = Views.raster( realRandomAccessible );  // set the initial interval as area to view return Views.interval( randomAccessible, interval ); }  /** * Sample randomly n points from the input and display the interpolated result using * distance-weighted interpolation of 20 nearest neighbors * * @param input - the input data * @param interval - the size of the input (where to collect random samples) * @param numPoints - how many points to sample * * @return - a RandomAccessibleInterval of the same size as the input, * rendered from the sparse data */ public < T extends RealType< T > > RandomAccessibleInterval< T > randomSamplingKNearest( RealRandomAccessible< T > input, Interval interval, int numPoints ) { // create an IterableRealInterval IterableRealInterval< T > realInterval = sampleRandomPoints( input, interval, numPoints );  // using nearest neighbor search we will be able to return a value an any position in space KNearestNeighborSearch< T > search = new KNearestNeighborSearchOnKDTree< T >( new KDTree< T > ( realInterval ), Math.min( 20, (int)realInterval.size() ) );  // make it into RealRandomAccessible using nearest neighbor search RealRandomAccessible< T > realRandomAccessible = Views.interpolate( search, new InverseDistanceWeightingInterpolatorFactory< T >() );  // convert it into a RandomAccessible which can be displayed RandomAccessible< T > randomAccessible = Views.raster( realRandomAccessible );  // set the initial interval as area to view return Views.interval( randomAccessible, interval ); }  /** * Sample a number of n-dimensional random points in a certain interval having a * random intensity 0...1 * * @param interval - the interval in which points are created * @param numPoints - the amount of points * * @return a RealPointSampleList (which is an IterableRealInterval) */ public static < T extends Type< T > > RealPointSampleList< T > sampleRandomPoints( RealRandomAccessible< T > input, RealInterval interval, int numPoints ) { // the number of dimensions int numDimensions = interval.numDimensions();  // a random number generator Random rnd = new Random( 1332441549191l );  // a list of Samples with coordinates RealPointSampleList< T > elements = new RealPointSampleList< T >( numDimensions );  // a random accessible in the image data to grep the right value RealRandomAccess< T > realRandomAccess = input.realRandomAccess();  for ( int i = 0; i < numPoints; ++i ) { RealPoint point = new RealPoint( numDimensions );  for ( int d = 0; d < numDimensions; ++d ) point.setPosition( rnd.nextDouble() * ( interval.realMax( d ) - interval.realMin( d ) ) + interval.realMin( d ), d );  realRandomAccess.setPosition( point );  // add a new element with a random intensity in the range 0...1 elements.add( point, realRandomAccess.get().copy() ); }  return elements; }  public static void main( String[] args ) throws ImgIOException { // open an ImageJ window new ImageJ();  // run the example new Example8b(); }}</source>
[[Category:ImgLib]]
[[Category:Tutorials]]
Bureaucrat, emailconfirmed, incoming, administrator, uploaders
11,833
edits