use of ij.ImagePlus in project TrakEM2 by trakem2.
the class Segmentation method fastMarching.
public static Bureaucrat fastMarching(final AreaWrapper aw, final Layer layer, final Rectangle srcRect, final int x_p_w, final int y_p_w, final List<Runnable> post_tasks) {
// Capture pointers before they are set to null
final AreaContainer ac = (AreaContainer) aw.getSource();
final AffineTransform source_aff = aw.getSource().getAffineTransform();
final Rectangle box = new Rectangle(x_p_w - Segmentation.fmp.width / 2, y_p_w - Segmentation.fmp.height / 2, Segmentation.fmp.width, Segmentation.fmp.height);
Bureaucrat burro = Bureaucrat.create(new Worker.Task("Fast marching") {
public void exec() {
// Capture image as large as the fmp width,height centered on x_p_w,y_p_w
Utils.log2("fmp box is " + box);
ImagePlus imp = new ImagePlus("", Patch.makeFlatImage(ImagePlus.GRAY8, layer, box, 1.0, (Collection) layer.getDisplayables(Patch.class, new Area(box), true), Color.black));
// Bandpass filter
if (fmp.apply_bandpass_filter) {
IJ.run(imp, "Bandpass Filter...", "filter_large=" + fmp.low_frequency_threshold + " filter_small=" + fmp.high_frequency_threshold + " suppress=None tolerance=5" + (fmp.autoscale_after_filtering ? " autoscale" : "") + (fmp.saturate_when_autoscaling ? " saturate" : ""));
}
// Setup seed point
PointRoi roi = new PointRoi(box.width / 2, box.height / 2);
imp.setRoi(roi);
Utils.log2("imp: " + imp);
Utils.log2("proi: " + imp.getRoi() + " " + Utils.toString(new int[] { x_p_w - srcRect.x, y_p_w - srcRect.y }));
// Setup state
ImageContainer ic = new ImageContainer(imp);
StateContainer state = new StateContainer();
state.setROI(roi, ic.getWidth(), ic.getHeight(), ic.getImageCount(), imp.getCurrentSlice());
state.setExpansionToInside(false);
// Run FastMarching
final FastMarching fm = new FastMarching(ic, null, state, true, fmp.fm_grey, fmp.fm_dist, fmp.apply_grey_value_erosion);
final int max_iterations = fmp.max_iterations;
final int iter_inc = fmp.iter_inc;
for (int i = 0; i < max_iterations; i++) {
if (Thread.currentThread().isInterrupted()) {
return;
}
if (!fm.step(iter_inc))
break;
}
// Extract ROI
setTaskName("Adding area");
final ArrayList<Coordinate> vc = fm.getStateContainer().getXYZ(false);
if (0 == vc.size()) {
Utils.log("No area growth.");
return;
}
final Area area = new Area();
Coordinate first = vc.remove(0);
final Rectangle r = new Rectangle(first.x, first.y, 1, 1);
int count = 0;
// Scan and add line-wise
for (final Coordinate c : vc) {
count++;
if (c.y == r.y && c.x == r.x + 1) {
// same line:
r.width += 1;
continue;
} else {
// add previous one
area.add(new Area(r));
}
// start new line:
r.x = c.x;
r.y = c.y;
r.width = 1;
if (0 == count % 1024 && Thread.currentThread().isInterrupted()) {
return;
}
}
// add last:
area.add(new Area(r));
/*
// Trying from the image mask: JUST AS SLOW
final byte[] b = (byte[]) fm.getStateContainer().getIPMask()[0].getPixels();
final int w = imp.getWidth();
for (int i=0; i<b.length; i++) {
if (0 == b[i]) {
r.x = i%w;
r.y = i/w;
area.add(new Area(r));
}
}
*/
/* // DOESN'T FILL?
// Trying to just get the contour, and then filling holes
for (final Coordinate c : fm.getStateContainer().getXYZ(true)) {
r.x = c.x;
r.y = c.y;
area.add(new Area(r));
}
Polygon pol = new Polygon();
final float[] coords = new float[6];
for (PathIterator pit = area.getPathIterator(null); !pit.isDone(); ) {
switch (pit.currentSegment(coords)) {
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
pol.addPoint((int)coords[0], (int)coords[1]);
break;
case PathIterator.SEG_CLOSE:
area.add(new Area(pol));
// prepare next:
pol = new Polygon();
break;
default:
Utils.log2("WARNING: unhandled seg type.");
break;
}
pit.next();
if (pit.isDone()) {
break;
}
}
*/
// / FAILS because by now AreaWrapper's source is null
// aw.add(area, new AffineTransform(1, 0, 0, 1, box.x, box.y));
// Instead, compose an Area that is local to the AreaWrapper's area
final AffineTransform aff = new AffineTransform(1, 0, 0, 1, box.x, box.y);
try {
aff.preConcatenate(source_aff.createInverse());
} catch (NoninvertibleTransformException nite) {
IJError.print(nite);
return;
}
aw.getArea().add(area.createTransformedArea(aff));
ac.calculateBoundingBox(layer);
Display.repaint(layer);
}
}, layer.getProject());
if (null != post_tasks)
for (Runnable task : post_tasks) burro.addPostTask(task);
burro.goHaveBreakfast();
return burro;
}
use of ij.ImagePlus in project TrakEM2 by trakem2.
the class StitchingTEM method correlate.
/**
* @param scale For optimizing the speed of phase- and cross-correlation.
* @param percent_overlap The minimum chunk of adjacent images to compare with, will automatically and gradually increase to 100% if no good matches are found.
* @return a double[4] array containing:<ul>
* <li>x2: relative X position of the second Patch</li>
* <li>y2: relative Y position of the second Patch</li>
* <li>flag: ERROR or SUCCESS</li>
* <li>R: cross-correlation coefficient</li>
* </ul>
*/
public static double[] correlate(final Patch base, final Patch moving, final float percent_overlap, final double scale, final int direction, final double default_dx, final double default_dy, final double min_R) {
// PhaseCorrelation2D pc = null;
final double R = -2;
// final int limit = 5; // number of peaks to check in the PhaseCorrelation results
// final float min_R = 0.40f; // minimum R for phase-correlation to be considered good
// half this min_R will be considered good for cross-correlation
// Iterate until PhaseCorrelation correlation coefficient R is over 0.5, or there's no more
// image overlap to feed
// Utils.log2("min_R: " + min_R);
ImageProcessor ip1, ip2;
final Rectangle b1 = base.getBoundingBox(null);
final Rectangle b2 = moving.getBoundingBox(null);
final int w1 = b1.width, h1 = b1.height, w2 = b2.width, h2 = b2.height;
Roi roi1 = null, roi2 = null;
float overlap = percent_overlap;
double dx = default_dx, dy = default_dy;
do {
// create rois for the stripes
switch(direction) {
case TOP_BOTTOM:
// bottom
roi1 = new Roi(0, h1 - (int) (h1 * overlap), w1, (int) (h1 * overlap));
// top
roi2 = new Roi(0, 0, w2, (int) (h2 * overlap));
break;
case LEFT_RIGHT:
// right
roi1 = new Roi(w1 - (int) (w1 * overlap), 0, (int) (w1 * overlap), h1);
// left
roi2 = new Roi(0, 0, (int) (w2 * overlap), h2);
break;
}
// Utils.log2("roi1: " + roi1);
// Utils.log2("roi2: " + roi2);
// will apply the transform if necessary
ip1 = makeStripe(base, roi1, scale);
ip2 = makeStripe(moving, roi2, scale);
// new ImagePlus("roi1", ip1).show();
// new ImagePlus("roi2", ip2).show();
ip1.setPixels(ImageFilter.computeGaussianFastMirror(new FloatArray2D((float[]) ip1.getPixels(), ip1.getWidth(), ip1.getHeight()), 1.0).data);
ip2.setPixels(ImageFilter.computeGaussianFastMirror(new FloatArray2D((float[]) ip2.getPixels(), ip2.getWidth(), ip2.getHeight()), 1.0).data);
//
final ImagePlus imp1 = new ImagePlus("", ip1);
final ImagePlus imp2 = new ImagePlus("", ip2);
final PhaseCorrelationCalculator t = new PhaseCorrelationCalculator(imp1, imp2);
final PhaseCorrelationPeak peak = t.getPeak();
final double resultR = peak.getCrossCorrelationPeak();
final int[] peackPostion = peak.getPosition();
final java.awt.Point shift = new java.awt.Point(peackPostion[0], peackPostion[1]);
// Utils.log2("overlap: " + overlap + " R: " + resultR + " shift: " + shift + " dx,dy: " + dx + ", " + dy);
if (resultR >= min_R) {
// success
final int success = SUCCESS;
switch(direction) {
case TOP_BOTTOM:
// boundary checks:
// if (shift.y/scale > default_dy) success = ERROR;
dx = shift.x / scale;
dy = roi1.getBounds().y + shift.y / scale;
break;
case LEFT_RIGHT:
// boundary checks:
// if (shift.x/scale > default_dx) success = ERROR;
dx = roi1.getBounds().x + shift.x / scale;
dy = shift.y / scale;
break;
}
// Utils.log2("R: " + resultR + " shift: " + shift + " dx,dy: " + dx + ", " + dy);
return new double[] { dx, dy, success, resultR };
}
// new ImagePlus("roi1", ip1.duplicate()).show();
// new ImagePlus("roi2", ip2.duplicate()).show();
// try { Thread.sleep(1000000000); } catch (Exception e) {}
// increase for next iteration
// increments of 10%
overlap += 0.10;
} while (R < min_R && Math.abs(overlap - 1.0f) < 0.001f);
// Phase-correlation failed, fall back to cross-correlation with a safe overlap
overlap = percent_overlap * 2;
if (overlap > 1.0f)
overlap = 1.0f;
switch(direction) {
case TOP_BOTTOM:
// bottom
roi1 = new Roi(0, h1 - (int) (h1 * overlap), w1, (int) (h1 * overlap));
// top
roi2 = new Roi(0, 0, w2, (int) (h2 * overlap));
break;
case LEFT_RIGHT:
// right
roi1 = new Roi(w1 - (int) (w1 * overlap), 0, (int) (w1 * overlap), h1);
// left
roi2 = new Roi(0, 0, (int) (w2 * overlap), h2);
break;
}
// use one third of the size used for phase-correlation though! Otherwise, it may take FOREVER
final double scale_cc = scale / 3.0f;
ip1 = makeStripe(base, roi1, scale_cc);
ip2 = makeStripe(moving, roi2, scale_cc);
// gaussian blur them before cross-correlation
ip1.setPixels(ImageFilter.computeGaussianFastMirror(new FloatArray2D((float[]) ip1.getPixels(), ip1.getWidth(), ip1.getHeight()), 1f).data);
ip2.setPixels(ImageFilter.computeGaussianFastMirror(new FloatArray2D((float[]) ip2.getPixels(), ip2.getWidth(), ip2.getHeight()), 1f).data);
// new ImagePlus("CC roi1", ip1).show();
// new ImagePlus("CC roi2", ip2).show();
final CrossCorrelation2D cc = new CrossCorrelation2D(ip1, ip2, false);
double[] cc_result = null;
switch(direction) {
case TOP_BOTTOM:
cc_result = cc.computeCrossCorrelationMT(0.9, 0.3, false);
break;
case LEFT_RIGHT:
cc_result = cc.computeCrossCorrelationMT(0.3, 0.9, false);
break;
}
if (cc_result[2] > min_R / 2) {
// accepting if R is above half the R accepted for Phase Correlation
// success
final int success = SUCCESS;
switch(direction) {
case TOP_BOTTOM:
// boundary checks:
// if (cc_result[1]/scale_cc > default_dy) success = ERROR;
dx = cc_result[0] / scale_cc;
dy = roi1.getBounds().y + cc_result[1] / scale_cc;
break;
case LEFT_RIGHT:
// boundary checks:
// if (cc_result[0]/scale_cc > default_dx) success = ERROR;
dx = roi1.getBounds().x + cc_result[0] / scale_cc;
dy = cc_result[1] / scale_cc;
break;
}
// Utils.log2("\trois: \t" + roi1 + "\n\t\t" + roi2);
return new double[] { dx, dy, success, cc_result[2] };
}
// Utils.log2("Using default");
return new double[] { default_dx, default_dy, ERROR, 0 };
// / ABOVE: boundary checks don't work if default_dx,dy are zero! And may actually be harmful in anycase
}
use of ij.ImagePlus in project TrakEM2 by trakem2.
the class ContrastEnhancerWrapper method apply.
public boolean apply(final Collection<Displayable> patches_) {
if (null == patches_)
return false;
// Create appropriate patch list
ArrayList<Patch> patches = new ArrayList<Patch>();
for (final Displayable d : patches_) {
if (d.getClass() == Patch.class)
patches.add((Patch) d);
}
if (0 == patches.size())
return false;
// Check that all images are of the same size and type
Patch firstp = (Patch) patches.get(0);
final int ptype = firstp.getType();
final double pw = firstp.getOWidth();
final double ph = firstp.getOHeight();
for (final Patch p : patches) {
if (p.getType() != ptype) {
// can't continue
Utils.log("Can't homogenize histograms: images are not all of the same type.\nFirst offending image is: " + p);
return false;
}
if (!equalize && 0 == stats_mode && p.getOWidth() != pw || p.getOHeight() != ph) {
Utils.log("Can't homogenize histograms: images are not all of the same size.\nFirst offending image is: " + p);
return false;
}
}
try {
if (equalize) {
for (final Patch p : patches) {
if (Thread.currentThread().isInterrupted())
return false;
p.appendFilters(new IFilter[] { new EqualizeHistogram() });
/*
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 3);
ImageProcessor ip = p.getImageProcessor().duplicate(); // a throw-away copy
if (this.from_existing_min_and_max) {
ip.setMinAndMax(p.getMin(), p.getMax());
}
ce.equalize(ip);
p.setMinAndMax(ip.getMin(), ip.getMax());
*/
// submit for regeneration
p.getProject().getLoader().decacheImagePlus(p.getId());
regenerateMipMaps(p);
}
return true;
}
// Else, call stretchHistogram with an appropriate stats object
final ImageStatistics stats;
if (1 == stats_mode) {
// use each image independent stats
stats = null;
} else if (0 == stats_mode) {
// use stack statistics
final ArrayList<Patch> sub = new ArrayList<Patch>();
if (use_full_stack) {
sub.addAll(patches);
} else {
// build stack statistics, ordered by stdDev
final SortedMap<Stats, Patch> sp = Collections.synchronizedSortedMap(new TreeMap<Stats, Patch>());
Process.progressive(patches, new TaskFactory<Patch, Stats>() {
public Stats process(final Patch p) {
if (Thread.currentThread().isInterrupted())
return null;
ImagePlus imp = p.getImagePlus();
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 2);
Stats s = new Stats(imp.getStatistics());
sp.put(s, p);
return s;
}
});
if (Thread.currentThread().isInterrupted())
return false;
final ArrayList<Patch> a = new ArrayList<Patch>(sp.values());
final int count = a.size();
if (count < 3) {
sub.addAll(a);
} else if (3 == count) {
// the middle one
sub.add(a.get(1));
} else if (4 == count) {
sub.addAll(a.subList(1, 3));
} else if (count > 4) {
int first = (int) (count / 4.0 + 0.5);
int last = (int) (count / 4.0 * 3 + 0.5);
sub.addAll(a.subList(first, last));
}
}
stats = new StackStatistics(new PatchStack(sub.toArray(new Patch[sub.size()]), 1));
} else {
stats = reference_stats;
}
final Calibration cal = patches.get(0).getLayer().getParent().getCalibrationCopy();
Process.progressive(patches, new TaskFactory<Patch, Object>() {
public Object process(final Patch p) {
if (Thread.currentThread().isInterrupted())
return null;
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 3);
// a throw-away copy
ImageProcessor ip = p.getImageProcessor().duplicate();
if (ContrastEnhancerWrapper.this.from_existing_min_and_max) {
ip.setMinAndMax(p.getMin(), p.getMax());
}
ImageStatistics st = stats;
if (null == stats) {
Utils.log2("Null stats, using image's self");
st = ImageStatistics.getStatistics(ip, Measurements.MIN_MAX, cal);
}
ce.stretchHistogram(ip, saturated, st);
// This is all we care about from stretching the histogram:
p.setMinAndMax(ip.getMin(), ip.getMax());
regenerateMipMaps(p);
return null;
}
});
} catch (Exception e) {
IJError.print(e);
return false;
}
return true;
}
use of ij.ImagePlus in project TrakEM2 by trakem2.
the class IntegralHistogram2d method view.
@SuppressWarnings("unused")
private static final void view(final long[] hist, final int w1, final int h1, final int nBins) {
final float[] pixels = new float[w1 * h1 * nBins];
for (int i = 0; i < hist.length; ++i) {
pixels[i] = hist[i];
}
new ImagePlus("Integral Histogram", new FloatProcessor(w1 * nBins, h1, pixels)).show();
}
use of ij.ImagePlus in project TrakEM2 by trakem2.
the class LayerStack method getProcessor.
/**
* Returns an ImageProcessor for the specified slice,
* where {@code 1<=n<=nslices}. Returns null if the stack is empty.
*/
@Override
public ImageProcessor getProcessor(int n) {
if (n < 1 || n > layers.size())
return null;
// Create a flat image on the fly with everything on it, and return its processor.
final Layer layer = layers.get(n - 1);
final Loader loader = layer.getProject().getLoader();
Long cid;
synchronized (id_cache) {
cid = id_cache.get(layer.getId());
if (null == cid) {
cid = loader.getNextTempId();
id_cache.put(layer.getId(), cid);
}
}
ImageProcessor ip;
synchronized (cid) {
ImagePlus imp = loader.getCachedImagePlus(cid);
if (null == imp || null == imp.getProcessor() || null == imp.getProcessor().getPixels()) {
ip = loader.getFlatImage(layer, this.roi, this.scale, this.c_alphas, this.type, this.clazz, null).getProcessor();
if (invert)
ip.invert();
loader.cacheImagePlus(cid, new ImagePlus("", ip));
} else
ip = imp.getProcessor();
}
return ip;
}
Aggregations