use of ini.trakem2.display.Layer 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 ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Blending method blendLayerWise.
public static final void blendLayerWise(final List<Layer> layers, final boolean respect_current_mask, final Filter<Patch> filter) {
for (final Layer layer : layers) {
final List<Patch> patches = layer.getAll(Patch.class);
final Set<Patch> s = new HashSet<Patch>();
if (null == filter) {
s.addAll(patches);
} else {
for (final Iterator<Patch> it = patches.iterator(); it.hasNext(); ) {
final Patch p = it.next();
if (filter.accept(p))
s.add(p);
}
}
blendPatches(s, respect_current_mask);
}
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class Blending method blendPatches.
public static final void blendPatches(final Set<Patch> patches, final boolean respect_current_mask) {
ExecutorService exe = null;
try {
if (null == patches || patches.size() < 2)
return;
final Layer layer = patches.iterator().next().getLayer();
for (final Patch p : patches) {
if (null != p.getCoordinateTransform()) {
Utils.log("CANNOT blend: at least one image has a coordinate transform.\nBlending of coordinate-transformed images will be enabled in the near future.");
return;
}
if (p.getLayer() != layer) {
Utils.log("CANNOT blend: all images must belong to the same layer!\n Otherwise the overlap cannot be computed.");
return;
}
}
final HashMap<Patch, TransformMesh> meshes = new HashMap<Patch, TransformMesh>();
for (final Patch p : patches) {
meshes.put(p, null == p.getCoordinateTransform() ? null : new TransformMesh(p.getCoordinateTransform(), p.getMeshResolution(), p.getOWidth(), p.getOHeight()));
}
exe = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final List<Future<?>> futures = Collections.synchronizedList(new ArrayList<Future<?>>());
final List<Future<?>> futures2 = Collections.synchronizedList(new ArrayList<Future<?>>());
// Cache the indices that determine overlap order within the layer
final HashMap<Patch, Integer> indices = new HashMap<Patch, Integer>();
int i = 0;
for (final Displayable d : layer.getDisplayables()) {
if (d.getClass() == Patch.class && patches.contains((Patch) d)) {
indices.put((Patch) d, i);
}
i += 1;
}
for (final Patch p : patches) {
if (Thread.currentThread().isInterrupted())
break;
futures.add(exe.submit(new Runnable() {
@Override
public void run() {
final int pLayerIndex = indices.get(p);
final Set<Patch> overlapping = new HashSet<Patch>();
for (final Patch op : patches) {
if (indices.get(op) < pLayerIndex)
overlapping.add(op);
}
if (setBlendingMask(p, overlapping, meshes, respect_current_mask)) {
futures2.add(p.updateMipMaps());
}
}
}, null));
}
// join all:
Utils.waitIfAlive(futures, false);
Utils.waitIfAlive(futures2, false);
} catch (final Exception e) {
IJError.print(e);
} finally {
if (null != exe)
exe.shutdown();
Display.repaint();
}
}
use of ini.trakem2.display.Layer 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;
}
use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.
the class FilterEditor method GUI.
public static final void GUI(final Collection<Patch> patches, final Patch reference) {
final ArrayList<FilterWrapper> filters = new ArrayList<FilterWrapper>();
// Find out if all images have the exact same filters
final StringBuilder sb = new StringBuilder();
final Patch ref = (null == reference ? patches.iterator().next() : reference);
final IFilter[] refFilters = ref.getFilters();
if (null != refFilters) {
// makes a copy of the IFilter
for (final IFilter f : refFilters) filters.add(new FilterWrapper(f));
}
//
for (final Patch p : patches) {
if (ref == p)
continue;
final IFilter[] fs = p.getFilters();
// ok
if (null == fs && null == refFilters)
continue;
if ((null != refFilters && null == fs) || (null == refFilters && null != fs) || (null != refFilters && null != fs && fs.length != refFilters.length)) {
sb.append("WARNING: patch #" + p.getId() + " has a different number of filters than reference patch #" + ref.getId());
continue;
}
// Compare each
for (int i = 0; i < refFilters.length; ++i) {
if (fs[i].getClass() != refFilters[i].getClass()) {
sb.append("WARNING: patch #" + p.getId() + " has a different filters than reference patch #" + ref.getId());
break;
}
// Does the filter have the same parameters?
if (!filters.get(i).sameParameterValues(new FilterWrapper(fs[i]))) {
sb.append("WARNING: patch #" + p.getId() + " has filter '" + fs[i].getClass().getSimpleName() + "' with different parameters than the reference patch #" + ref.getId());
}
}
}
if (sb.length() > 0) {
final GenericDialog gd = new GenericDialog("WARNING", null == Display.getFront() ? IJ.getInstance() : Display.getFront().getFrame());
gd.addMessage("Filters are not all the same for all images:");
gd.addTextAreas(sb.toString(), null, 20, 30);
final String[] s = new String[] { "Use the filters of the reference image", "Start from an empty list of filters" };
gd.addChoice("Do:", s, s[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
if (1 == gd.getNextChoiceIndex())
filters.clear();
}
final TableChosenFilters tcf = new TableChosenFilters(filters);
final TableParameters tp = new TableParameters(tcf);
tcf.setupListener(tp);
final TableAvailableFilters taf = new TableAvailableFilters(tcf);
if (filters.size() > 0) {
tcf.getSelectionModel().setSelectionInterval(0, 0);
}
final JFrame frame = new JFrame("Image filters");
final JButton set = new JButton("Set");
final JComboBox pulldown = new JComboBox(new String[] { "Selected images (" + patches.size() + ")", "All images in layer " + (ref.getLayer().getParent().indexOf(ref.getLayer()) + 1), "All images in layer range..." });
final Component[] cs = new Component[] { set, pulldown, tcf, tp, taf };
set.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
if (check(frame, filters)) {
final ArrayList<Patch> ps = new ArrayList<Patch>();
switch(pulldown.getSelectedIndex()) {
case 0:
ps.addAll(patches);
break;
case 1:
for (final Displayable d : ref.getLayer().getDisplayables(Patch.class)) {
ps.add((Patch) d);
}
break;
case 2:
final GenericDialog gd = new GenericDialog("Apply filters");
Utils.addLayerRangeChoices(ref.getLayer(), gd);
gd.addStringField("Image title matches:", "", 30);
gd.addCheckbox("Visible images only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final String regex = gd.getNextString();
final boolean visible_only = gd.getNextBoolean();
Pattern pattern = null;
if (0 != regex.length()) {
pattern = Pattern.compile(regex);
}
for (final Layer l : ref.getLayer().getParent().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex())) {
for (final Displayable d : l.getDisplayables(Patch.class, visible_only)) {
if (null != pattern && !pattern.matcher(d.getTitle()).matches()) {
continue;
}
ps.add((Patch) d);
}
}
}
apply(ps, filters, cs, false);
}
}
});
final JPanel buttons = new JPanel();
final JLabel label = new JLabel("Push F1 for help");
final GridBagConstraints c2 = new GridBagConstraints();
final GridBagLayout gb2 = new GridBagLayout();
buttons.setLayout(gb2);
c2.anchor = GridBagConstraints.WEST;
c2.gridx = 0;
gb2.setConstraints(label, c2);
buttons.add(label);
c2.gridx = 1;
c2.weightx = 1;
final JPanel empty = new JPanel();
gb2.setConstraints(empty, c2);
buttons.add(empty);
c2.gridx = 2;
c2.weightx = 0;
c2.anchor = GridBagConstraints.EAST;
final JLabel a = new JLabel("Apply to:");
gb2.setConstraints(a, c2);
buttons.add(a);
c2.gridx = 3;
c2.insets = new Insets(4, 10, 4, 0);
gb2.setConstraints(pulldown, c2);
buttons.add(pulldown);
c2.gridx = 4;
gb2.setConstraints(set, c2);
buttons.add(set);
//
taf.setPreferredSize(new Dimension(350, 500));
tcf.setPreferredSize(new Dimension(350, 250));
tp.setPreferredSize(new Dimension(350, 250));
//
final GridBagLayout gb = new GridBagLayout();
final GridBagConstraints c = new GridBagConstraints();
final JPanel all = new JPanel();
all.setBackground(Color.white);
all.setPreferredSize(new Dimension(700, 500));
all.setLayout(gb);
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 2;
c.weightx = 0.5;
final JScrollPane p1 = new JScrollPane(taf);
p1.setPreferredSize(taf.getPreferredSize());
gb.setConstraints(p1, c);
all.add(p1);
c.gridx = 1;
c.gridy = 0;
c.gridheight = 1;
c.weighty = 0.7;
final JScrollPane p2 = new JScrollPane(tcf);
p2.setPreferredSize(tcf.getPreferredSize());
gb.setConstraints(p2, c);
all.add(p2);
c.gridx = 1;
c.gridy = 1;
c.weighty = 0.3;
final JScrollPane p3 = new JScrollPane(tp);
p3.setPreferredSize(tp.getPreferredSize());
gb.setConstraints(p3, c);
all.add(p3);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 2;
c.weightx = 1;
c.weighty = 0;
gb.setConstraints(buttons, c);
all.add(buttons);
final KeyAdapter help = new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_F1) {
final GenericDialog gd = new GenericDialog("Help :: image filters");
gd.addMessage("In the table 'Available Filters':\n" + " - double-click a filter to add it to the table of 'Chosen Filters'\n \n" + "In the table 'Chosen Filters':\n" + " - double-click a filter to remove it.\n" + " - PAGE UP/DOWN keys move the filter up/down in the list.\n" + " - 'Delete' key removes the selected filter.\n \n" + "In the table of parameter names and values:\n" + " - double-click a value to edit it. Then push enter to set the new value.\n \n" + "What you need to know:\n" + " - filters are set and applied in order, so order matters.\n" + " - filters with parameters for which you entered a value of zero\nwill result in a warning message.\n" + " - when applying the filters, if you choose 'Selected images', these are the images\nthat were selected when the filter editor was opened.\n" + " - when applying the filters, if you want to filter for a regular expression pattern\nin the image name, use the 'All images in layer range...' option,\nwhere a range of one single layer is also possible.");
gd.hideCancelButton();
gd.setModal(false);
gd.showDialog();
}
}
};
taf.addKeyListener(help);
tcf.addKeyListener(help);
tp.addKeyListener(help);
all.addKeyListener(help);
buttons.addKeyListener(help);
empty.addKeyListener(help);
a.addKeyListener(help);
frame.getContentPane().add(all);
frame.pack();
frame.setVisible(true);
}
Aggregations