Skip to content

Instantly share code, notes, and snippets.

@ctrueden
Created June 18, 2019 18:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctrueden/fcdf93f0aef4db290f982d8df2e90b39 to your computer and use it in GitHub Desktop.
Save ctrueden/fcdf93f0aef4db290f982d8df2e90b39 to your computer and use it in GitHub Desktop.
Generate an image from a function in ImageJ
#@ Long(value = 3000) size
import java.util.function.BiConsumer
import net.imglib2.img.display.imagej.ImageJFunctions
import net.imglib2.position.FunctionRandomAccessible
import net.imglib2.type.numeric.integer.UnsignedByteType
import net.imglib2.view.Views
// Define a function in 2-space.
ndim = 2
t = new UnsignedByteType()
typeSupplier = { -> t }
BiConsumer triangleFunction = { l, type ->
x = l.getLongPosition(0)
y = l.getLongPosition(1)
foreground = 2 * x + y < size || 2 * (size - x) + y < size
type.setReal(foreground ? 255 : 0)
}
ra = new FunctionRandomAccessible(ndim, triangleFunction, typeSupplier)
// Bound the function.
long[] min = [0, 0]
long[] max = [size - 1, size - 1]
rai = Views.interval(ra, min, max)
// Convert the ImgLib2 image to an ImageJ1 ImagePlus.
imp = ImageJFunctions.wrapUnsignedByte(rai, "Triangle")
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import ij.ImagePlus;
import net.imglib2.Localizable;
import net.imglib2.RandomAccessible;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.position.FunctionRandomAccessible;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.view.Views;
import org.scijava.ItemIO;
import org.scijava.command.Command;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
@Plugin(type = Command.class)
public class Generative_Image implements Command {
@Parameter
private long size = 3000;
@Parameter(type = ItemIO.OUTPUT)
private ImagePlus imp;
@Override
public void run() {
// Define a function in 2-space.
int ndim = 2;
UnsignedByteType t = new UnsignedByteType();
Supplier<UnsignedByteType> typeSupplier = () -> t;
BiConsumer<Localizable, UnsignedByteType> triangleFunction = (l, type) -> {
long x = l.getLongPosition(0);
long y = l.getLongPosition(1);
boolean foreground = 2 * x + y < size || 2 * (size - x) + y < size;
type.setReal(foreground ? 255 : 0);
};
FunctionRandomAccessible<UnsignedByteType> ra = new FunctionRandomAccessible<>(ndim, triangleFunction, typeSupplier);
// Bound the function.
long[] min = {0, 0};
long[] max = {size - 1, size - 1};
RandomAccessibleInterval<UnsignedByteType> rai = Views.interval(ra, min, max);
// Convert the ImgLib2 image to an ImageJ1 ImagePlus.
imp = ImageJFunctions.wrapUnsignedByte(rai, "Triangle");
}
}
@ctrueden
Copy link
Author

The Groovy script becomes very slow for large size, due to the lambda being interpreted every time. The Java command is much faster, on the order of seconds instead of minutes for a 30000 x 30000 image, thanks to Java's Just-in-Time compiler with type-safe lambda.

@hadim
Copy link

hadim commented Jun 18, 2019

@ctrueden
Copy link
Author

ctrueden commented Jun 18, 2019

Sorry for the confusion. I used 3000 to test it initially, then changed it to 30000 when I was confident it worked correctly. I think 3000 is a good default because it completes relatively quickly. But what I wrote above is correct: for a size of 30000, the Groovy script is much slower than the Java version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment