use of ij.process.ShortProcessor in project TrakEM2 by trakem2.
the class ExportUnsignedShort method exportTiles.
/**
* Create constant size tiles that carpet the areas of the {@code layer} where there are images;
* these tiles are returned in a lazy sequence of {@link Callable} objects that create a tripled
* consisting of the {@link ShortProcessor} and the X and Y pixel coordinates of that tile.
*
* @param layer The layer to export images for
* @param tileWidth The width of the tiles to export
* @param tileHeight
* @return A lazy sequence of {@link Callable} instances, each holding a {@link Triple} that specifies the ShortProcessor,
* the X and the Y (both in world pixel uncalibrated coordinates).
*/
public static final Iterable<Callable<ExportedTile>> exportTiles(final Layer layer, final int tileWidth, final int tileHeight, final boolean visible_only) {
final ArrayList<Displayable> patches = layer.getDisplayables(Patch.class, visible_only);
// If the Layer lacks images, return an empty sequence.
if (patches.isEmpty()) {
return Collections.emptyList();
}
/* calculate intensity transfer */
final ArrayList<PatchIntensityRange> patchIntensityRanges = new ArrayList<PatchIntensityRange>();
double min_ = Double.MAX_VALUE;
double max_ = -Double.MAX_VALUE;
for (final Displayable d : patches) {
final Patch patch = (Patch) d;
final PatchIntensityRange pir = new PatchIntensityRange(patch);
if (pir.min < min_)
min_ = pir.min;
if (pir.max > max_)
max_ = pir.max;
patchIntensityRanges.add(pir);
}
final double min = min_;
final double max = max_;
/* Create lazy sequence that creates Callable instances. */
final Rectangle box = layer.getMinimalBoundingBox(Patch.class, visible_only).intersection(layer.getParent().get2DBounds());
final int nCols = (int) Math.ceil(box.width / (double) tileWidth);
final int nRows = (int) Math.ceil(box.height / (double) tileHeight);
final double minI = -min * 65535.0 / (max - min);
final double maxI = (1.0 - min) * 65535.0 / (max - min);
return new Iterable<Callable<ExportedTile>>() {
@Override
public Iterator<Callable<ExportedTile>> iterator() {
return new Iterator<Callable<ExportedTile>>() {
// Internal state
private int row = 0, col = 0, x0 = box.x, y0 = box.y;
private final ArrayList<PatchIntensityRange> ps = new ArrayList<PatchIntensityRange>();
{
// Constructor body. Prepare to be able to answer "hasNext()"
findNext();
}
private final void findNext() {
// Iterate until finding a tile that intersects one or more patches
ps.clear();
while (true) {
if (nRows == row) {
// End of domain
break;
}
x0 = box.x + col * tileWidth;
y0 = box.y + row * tileHeight;
final Rectangle tileBounds = new Rectangle(x0, y0, tileWidth, tileHeight);
for (final PatchIntensityRange pir : patchIntensityRanges) {
if (pir.patch.getBoundingBox().intersects(tileBounds)) {
ps.add(pir);
}
}
// Prepare next iteration
col += 1;
if (nCols == col) {
col = 0;
row += 1;
}
if (ps.size() > 0) {
// Ready for next iteration
break;
}
}
}
@Override
public boolean hasNext() {
return ps.size() > 0;
}
@Override
public Callable<ExportedTile> next() {
// Capture state locally
final ArrayList<PatchIntensityRange> pirs = new ArrayList<PatchIntensityRange>(ps);
final int x = x0;
final int y = y0;
// Advance
findNext();
return new Callable<ExportedTile>() {
@Override
public ExportedTile call() throws Exception {
final ShortProcessor sp = new ShortProcessor(tileWidth, tileHeight);
sp.setMinAndMax(minI, maxI);
for (final PatchIntensityRange pir : pirs) {
map(new PatchTransform(pir), x, y, mapIntensities(pir, min, max), sp);
}
return new ExportedTile(sp, x, y, minI, maxI);
}
};
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
use of ij.process.ShortProcessor in project TrakEM2 by trakem2.
the class ExportUnsignedShort method exportTEST.
public static final void exportTEST(final Layer layer, final int tileWidth, final int tileHeight) {
/* calculate intensity transfer */
final ArrayList<Displayable> patches = layer.getDisplayables(Patch.class);
final ArrayList<PatchIntensityRange> patchIntensityRanges = new ArrayList<PatchIntensityRange>();
double min = Double.MAX_VALUE;
double max = -Double.MAX_VALUE;
for (final Displayable d : patches) {
final Patch patch = (Patch) d;
final PatchIntensityRange pir = new PatchIntensityRange(patch);
if (pir.min < min)
min = pir.min;
if (pir.max > max)
max = pir.max;
patchIntensityRanges.add(pir);
}
/* render tiles */
/* TODO Do not render them into a stack but save them as files */
final ImageStack stack = new ImageStack(tileWidth, tileHeight);
ImagePlus imp = null;
final double minI = -min * 65535.0 / (max - min);
final double maxI = (1.0 - min) * 65535.0 / (max - min);
// ij.IJ.log("min, max: " + min + ", " + max + ", minI, maxI: " + minI + ", " + maxI);
final int nc = (int) Math.ceil(layer.getLayerWidth() / tileWidth);
final int nr = (int) Math.ceil(layer.getLayerHeight() / tileHeight);
for (int r = 0; r < nr; ++r) {
final int y0 = r * tileHeight;
for (int c = 0; c < nc; ++c) {
final int x0 = c * tileWidth;
final Rectangle box = new Rectangle(x0, y0, tileWidth, tileHeight);
final ShortProcessor sp = new ShortProcessor(tileWidth, tileHeight);
sp.setMinAndMax(minI, maxI);
for (final PatchIntensityRange pir : patchIntensityRanges) {
if (pir.patch.getBoundingBox().intersects(box))
map(new PatchTransform(pir), x0, y0, mapIntensities(pir, min, max), sp);
}
stack.addSlice(r + ", " + c, sp);
if (null == imp && stack.getSize() > 1) {
imp = new ImagePlus("tiles", stack);
imp.show();
}
if (null != imp) {
imp.setSlice(stack.getSize());
imp.updateAndDraw();
}
}
}
if (null == imp) {
// single-slice, non-StackWindow
new ImagePlus("tiles", stack).show();
}
}
use of ij.process.ShortProcessor in project TrakEM2 by trakem2.
the class RobustNormalizeLocalContrast method run.
public static final void run(final ImageProcessor ip, final int scaleLevel, final int brx1, final int bry1, final float stds1, final int brx2, final int bry2, final float stds2) {
final PixelSetter setter;
if (ByteProcessor.class.isInstance(ip))
setter = new ByteSetter((ByteProcessor) ip);
else if (ShortProcessor.class.isInstance(ip))
setter = new ShortSetter((ShortProcessor) ip);
else
setter = new FloatSetter(ip);
final int scale = (int) Util.pow(2, scaleLevel);
final int scale2 = scale / 2;
final double[] f = new double[scale];
for (int i = 0; i < scale; ++i) f[i] = (i + 0.5) / scale;
final int sbrx1 = brx1 / scale;
final int sbry1 = bry1 / scale;
final int sbrx2 = brx2 / scale;
final int sbry2 = bry2 / scale;
final int ipWidth = ip.getWidth();
final int ipHeight = ip.getHeight();
final double ipMin = ip.getMin();
final double ipLength = ip.getMax() - ipMin;
FloatProcessor ipScaled = (FloatProcessor) ip.convertToFloat();
for (int i = 0; i < scaleLevel; ++i) ipScaled = Downsampler.downsampleFloatProcessor(ipScaled);
final FloatProcessor std = ipScaled;
// new ImagePlus("downsampled", std.duplicate() ).show();
RemoveOutliers.run(std, sbrx1, sbry1, stds1);
// new ImagePlus("outlier-filtered", std.duplicate() ).show();
final BlockStatistics bs = new BlockStatistics(std);
bs.mean(sbrx2, sbry2);
// new ImagePlus("mean", std.duplicate() ).show();
final FloatProcessor mean = (FloatProcessor) std.duplicate();
bs.std(sbrx2, sbry2);
// new ImagePlus("std", std.duplicate() ).show();
final int w = mean.getWidth();
final int h = mean.getHeight();
final ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final ArrayList<Future<?>> tasks = new ArrayList<Future<?>>();
/* the big inside */
for (int y = 1; y < h; ++y) {
final int ya = y - 1;
final int yb = y;
tasks.add(exec.submit(new Runnable() {
public final void run() {
for (int x = 1; x < w; ++x) {
final int xa = x - 1;
final float meanA = mean.getf(xa, ya);
final float meanB = mean.getf(x, ya);
final float meanC = mean.getf(xa, yb);
final float meanD = mean.getf(x, yb);
final float stdA = std.getf(xa, ya);
final float stdB = std.getf(x, ya);
final float stdC = std.getf(xa, yb);
final float stdD = std.getf(x, yb);
int ys = yb * scale - scale2;
final int xss = x * scale - scale2;
for (int yi = 0; yi < scale; ++ys, ++yi) for (int xs = xss, xi = 0; xi < scale; ++xs, ++xi) {
final double meanAB = meanA * f[xi] + meanB * (1.0 - f[xi]);
final double meanCD = meanC * f[xi] + meanD * (1.0 - f[xi]);
final double meanABCD = meanAB * f[yi] + meanCD * (1.0 - f[yi]);
final double stdAB = stdA * f[xi] + stdB * (1.0 - f[xi]);
final double stdCD = stdC * f[xi] + stdD * (1.0 - f[xi]);
final double stdABCD = stdAB * f[yi] + stdCD * (1.0 - f[yi]);
final double d = stds2 * stdABCD;
final double min = meanABCD - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
}
}
}));
}
for (Future<?> task : tasks) {
try {
task.get();
} catch (InterruptedException e) {
exec.shutdownNow();
return;
} catch (ExecutionException e) {
exec.shutdownNow();
return;
}
}
tasks.clear();
exec.shutdown();
/* top and bottom */
for (int x = 1; x < w; ++x) {
final int xa = x - 1;
final float meanA = mean.getf(xa, 0);
final float meanB = mean.getf(x, 0);
final float meanC = mean.getf(xa, h - 1);
final float meanD = mean.getf(x, h - 1);
final float stdA = std.getf(xa, 0);
final float stdB = std.getf(x, 0);
final float stdC = std.getf(xa, h - 1);
final float stdD = std.getf(x, h - 1);
/* top */
final int xss = x * scale - scale2;
for (int ys = 0; ys < scale2; ++ys) for (int xs = xss, xi = 0; xi < scale; ++xs, ++xi) {
final double meanAB = meanA * f[xi] + meanB * (1.0 - f[xi]);
final double stdAB = stdA * f[xi] + stdB * (1.0 - f[xi]);
final double d = stds2 * stdAB;
final double min = meanAB - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
/* bottom */
for (int ys = h * scale - scale2; ys < ipHeight; ++ys) for (int xs = xss, xi = 0; xi < scale; ++xs, ++xi) {
final double meanCD = meanC * f[xi] + meanD * (1.0 - f[xi]);
final double stdCD = stdC * f[xi] + stdD * (1.0 - f[xi]);
final double d = stds2 * stdCD;
final double min = meanCD - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
}
final int xss = w * scale - scale2;
/* left and right */
for (int y = 1; y < h; ++y) {
final int ya = y - 1;
final float meanA = mean.getf(0, ya);
final float meanB = mean.getf(0, y);
final float meanC = mean.getf(w - 1, ya);
final float meanD = mean.getf(w - 1, y);
final float stdA = std.getf(0, ya);
final float stdB = std.getf(0, y);
final float stdC = std.getf(w - 1, ya);
final float stdD = std.getf(w - 1, y);
int ys = y * scale - scale2;
for (int yi = 0; yi < scale; ++ys, ++yi) {
/* left */
for (int xs = 0; xs < scale2; ++xs) {
final double meanAB = meanA * f[yi] + meanB * (1.0 - f[yi]);
final double stdAB = stdA * f[yi] + stdB * (1.0 - f[yi]);
final double d = stds2 * stdAB;
final double min = meanAB - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
/* right */
for (int xs = xss; xs < ipWidth; ++xs) {
final double meanCD = meanC * f[yi] + meanD * (1.0 - f[yi]);
final double stdCD = stdC * f[yi] + stdD * (1.0 - f[yi]);
final double d = stds2 * stdCD;
final double min = meanCD - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
}
}
/* corners */
final float meanA = mean.getf(0, 0);
final float meanB = mean.getf(w - 1, 0);
final float meanC = mean.getf(0, h - 1);
final float meanD = mean.getf(w - 1, h - 1);
final float stdA = std.getf(0, 0);
final float stdB = std.getf(w - 1, 0);
final float stdC = std.getf(0, h - 1);
final float stdD = std.getf(w - 1, h - 1);
for (int ys = 0; ys < scale2; ++ys) {
for (int xs = 0; xs < scale2; ++xs) {
final double d = stds2 * stdA;
final double min = meanA - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
for (int xs = xss; xs < ipWidth; ++xs) {
final double d = stds2 * stdB;
final double min = meanB - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
}
for (int ys = h * scale - scale2; ys < ipHeight; ++ys) {
for (int xs = 0; xs < scale2; ++xs) {
final double d = stds2 * stdC;
final double min = meanC - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
for (int xs = xss; xs < ipWidth; ++xs) {
final double d = stds2 * stdD;
final double min = meanD - d;
final int i = ys * ipWidth + xs;
setter.setf(i, (float) ((ip.getf(i) - min) / 2 / d * ipLength + ipMin));
}
}
// new ImagePlus( "processed", ip.duplicate() ).show();
}
use of ij.process.ShortProcessor in project TrakEM2 by trakem2.
the class Downsampler method downsampleShortProcessor.
public static final ShortProcessor downsampleShortProcessor(final ShortProcessor a) {
final int wa = a.getWidth();
final int ha = a.getHeight();
final int wa2 = wa + wa;
final int wb = wa / 2;
final int hb = ha / 2;
final int nb = hb * wb;
final ShortProcessor b = new ShortProcessor(wb, hb);
final short[] aPixels = (short[]) a.getPixels();
final short[] bPixels = (short[]) b.getPixels();
for (int ya = 0, yb = 0; yb < nb; ya += wa2, yb += wb) {
final int ya1 = ya + wa;
for (int xa = 0, xb = 0; xb < wb; xa += 2, ++xb) {
final int xa1 = xa + 1;
final int s = averageShort(ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels);
bPixels[yb + xb] = (short) s;
}
}
return b;
}
use of ij.process.ShortProcessor in project TrakEM2 by trakem2.
the class Patch method makeFlatImage.
/**
* Creates an ImageProcessor of the specified type.
* @param type Any of ImagePlus.GRAY_8, GRAY_16, GRAY_32 or COLOR_RGB.
* @param srcRect the box in world coordinates to make an image out of.
* @param scale may be up to 1.0.
* @param patches The list of patches to paint. The first gets painted first (at the bottom).
* @param background The color with which to paint the outsides where no image paints into.
* @param setMinAndMax defines whether the min and max of each Patch is set before pasting the Patch.
*
* For exporting while blending the display ranges (min,max) and respecting alpha masks, see {@link ExportUnsignedShort}.
*/
public static ImageProcessor makeFlatImage(final int type, final Layer layer, final Rectangle srcRect, final double scale, final Collection<Patch> patches, final Color background, final boolean setMinAndMax) {
final ImageProcessor ip;
final int W, H;
if (scale < 1) {
W = (int) (srcRect.width * scale);
H = (int) (srcRect.height * scale);
} else {
W = srcRect.width;
H = srcRect.height;
}
switch(type) {
case ImagePlus.GRAY8:
ip = new ByteProcessor(W, H);
break;
case ImagePlus.GRAY16:
ip = new ShortProcessor(W, H);
break;
case ImagePlus.GRAY32:
ip = new FloatProcessor(W, H);
break;
case ImagePlus.COLOR_RGB:
ip = new ColorProcessor(W, H);
break;
default:
Utils.logAll("Cannot create an image of type " + type + ".\nSupported types: 8-bit, 16-bit, 32-bit and RGB.");
return null;
}
// Fill with background
if (null != background && Color.black != background) {
ip.setColor(background);
ip.fill();
}
AffineModel2D sc = null;
if (scale < 1.0) {
sc = new AffineModel2D();
sc.set(scale, 0, 0, scale, 0, 0);
}
for (final Patch p : patches) {
// TODO patches seem to come in in inverse order---find out why
// A list to represent all the transformations that the Patch image has to go through to reach the scaled srcRect image
final CoordinateTransformList<CoordinateTransform> list = new CoordinateTransformList<CoordinateTransform>();
final AffineTransform at = new AffineTransform();
at.translate(-srcRect.x, -srcRect.y);
at.concatenate(p.getAffineTransform());
// 1. The coordinate tranform of the Patch, if any
if (p.hasCoordinateTransform()) {
final CoordinateTransform ct = p.getCoordinateTransform();
list.add(ct);
// Remove the translation in the patch_affine that the ct added to it
final Rectangle box = Patch.getCoordinateTransformBoundingBox(p, ct);
at.translate(-box.x, -box.y);
}
// 2. The affine transform of the Patch
final AffineModel2D patch_affine = new AffineModel2D();
patch_affine.set(at);
list.add(patch_affine);
// 3. The desired scaling
if (null != sc)
patch_affine.preConcatenate(sc);
final CoordinateTransformMesh mesh = new CoordinateTransformMesh(list, p.meshResolution, p.getOWidth(), p.getOHeight());
final mpicbg.ij.TransformMeshMapping<CoordinateTransformMesh> mapping = new mpicbg.ij.TransformMeshMapping<CoordinateTransformMesh>(mesh);
// 4. Convert the patch to the required type
ImageProcessor pi = p.getImageProcessor();
if (setMinAndMax) {
pi = pi.duplicate();
pi.setMinAndMax(p.min, p.max);
}
switch(type) {
case ImagePlus.GRAY8:
pi = pi.convertToByte(true);
break;
case ImagePlus.GRAY16:
pi = pi.convertToShort(true);
break;
case ImagePlus.GRAY32:
pi = pi.convertToFloat();
break;
default:
// ImagePlus.COLOR_RGB and COLOR_256
pi = pi.convertToRGB();
break;
}
/* TODO for taking into account independent min/max setting for each patch,
* we will need a mapping with an `intensity transfer function' to be implemented.
* --> EXISTS already as mpicbg/trakem2/transform/ExportUnsignedShort.java
*/
mapping.mapInterpolated(pi, ip);
}
return ip;
}
Aggregations