use of ini.trakem2.display.AreaList in project TrakEM2 by trakem2.
the class Display3D method show.
/**
* Scan the {@link ProjectThing} children and assign the renderable ones to an existing {@link Display3D} for their {@link LayerSet}, or open a new one. If {@code true == wait && -1 != resample}, then the method returns only when the mesh/es have been added.
*/
public static Future<Vector<Future<Content>>> show(final ProjectThing pt, final boolean wait, final int resample) {
if (null == pt)
return null;
final Future<Vector<Future<Content>>> fu = launchers.submit(new Callable<Vector<Future<Content>>>() {
@Override
public Vector<Future<Content>> call() {
// Scan the given ProjectThing for 3D-viewable items
// So: find arealist, pipe, ball, and profile_list types
final HashSet<ProjectThing> hs = pt.findBasicTypeChildren();
if (null == hs || 0 == hs.size()) {
Utils.logAll("Node " + pt + " does not contain any 3D-displayable children");
return null;
}
// Remove profile if it lives under a profile_list
for (final Iterator<ProjectThing> it = hs.iterator(); it.hasNext(); ) {
final ProjectThing pt = it.next();
if (null != pt.getObject() && pt.getObject().getClass() == Profile.class && pt.getParent().getType().equals("profile_list")) {
it.remove();
}
}
setWaitingCursor();
// Start new scheduler to publish/add meshes to the 3D Viewer every 5 seconds and when done.
final Hashtable<Display3D, Vector<Content>> contents = new Hashtable<Display3D, Vector<Content>>();
final ScheduledExecutorService updater = Executors.newScheduledThreadPool(1);
final AtomicInteger counter = new AtomicInteger();
updater.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
// Obtain a copy of the contents queue
final HashMap<Display3D, Vector<Content>> m = new HashMap<Display3D, Vector<Content>>();
synchronized (contents) {
m.putAll(contents);
contents.clear();
}
if (m.isEmpty())
return;
// Add all to the corresponding Display3D
for (final Map.Entry<Display3D, Vector<Content>> e : m.entrySet()) {
e.getKey().universe.addContentLater(e.getValue());
counter.getAndAdd(e.getValue().size());
}
Utils.showStatus(new StringBuilder("Rendered ").append(counter.get()).append('/').append(hs.size()).toString());
}
}, 100, 4000, TimeUnit.MILLISECONDS);
// A list of all generated Content objects
final Vector<Future<Content>> list = new Vector<Future<Content>>();
for (final Iterator<ProjectThing> it = hs.iterator(); it.hasNext(); ) {
// obtain the Displayable object under the node
final ProjectThing child = it.next();
final Object obc = child.getObject();
final Displayable displ = obc.getClass().equals(String.class) ? null : (Displayable) obc;
if (null != displ) {
if (displ.getClass().equals(Profile.class)) {
// handled by profile_list Thing
continue;
}
if (!displ.isVisible()) {
Utils.log("Skipping non-visible node " + displ);
continue;
}
}
// obtain the containing LayerSet
final Display3D d3d;
if (null != displ)
d3d = Display3D.get(displ.getLayerSet());
else if (child.getType().equals("profile_list")) {
final ArrayList<ProjectThing> al_children = child.getChildren();
if (null == al_children || 0 == al_children.size())
continue;
// else, get the first Profile and get its LayerSet
d3d = Display3D.get(((Displayable) ((ProjectThing) al_children.get(0)).getObject()).getLayerSet());
} else {
Utils.log("Don't know what to do with node " + child);
d3d = null;
}
if (null == d3d) {
Utils.log("Could not get a proper 3D display for node " + displ);
// java3D not installed most likely
return null;
}
boolean already;
synchronized (d3d.ht_pt_meshes) {
already = d3d.ht_pt_meshes.containsKey(child);
}
if (already) {
if (child.getObject() instanceof ZDisplayable) {
Utils.log("Updating 3D view of " + child.getObject());
} else {
Utils.log("Updating 3D view of " + child);
}
}
list.add(d3d.executors.submit(new Callable<Content>() {
@Override
public Content call() {
Content c = null;
try {
c = d3d.createMesh(child, displ, resample).call();
Vector<Content> vc;
synchronized (contents) {
vc = contents.get(d3d);
if (null == vc)
vc = new Vector<Content>();
contents.put(d3d, vc);
}
vc.add(c);
} catch (final Exception e) {
IJError.print(e);
}
return c;
}
}));
// If it's the last one:
if (!it.hasNext()) {
// Add the concluding task, that waits on all and shuts down the scheduler
d3d.executors.submit(new Runnable() {
@Override
public void run() {
// Wait until all are done
for (final Future<Content> c : list) {
try {
c.get();
} catch (final Throwable t) {
IJError.print(t);
}
}
try {
// Shutdown scheduler and execute remaining tasks
for (final Runnable r : updater.shutdownNow()) {
r.run();
}
} catch (final Throwable e) {
IJError.print(e);
}
// Reset cursor
doneWaiting();
Utils.showStatus(new StringBuilder("Done rendering ").append(counter.get()).append('/').append(hs.size()).toString());
}
});
}
}
return list;
}
});
if (wait && -1 != resample) {
try {
fu.get();
} catch (final Throwable t) {
IJError.print(t);
}
}
return fu;
}
use of ini.trakem2.display.AreaList in project TrakEM2 by trakem2.
the class Loader method importStack.
/**
* Imports an image stack from a multitiff file and places each slice in the proper layer, creating new layers as it goes. If the given stack is null, popup a file dialog to choose one
*/
public Bureaucrat importStack(final Layer first_layer, final double x, final double y, final ImagePlus imp_stack_, final boolean ask_for_data, final String filepath_, final boolean one_patch_per_layer_) {
Utils.log2("Loader.importStack filepath: " + filepath_);
if (null == first_layer)
return null;
final Worker worker = new Worker("import stack") {
@Override
public void run() {
startedWorking();
try {
String filepath = filepath_;
boolean one_patch_per_layer = one_patch_per_layer_;
/* On drag and drop the stack is not null! */
// Utils.log2("imp_stack_ is " + imp_stack_);
ImagePlus[] stks = null;
boolean choose = false;
if (null == imp_stack_) {
stks = Utils.findOpenStacks();
choose = null == stks || stks.length > 0;
} else {
stks = new ImagePlus[] { imp_stack_ };
}
ImagePlus imp_stack = null;
// ask to open a stack if it's null
if (null == stks) {
// choose one
imp_stack = openStack();
} else if (choose) {
// choose one from the list
final GenericDialog gd = new GenericDialog("Choose one");
gd.addMessage("Choose a stack from the list or 'open...' to bring up a file chooser dialog:");
final String[] list = new String[stks.length + 1];
for (int i = 0; i < list.length - 1; i++) {
list[i] = stks[i].getTitle();
}
list[list.length - 1] = "[ Open stack... ]";
gd.addChoice("choose stack: ", list, list[0]);
gd.showDialog();
if (gd.wasCanceled()) {
finishedWorking();
return;
}
final int i_choice = gd.getNextChoiceIndex();
if (list.length - 1 == i_choice) {
// the open... command
imp_stack = first_layer.getProject().getLoader().openStack();
} else {
imp_stack = stks[i_choice];
}
} else {
imp_stack = imp_stack_;
}
// check:
if (null == imp_stack) {
finishedWorking();
return;
}
final String props = (String) imp_stack.getProperty("Info");
// check if it's amira labels stack to prevent missimports
if (null != props && -1 != props.indexOf("Materials {")) {
final YesNoDialog yn = new YesNoDialog(IJ.getInstance(), "Warning", "You are importing a stack of Amira labels as a regular image stack. Continue anyway?");
if (!yn.yesPressed()) {
finishedWorking();
return;
}
}
// String dir = imp_stack.getFileInfo().directory;
final double layer_width = first_layer.getLayerWidth();
final double layer_height = first_layer.getLayerHeight();
final double current_thickness = first_layer.getThickness();
double thickness = current_thickness;
boolean expand_layer_set = false;
boolean lock_stack = false;
// int anchor = LayerSet.NORTHWEST; //default
if (ask_for_data) {
// ask for slice separation in pixels
final GenericDialog gd = new GenericDialog("Slice separation?");
gd.addMessage("Please enter the slice thickness, in pixels");
// assuming pixelWidth == pixelHeight
gd.addNumericField("slice_thickness: ", Math.abs(imp_stack.getCalibration().pixelDepth / imp_stack.getCalibration().pixelHeight), 3);
if (layer_width != imp_stack.getWidth() || layer_height != imp_stack.getHeight()) {
gd.addCheckbox("Resize canvas to fit stack", true);
// gd.addChoice("Anchor: ", LayerSet.ANCHORS, LayerSet.ANCHORS[0]);
}
gd.addCheckbox("Lock stack", false);
final String[] importStackTypes = { "One slice per layer (Patches)", "Image volume (Stack)" };
if (imp_stack.getStack().isVirtual()) {
one_patch_per_layer = true;
}
gd.addChoice("Import stack as:", importStackTypes, importStackTypes[0]);
((Component) gd.getChoices().get(0)).setEnabled(!imp_stack.getStack().isVirtual());
gd.showDialog();
if (gd.wasCanceled()) {
if (null == stks) {
// flush only if it was not open before
flush(imp_stack);
}
finishedWorking();
return;
}
if (layer_width != imp_stack.getWidth() || layer_height != imp_stack.getHeight()) {
expand_layer_set = gd.getNextBoolean();
// anchor = gd.getNextChoiceIndex();
}
lock_stack = gd.getNextBoolean();
thickness = gd.getNextNumber();
// check provided thickness with that of the first layer:
if (thickness != current_thickness) {
if (1 == first_layer.getParent().size() && first_layer.isEmpty()) {
final YesNoCancelDialog yn = new YesNoCancelDialog(IJ.getInstance(), "Mismatch!", "The current layer's thickness is " + current_thickness + "\nwhich is " + (thickness < current_thickness ? "larger" : "smaller") + " than\nthe desired " + thickness + " for each stack slice.\nAdjust current layer's thickness to " + thickness + " ?");
if (yn.cancelPressed()) {
// was opened new
if (null != imp_stack_)
flush(imp_stack);
finishedWorking();
return;
} else if (yn.yesPressed()) {
first_layer.setThickness(thickness);
// The rest of layers, created new, will inherit the same thickness
}
} else {
final YesNoDialog yn = new YesNoDialog(IJ.getInstance(), "WARNING", "There's more than one layer or the current layer is not empty\nso the thickness cannot be adjusted. Proceed anyway?");
if (!yn.yesPressed()) {
finishedWorking();
return;
}
}
}
one_patch_per_layer = imp_stack.getStack().isVirtual() || 0 == gd.getNextChoiceIndex();
}
if (null == imp_stack.getStack()) {
Utils.showMessage("Not a stack.");
finishedWorking();
return;
}
// WARNING: there are fundamental issues with calibration, because the Layer thickness is disconnected from the Calibration pixelDepth
// set LayerSet calibration if there is no calibration
boolean calibrate = true;
if (ask_for_data && first_layer.getParent().isCalibrated()) {
if (!ControlWindow.isGUIEnabled()) {
Utils.log2("Loader.importStack: overriding LayerSet calibration with that of the imported stack.");
} else {
final YesNoDialog yn = new YesNoDialog("Calibration", "The layer set is already calibrated. Override with the stack calibration values?");
if (!yn.yesPressed()) {
calibrate = false;
}
}
}
if (calibrate) {
first_layer.getParent().setCalibration(imp_stack.getCalibration());
}
if (layer_width < imp_stack.getWidth() || layer_height < imp_stack.getHeight()) {
expand_layer_set = true;
}
if (imp_stack.getStack().isVirtual()) {
// do nothing
} else if (null == filepath) {
// try to get it from the original FileInfo
final FileInfo fi = imp_stack.getOriginalFileInfo();
if (null != fi && null != fi.directory && null != fi.fileName) {
filepath = fi.directory.replace('\\', '/');
if (!filepath.endsWith("/"))
filepath += '/';
filepath += fi.fileName;
}
Utils.log2("Getting filepath from FileInfo: " + filepath);
// check that file exists, otherwise save a copy in the storage folder
if (null == filepath || (!filepath.startsWith("http://") && !new File(filepath).exists())) {
filepath = handlePathlessImage(imp_stack);
}
} else {
filepath = filepath.replace('\\', '/');
}
// Import as Stack ZDisplayable object:
if (!one_patch_per_layer) {
final Stack st = new Stack(first_layer.getProject(), new File(filepath).getName(), x, y, first_layer, filepath);
first_layer.getParent().add(st);
finishedWorking();
return;
}
// Place the first slice in the current layer, and then query the parent LayerSet for subsequent layers, and create them if not present.
final Patch last_patch = Loader.this.importStackAsPatches(first_layer.getProject(), first_layer, x, y, imp_stack, null != imp_stack_ && null != imp_stack_.getCanvas(), filepath);
if (null != last_patch) {
last_patch.setLocked(lock_stack);
Display.updateCheckboxes(last_patch.getLinkedGroup(null), DisplayablePanel.LOCK_STATE, true);
}
if (expand_layer_set) {
last_patch.getLayer().getParent().setMinimumDimensions();
}
Utils.log2("props: " + props);
// check if it's an amira stack, then ask to import labels
if (null != props && -1 == props.indexOf("Materials {") && -1 != props.indexOf("CoordType")) {
final YesNoDialog yn = new YesNoDialog(IJ.getInstance(), "Amira Importer", "Import labels as well?");
if (yn.yesPressed()) {
// select labels
final Collection<AreaList> alis = AmiraImporter.importAmiraLabels(first_layer, last_patch.getX(), last_patch.getY(), imp_stack.getOriginalFileInfo().directory);
if (null != alis) {
// import all created AreaList as nodes in the ProjectTree under a new imported_segmentations node
first_layer.getProject().getProjectTree().insertSegmentations(alis);
// link them to the images
for (final AreaList ali : alis) {
ali.linkPatches();
}
}
}
}
// it is safe not to flush the imp_stack, because all its resources are being used anyway (all the ImageProcessor), and it has no awt.Image. Unless it's being shown in ImageJ, and then it will be flushed on its own when the user closes its window.
} catch (final Exception e) {
IJError.print(e);
}
finishedWorking();
}
};
return Bureaucrat.createAndStart(worker, first_layer.getProject());
}
use of ini.trakem2.display.AreaList in project TrakEM2 by trakem2.
the class Loader method importLabelsAsAreaLists.
/**
* If base_x or base_y are Double.MAX_VALUE, then those values are asked for in a GenericDialog.
*/
public Bureaucrat importLabelsAsAreaLists(final Layer first_layer, final String path_, final double base_x_, final double base_y_, final float alpha_, final boolean add_background_) {
final Worker worker = new Worker("Import labels as arealists") {
@Override
public void run() {
startedWorking();
try {
String path = path_;
if (null == path) {
final OpenDialog od = new OpenDialog("Select stack", "");
final String name = od.getFileName();
if (null == name || 0 == name.length()) {
return;
}
String dir = od.getDirectory().replace('\\', '/');
if (!dir.endsWith("/"))
dir += "/";
path = dir + name;
}
if (path.toLowerCase().endsWith(".xml")) {
Utils.log("Avoided opening a TrakEM2 project.");
return;
}
double base_x = base_x_;
double base_y = base_y_;
float alpha = alpha_;
boolean add_background = add_background_;
Layer layer = first_layer;
if (Double.MAX_VALUE == base_x || Double.MAX_VALUE == base_y || alpha < 0 || alpha > 1) {
final GenericDialog gd = new GenericDialog("Base x, y");
Utils.addLayerChoice("First layer:", first_layer, gd);
gd.addNumericField("Base_X:", 0, 0);
gd.addNumericField("Base_Y:", 0, 0);
gd.addSlider("Alpha:", 0, 100, 40);
gd.addCheckbox("Add background (zero)", false);
gd.showDialog();
if (gd.wasCanceled()) {
return;
}
layer = first_layer.getParent().getLayer(gd.getNextChoiceIndex());
base_x = gd.getNextNumber();
base_y = gd.getNextNumber();
if (Double.isNaN(base_x) || Double.isNaN(base_y)) {
Utils.log("Base x or y is NaN!");
return;
}
alpha = (float) (gd.getNextNumber() / 100);
add_background = gd.getNextBoolean();
}
releaseToFit(new File(path).length() * 3);
final ImagePlus imp;
if (path.toLowerCase().endsWith(".am")) {
final AmiraMeshDecoder decoder = new AmiraMeshDecoder();
if (decoder.open(path))
imp = new ImagePlus(path, decoder.getStack());
else
imp = null;
} else {
imp = openImagePlus(path);
}
if (null == imp) {
Utils.log("Could not open image at " + path);
return;
}
final Map<Float, AreaList> alis = AmiraImporter.extractAreaLists(imp, layer, base_x, base_y, alpha, add_background);
if (!hasQuitted() && alis.size() > 0) {
layer.getProject().getProjectTree().insertSegmentations(alis.values());
}
} catch (final Exception e) {
IJError.print(e);
} finally {
finishedWorking();
}
}
};
return Bureaucrat.createAndStart(worker, first_layer.getProject());
}
use of ini.trakem2.display.AreaList in project TrakEM2 by trakem2.
the class AreaList method keyPressed.
@Override
public void keyPressed(final KeyEvent ke) {
final Object source = ke.getSource();
if (!(source instanceof DisplayCanvas))
return;
final DisplayCanvas dc = (DisplayCanvas) source;
final Layer layer = dc.getDisplay().getLayer();
final int keyCode = ke.getKeyCode();
final long layer_id = layer.getId();
if (KeyEvent.VK_K == keyCode) {
final Roi roi = dc.getFakeImagePlus().getRoi();
if (null == roi)
return;
if (!M.isAreaROI(roi)) {
Utils.log("AreaList only accepts region ROIs, not lines.");
return;
}
final ShapeRoi sroi = new ShapeRoi(roi);
try {
final AreaList p = part(layer_id, sroi);
if (null != p) {
project.getProjectTree().addSibling(this, p);
}
Display.repaint(layer, getBoundingBox(), 5);
linkPatches();
} catch (final NoninvertibleTransformException nite) {
IJError.print(nite);
}
ke.consume();
} else {
Area a = getArea(layer_id);
if (null == a) {
a = new Area();
ht_areas.put(layer_id, a);
}
new AreaWrapper(this, a).keyPressed(ke, dc, layer);
}
}
use of ini.trakem2.display.AreaList in project TrakEM2 by trakem2.
the class AreaList method getStack.
/**
* Returns a stack of images representing the pixel data of this LayerSet inside this AreaList.
*/
public ImagePlus getStack(final int type, final double scale) {
final ImageProcessor ref_ip = Utils.createProcessor(type, 2, 2);
if (null == ref_ip) {
Utils.log("AreaList.getStack: Unknown type " + type);
return null;
}
final Rectangle b = getBoundingBox();
final int w = (int) (0.5 + b.width * scale);
final int h = (int) (0.5 + b.height * scale);
final ImageStack stack = new ImageStack(w, h);
for (final Layer la : getLayerRange()) {
final Area area = getArea(la);
final double z = layer.getZ();
project.getLoader().releaseToFit(w * h * 10);
final ImageProcessor ip = ref_ip.createProcessor(w, h);
if (null == area) {
stack.addSlice(Double.toString(z), ip);
continue;
}
// Create a ROI from the area at Layer la:
final AffineTransform aff = getAffineTransformCopy();
aff.translate(-b.x, -b.y);
aff.scale(scale, scale);
final ShapeRoi roi = new ShapeRoi(area.createTransformedArea(aff));
// Create a cropped snapshot of the images at Layer la under the area:
final ImageProcessor flat = Patch.makeFlatImage(type, la, b, scale, la.getAll(Patch.class), Color.black);
flat.setRoi(roi);
final Rectangle rb = roi.getBounds();
ip.insert(flat.crop(), rb.x, rb.y);
// Clear the outside
final ImagePlus bimp = new ImagePlus("", ip);
bimp.setRoi(roi);
ip.setValue(0);
ip.setBackgroundValue(0);
IJ.run(bimp, "Clear Outside", "");
stack.addSlice(Double.toString(z), ip);
}
final ImagePlus imp = new ImagePlus("AreaList stack for " + this, stack);
imp.setCalibration(layer_set.getCalibrationCopy());
return imp;
}
Aggregations