use of org.janelia.intensity.MatchIntensities in project TrakEM2 by trakem2.
the class Display method actionPerformed.
@Override
public void actionPerformed(final ActionEvent ae) {
dispatcher.exec(new Runnable() {
@Override
public void run() {
final String command = ae.getActionCommand();
if (command.startsWith("Job")) {
if (Utils.checkYN("Really cancel job?")) {
project.getLoader().quitJob(command);
repairGUI();
}
return;
} else if (command.equals("Move to top")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.TOP, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move up")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.UP, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move down")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.DOWN, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Move to bottom")) {
if (null == active)
return;
canvas.setUpdateGraphics(true);
getLayerSet().addUndoMoveStep(active);
layer.getParent().move(LayerSet.BOTTOM, active);
getLayerSet().addUndoMoveStep(active);
Display.repaint(layer.getParent(), active, 5);
// Display.updatePanelIndex(layer, active);
} else if (command.equals("Duplicate, link and send to next layer")) {
duplicateLinkAndSendTo(active, 1, layer.getParent().next(layer));
} else if (command.equals("Duplicate, link and send to previous layer")) {
duplicateLinkAndSendTo(active, 0, layer.getParent().previous(layer));
} else if (command.equals("Duplicate, link and send to...")) {
// fix non-scrolling popup menu
Utils.invokeLater(new Runnable() {
@Override
public void run() {
final GenericDialog gd = new GenericDialog("Send to");
gd.addMessage("Duplicate, link and send to...");
final String[] sl = new String[layer.getParent().size()];
int next = 0;
for (final Layer la : layer.getParent().getLayers()) {
sl[next++] = project.findLayerThing(la).toString();
}
gd.addChoice("Layer: ", sl, sl[layer.getParent().indexOf(layer)]);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer la = layer.getParent().getLayer(gd.getNextChoiceIndex());
if (layer == la) {
Utils.showMessage("Can't duplicate, link and send to the same layer.");
return;
}
duplicateLinkAndSendTo(active, 0, la);
}
});
} else if (-1 != command.indexOf("z = ")) {
// this is an item from the "Duplicate, link and send to" menu of layer z's
final Layer target_layer = layer.getParent().getLayer(Double.parseDouble(command.substring(command.lastIndexOf(' ') + 1)));
Utils.log2("layer: __" + command.substring(command.lastIndexOf(' ') + 1) + "__");
if (null == target_layer)
return;
duplicateLinkAndSendTo(active, 0, target_layer);
} else if (-1 != command.indexOf("z=")) {
// WARNING the indexOf is very similar to the previous one
// Send the linked group to the selected layer
final int iz = command.indexOf("z=") + 2;
Utils.log2("iz=" + iz + " other: " + command.indexOf(' ', iz + 2));
int end = command.indexOf(' ', iz);
if (-1 == end)
end = command.length();
final double lz = Double.parseDouble(command.substring(iz, end));
final Layer target = layer.getParent().getLayer(lz);
// TODO what happens when ZDisplayable are selected?
layer.getParent().move(selection.getAffected(), active.getLayer(), target);
} else if (command.equals("Unlink")) {
if (null == active || active instanceof Patch)
return;
active.unlink();
// selection.update();
updateSelection();
} else if (command.equals("Unlink from images")) {
if (null == active)
return;
try {
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
} else if (command.equals("Unlink slices")) {
final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Attention", "Really unlink all slices from each other?\nThere is no undo.");
if (!yn.yesPressed())
return;
final ArrayList<Patch> pa = ((Patch) active).getStackPatches();
for (int i = pa.size() - 1; i > 0; i--) {
pa.get(i).unlink(pa.get(i - 1));
}
} else if (command.equals("Send to next layer")) {
final Rectangle box = selection.getBox();
try {
// unlink Patch instances
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
// layer.getParent().moveDown(layer, active); // will repaint whatever appropriate layers
selection.moveDown();
repaint(layer.getParent(), box);
} else if (command.equals("Send to previous layer")) {
final Rectangle box = selection.getBox();
try {
// unlink Patch instances
for (final Displayable displ : selection.getSelected()) {
displ.unlinkAll(Patch.class);
}
// selection.update();
updateSelection();
} catch (final Exception e) {
IJError.print(e);
}
// layer.getParent().moveUp(layer, active); // will repaint whatever appropriate layers
selection.moveUp();
repaint(layer.getParent(), box);
} else if (command.equals("Show centered")) {
if (active == null)
return;
showCentered(active);
} else if (command.equals("Delete...")) {
// remove all selected objects
selection.deleteAll();
} else if (command.equals("Color...")) {
IJ.doCommand("Color Picker...");
} else if (command.equals("Revert")) {
if (null == active || active.getClass() != Patch.class)
return;
final Patch p = (Patch) active;
if (!p.revert()) {
if (null == p.getOriginalPath())
Utils.log("No editions to save for patch " + p.getTitle() + " #" + p.getId());
else
Utils.log("Could not revert Patch " + p.getTitle() + " #" + p.getId());
}
} else if (command.equals("Remove alpha mask")) {
Display.removeAlphaMasks(selection.get(Patch.class));
} else if (command.equals("Undo")) {
Bureaucrat.createAndStart(new Worker.Task("Undo") {
@Override
public void exec() {
layer.getParent().undoOneStep();
Display.repaint(layer.getParent());
}
}, project);
} else if (command.equals("Redo")) {
Bureaucrat.createAndStart(new Worker.Task("Redo") {
@Override
public void exec() {
layer.getParent().redoOneStep();
Display.repaint(layer.getParent());
}
}, project);
} else if (command.equals("Apply transform")) {
canvas.applyTransform();
} else if (command.equals("Apply transform propagating to last layer")) {
if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
final LayerSet ls = getLayerSet();
// +1 to exclude current layer
final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(ls.indexOf(Display.this.layer) + 1, ls.size() - 1));
if (mode.getClass() == AffineTransformMode.class)
((AffineTransformMode) mode).applyAndPropagate(subset);
else if (mode.getClass() == NonLinearTransformMode.class)
((NonLinearTransformMode) mode).apply(subset);
setMode(new DefaultMode(Display.this));
}
} else if (command.equals("Apply transform propagating to first layer")) {
if (mode.getClass() == AffineTransformMode.class || mode.getClass() == NonLinearTransformMode.class) {
final LayerSet ls = getLayerSet();
// -1 to exclude current layer
final HashSet<Layer> subset = new HashSet<Layer>(ls.getLayers(0, ls.indexOf(Display.this.layer) - 1));
if (mode.getClass() == AffineTransformMode.class)
((AffineTransformMode) mode).applyAndPropagate(subset);
else if (mode.getClass() == NonLinearTransformMode.class)
((NonLinearTransformMode) mode).apply(subset);
setMode(new DefaultMode(Display.this));
}
} else if (command.equals("Cancel transform")) {
// calls getMode().cancel()
canvas.cancelTransform();
} else if (command.equals("Specify transform...")) {
if (null == active)
return;
selection.specify();
} else if (command.equals("Exit inspection")) {
getMode().cancel();
setMode(new DefaultMode(Display.this));
} else if (command.equals("Inspect image mesh triangles")) {
setMode(new InspectPatchTrianglesMode(Display.this));
} else if (command.equals("Hide all but images")) {
final ArrayList<Class<?>> type = new ArrayList<Class<?>>();
type.add(Patch.class);
type.add(Stack.class);
final Collection<Displayable> col = layer.getParent().hideExcept(type, false);
selection.removeAll(col);
Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
Display.update(layer.getParent(), false);
} else if (command.equals("Unhide all")) {
Display.updateCheckboxes(layer.getParent().setAllVisible(false), DisplayablePanel.VISIBILITY_STATE);
Display.update(layer.getParent(), false);
} else if (command.startsWith("Hide all ")) {
// skip the ending plural 's'
final String type = command.substring(9, command.length() - 1);
final Collection<Displayable> col = layer.getParent().setVisible(type, false, true);
selection.removeAll(col);
Display.updateCheckboxes(col, DisplayablePanel.VISIBILITY_STATE);
} else if (command.startsWith("Unhide all ")) {
// skip the ending plural 's'
String type = command.substring(11, command.length() - 1);
type = type.substring(0, 1).toUpperCase() + type.substring(1);
updateCheckboxes(layer.getParent().setVisible(type, true, true), DisplayablePanel.VISIBILITY_STATE);
} else if (command.equals("Hide deselected")) {
hideDeselected(0 != (ActionEvent.ALT_MASK & ae.getModifiers()));
} else if (command.equals("Hide deselected except images")) {
hideDeselected(true);
} else if (command.equals("Hide selected")) {
// TODO should deselect them too? I don't think so.
selection.setVisible(false);
Display.updateCheckboxes(selection.getSelected(), DisplayablePanel.VISIBILITY_STATE);
} else if (command.equals("Resize canvas/LayerSet...")) {
resizeCanvas();
} else if (command.equals("Autoresize canvas/LayerSet")) {
layer.getParent().setMinimumDimensions();
} else if (command.equals("Resize canvas/LayerSet to ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi) {
Utils.log("No ROI present!");
return;
}
resizeCanvas(roi.getBounds());
} else if (command.equals("Import image")) {
importImage();
} else if (command.equals("Import next image")) {
importNextImage();
} else if (command.equals("Import stack...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Rectangle sr = getCanvas().getSrcRect();
final Bureaucrat burro = project.getLoader().importStack(layer, sr.x + sr.width / 2, sr.y + sr.height / 2, null, true, null, false);
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import stack with landmarks...")) {
// 1 - Find out if there's any other project open
final List<Project> pr = Project.getProjects();
if (1 == pr.size()) {
Utils.logAll("Need another project open!");
return;
}
// 2 - Ask for a "landmarks" type
final GenericDialog gd = new GenericDialog("Landmarks");
gd.addStringField("landmarks type:", "landmarks");
final String[] none = { "-- None --" };
final Hashtable<String, Project> mpr = new Hashtable<String, Project>();
for (final Project p : pr) {
if (p == project)
continue;
mpr.put(p.toString(), p);
}
final String[] project_titles = mpr.keySet().toArray(new String[0]);
final Hashtable<String, ProjectThing> map_target = findLandmarkNodes(project, "landmarks");
final String[] target_landmark_titles = map_target.isEmpty() ? none : map_target.keySet().toArray(new String[0]);
gd.addChoice("Landmarks node in this project:", target_landmark_titles, target_landmark_titles[0]);
gd.addMessage("");
gd.addChoice("Source project:", project_titles, project_titles[0]);
final Hashtable<String, ProjectThing> map_source = findLandmarkNodes(mpr.get(project_titles[0]), "landmarks");
final String[] source_landmark_titles = map_source.isEmpty() ? none : map_source.keySet().toArray(new String[0]);
gd.addChoice("Landmarks node in source project:", source_landmark_titles, source_landmark_titles[0]);
final List<Patch> stacks = Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet());
String[] stack_titles;
if (stacks.isEmpty()) {
if (1 == mpr.size()) {
IJ.showMessage("Project " + project_titles[0] + " does not contain any Stack.");
return;
}
stack_titles = none;
} else {
stack_titles = new String[stacks.size()];
int next = 0;
for (final Patch pa : stacks) stack_titles[next++] = pa.toString();
}
gd.addChoice("Stacks:", stack_titles, stack_titles[0]);
final Vector<?> vc = gd.getChoices();
final Choice choice_target_landmarks = (Choice) vc.get(0);
final Choice choice_source_projects = (Choice) vc.get(1);
final Choice choice_source_landmarks = (Choice) vc.get(2);
final Choice choice_stacks = (Choice) vc.get(3);
final TextField input = (TextField) gd.getStringFields().get(0);
input.addTextListener(new TextListener() {
@Override
public void textValueChanged(final TextEvent te) {
final String text = input.getText();
update(choice_target_landmarks, Display.this.project, text, map_target);
update(choice_source_landmarks, mpr.get(choice_source_projects.getSelectedItem()), text, map_source);
}
private void update(final Choice c, final Project p, final String type, final Hashtable<String, ProjectThing> table) {
table.clear();
table.putAll(findLandmarkNodes(p, type));
c.removeAll();
if (table.isEmpty())
c.add(none[0]);
else
for (final String t : table.keySet()) c.add(t);
}
});
choice_source_projects.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final String item = (String) e.getItem();
final Project p = mpr.get(choice_source_projects.getSelectedItem());
// 1 - Update choice of landmark items
map_source.clear();
map_source.putAll(findLandmarkNodes(p, input.getText()));
choice_target_landmarks.removeAll();
if (map_source.isEmpty())
choice_target_landmarks.add(none[0]);
else
for (final String t : map_source.keySet()) choice_target_landmarks.add(t);
// 2 - Update choice of Stack items
stacks.clear();
choice_stacks.removeAll();
stacks.addAll(Display.getPatchStacks(mpr.get(project_titles[0]).getRootLayerSet()));
if (stacks.isEmpty())
choice_stacks.add(none[0]);
else
for (final Patch pa : stacks) choice_stacks.add(pa.toString());
}
});
gd.showDialog();
if (gd.wasCanceled())
return;
final String type = gd.getNextString();
if (null == type || 0 == type.trim().length()) {
Utils.log("Invalid landmarks node type!");
return;
}
final ProjectThing target_landmarks_node = map_target.get(gd.getNextChoice());
final Project source = mpr.get(gd.getNextChoice());
final ProjectThing source_landmarks_node = map_source.get(gd.getNextChoice());
final Patch stack_patch = stacks.get(gd.getNextChoiceIndex());
// Store current state
Display.this.getLayerSet().addLayerContentStep(layer);
// Insert stack
insertStack(target_landmarks_node, source, source_landmarks_node, stack_patch);
// Store new state
Display.this.getLayerSet().addChangeTreesStep();
} else if (command.equals("Import grid...")) {
Display.this.getLayerSet().addLayerContentStep(layer);
final Bureaucrat burro = project.getLoader().importGrid(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addLayerContentStep(layer);
}
});
} else if (command.equals("Import sequence as grid...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importSequenceAsGrid(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import from text file...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importImages(layer);
if (null != burro)
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Import labels as arealists...")) {
Display.this.getLayerSet().addChangeTreesStep();
final Bureaucrat burro = project.getLoader().importLabelsAsAreaLists(layer, null, Double.MAX_VALUE, 0, 0.4f, false);
burro.addPostTask(new Runnable() {
@Override
public void run() {
Display.this.getLayerSet().addChangeTreesStep();
}
});
} else if (command.equals("Make flat image...")) {
// if there's a ROI, just use that as cropping rectangle
Rectangle srcRect = null;
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null != roi) {
srcRect = roi.getBounds();
} else {
// otherwise, whatever is visible
// srcRect = canvas.getSrcRect();
// The above is confusing. That is what ROIs are for. So paint all:
srcRect = new Rectangle(0, 0, (int) Math.ceil(layer.getParent().getLayerWidth()), (int) Math.ceil(layer.getParent().getLayerHeight()));
}
double scale = 1.0;
final String[] types = new String[] { "8-bit grayscale", "RGB Color" };
int the_type = ImagePlus.GRAY8;
final GenericDialog gd = new GenericDialog("Choose", frame);
gd.addSlider("Scale: ", 1, 100, 100);
gd.addNumericField("Width: ", srcRect.width, 0);
gd.addNumericField("height: ", srcRect.height, 0);
// connect the above 3 fields:
final Vector<?> numfields = gd.getNumericFields();
final UpdateDimensionField udf = new UpdateDimensionField(srcRect.width, srcRect.height, (TextField) numfields.get(1), (TextField) numfields.get(2), (TextField) numfields.get(0), (Scrollbar) gd.getSliders().get(0));
for (final Object ob : numfields) ((TextField) ob).addTextListener(udf);
gd.addChoice("Type: ", types, types[0]);
if (layer.getParent().size() > 1) {
// / $#%! where are my lisp macros
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Include non-empty layers only", true);
}
gd.addMessage("Background color:");
Utils.addRGBColorSliders(gd, Color.black);
gd.addCheckbox("Best quality", false);
gd.addMessage("");
final String[] choices = new String[] { "Show", "Save to file", "Save for web (CATMAID)" };
gd.addChoice("Export:", choices, choices[0]);
final String[] formats = Saver.formats();
gd.addChoice("Format:", formats, formats[0]);
gd.addNumericField("Tile_side", 256, 0);
final Choice cformats = (Choice) gd.getChoices().get(gd.getChoices().size() - 1);
cformats.setEnabled(false);
final Choice cchoices = (Choice) gd.getChoices().get(gd.getChoices().size() - 2);
final TextField tf = (TextField) gd.getNumericFields().get(gd.getNumericFields().size() - 1);
tf.setEnabled(false);
cchoices.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
cformats.setEnabled(cchoices.getSelectedIndex() > 0);
if (2 == cchoices.getSelectedIndex()) {
cformats.select(".jpg");
tf.setEnabled(true);
} else {
tf.setEnabled(false);
}
}
});
gd.addCheckbox("Use original images", true);
gd.showDialog();
if (gd.wasCanceled())
return;
scale = gd.getNextNumber() / 100;
the_type = (0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB);
if (Double.isNaN(scale) || scale <= 0.0) {
Utils.showMessage("Invalid scale.");
return;
}
// consuming and ignoring width and height:
gd.getNextNumber();
gd.getNextNumber();
Layer[] layer_array = null;
boolean non_empty_only = false;
if (layer.getParent().size() > 1) {
non_empty_only = gd.getNextBoolean();
final int i_start = gd.getNextChoiceIndex();
final int i_end = gd.getNextChoiceIndex();
final ArrayList<Layer> al = new ArrayList<Layer>();
final ArrayList<ZDisplayable> al_zd = layer.getParent().getZDisplayables();
final ZDisplayable[] zd = new ZDisplayable[al_zd.size()];
al_zd.toArray(zd);
for (int i = i_start, j = 0; i <= i_end; i++, j++) {
final Layer la = layer.getParent().getLayer(i);
// checks both the Layer and the ZDisplayable objects in the parent LayerSet
if (!la.isEmpty() || !non_empty_only)
al.add(la);
}
if (0 == al.size()) {
Utils.showMessage("All layers are empty!");
return;
}
layer_array = new Layer[al.size()];
al.toArray(layer_array);
} else {
layer_array = new Layer[] { Display.this.layer };
}
final Color background = new Color((int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
final boolean quality = gd.getNextBoolean();
final int choice = gd.getNextChoiceIndex();
final boolean save_to_file = 1 == choice;
final boolean save_for_web = 2 == choice;
final String format = gd.getNextChoice();
final Saver saver = new Saver(format);
final int tile_side = (int) gd.getNextNumber();
final boolean use_original_images = gd.getNextBoolean();
// in its own thread
if (save_for_web)
project.getLoader().makePrescaledTiles(layer_array, Patch.class, srcRect, scale, c_alphas, the_type, null, use_original_images, saver, tile_side);
else
project.getLoader().makeFlatImage(layer_array, srcRect, scale, c_alphas, the_type, save_to_file, format, quality, background);
} else if (command.equals("Lock")) {
selection.setLocked(true);
Utils.revalidateComponent(tabs.getSelectedComponent());
} else if (command.equals("Unlock")) {
selection.setLocked(false);
Utils.revalidateComponent(tabs.getSelectedComponent());
} else if (command.equals("Properties...")) {
switch(selection.getSelected().size()) {
case 0:
return;
case 1:
active.adjustProperties();
break;
default:
adjustGroupProperties(selection.getSelected());
break;
}
updateSelection();
} else if (command.equals("Measurement options...")) {
adjustMeasurementOptions();
} else if (command.equals("Show current 2D position in 3D")) {
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
Display3D.addFatPoint("Current 2D Position", getLayerSet(), p.x, p.y, layer.getZ(), 10, Color.magenta);
} else if (command.equals("Show layers as orthoslices in 3D")) {
final GenericDialog gd = new GenericDialog("Options");
final Roi roi = canvas.getFakeImagePlus().getRoi();
final Rectangle r = null == roi ? getLayerSet().get2DBounds() : roi.getBounds();
gd.addMessage("ROI 2D bounds:");
gd.addNumericField("x:", r.x, 0, 30, "pixels");
gd.addNumericField("y:", r.y, 0, 30, "pixels");
gd.addNumericField("width:", r.width, 0, 30, "pixels");
gd.addNumericField("height:", r.height, 0, 30, "pixels");
gd.addMessage("Layers to include:");
Utils.addLayerRangeChoices(layer, gd);
gd.addMessage("Constrain dimensions to:");
gd.addNumericField("max width and height:", getLayerSet().getPixelsMaxDimension(), 0, 30, "pixels");
gd.addMessage("Options:");
final String[] types = { "Greyscale", "Color RGB" };
gd.addChoice("Image type:", types, types[0]);
gd.addCheckbox("Invert images", false);
gd.showDialog();
if (gd.wasCanceled())
return;
final int x = (int) gd.getNextNumber(), y = (int) gd.getNextNumber(), width = (int) gd.getNextNumber(), height = (int) gd.getNextNumber();
final int first = gd.getNextChoiceIndex(), last = gd.getNextChoiceIndex();
final List<Layer> layers = getLayerSet().getLayers(first, last);
final int max_dim = Math.min((int) gd.getNextNumber(), Math.max(width, height));
float scale = 1;
if (max_dim < Math.max(width, height)) {
scale = max_dim / (float) Math.max(width, height);
}
final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
final boolean invert = gd.getNextBoolean();
final LayerStack stack = new LayerStack(layers, new Rectangle(x, y, width, height), scale, type, Patch.class, max_dim, invert);
Display3D.showOrthoslices(stack.getImagePlus(), "LayerSet [" + x + "," + y + "," + width + "," + height + "] " + first + "--" + last, x, y, scale, layers.get(0));
} else if (command.equals("Align stack slices")) {
if (getActive() instanceof Patch) {
final Patch slice = (Patch) getActive();
if (slice.isStack()) {
// check linked group
final HashSet hs = slice.getLinkedGroup(new HashSet());
for (final Iterator it = hs.iterator(); it.hasNext(); ) {
if (it.next().getClass() != Patch.class) {
// labels should be fine, need to check that
Utils.showMessage("Images are linked to other objects, can't proceed to cross-correlate them.");
return;
}
}
final LayerSet ls = slice.getLayerSet();
final HashSet<Displayable> linked = slice.getLinkedGroup(null);
ls.addTransformStepWithData(linked);
// will repaint
final Bureaucrat burro = AlignTask.registerStackSlices((Patch) getActive());
burro.addPostTask(new Runnable() {
@Override
public void run() {
ls.enlargeToFit(linked);
// The current state when done
ls.addTransformStepWithData(linked);
}
});
} else {
Utils.log("Align stack slices: selected image is not part of a stack.");
}
}
} else if (command.equals("Align layers manually with landmarks")) {
setMode(new ManualAlignMode(Display.this));
} else if (command.equals("Align layers")) {
Roi roi = canvas.getFakeImagePlus().getRoi();
if (null != roi) {
final YesNoCancelDialog yn = new YesNoCancelDialog(frame, "Use ROI?", "Snapshot layers using the ROI bounds?\n" + roi.getBounds());
if (yn.cancelPressed())
return;
if (!yn.yesPressed()) {
roi = null;
}
}
// caching, since scroll wheel may change it
final Layer la = layer;
la.getParent().addTransformStep(la.getParent().getLayers());
final Bureaucrat burro = AlignLayersTask.alignLayersTask(la, null == roi ? null : roi.getBounds());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
la.getParent().addTransformStep(la.getParent().getLayers());
}
});
} else if (command.equals("Align multi-layer mosaic")) {
// caching, since scroll wheel may change it
final Layer la = layer;
la.getParent().addTransformStep();
final Bureaucrat burro = AlignTask.alignMultiLayerMosaicTask(la, active instanceof Patch ? (Patch) active : null);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(getLayerSet().getDisplayables(Patch.class));
la.getParent().addTransformStep();
}
});
} else if (command.equals("Montage all images in this layer")) {
final Layer la = layer;
final List<Patch> patches = new ArrayList<Patch>((List<Patch>) (List) la.getDisplayables(Patch.class, true));
if (patches.size() < 2) {
Utils.showMessage("Montage needs 2 or more visible images");
return;
}
final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
// find any locked or selected patches
final HashSet<Patch> fixed = new HashSet<Patch>();
for (final Patch p : patches) {
if (p.isLocked2() || selection.contains(p))
fixed.add(p);
}
if (patches.size() == fixed.size()) {
Utils.showMessage("Can't do", "No montage possible: all images are selected,\nand hence all are considered locked.\nSelect only one image to be used as reference, or none.");
return;
}
Utils.log("Using " + fixed.size() + " image" + (fixed.size() == 1 ? "" : "s") + " as reference.");
final Bureaucrat burro = AlignTask.alignPatchesTask(patches, fixed);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().enlargeToFit(patches);
la.getParent().addTransformStepWithData(col);
}
});
} else if (command.equals("Montage selected images")) {
final Layer la = layer;
if (selection.getSelected(Patch.class).size() < 2) {
Utils.showMessage("Montage needs 2 or more images selected");
return;
}
final Collection<Displayable> col = la.getParent().addTransformStepWithDataForAll(Arrays.asList(new Layer[] { la }));
final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
if (null == burro)
return;
burro.addPostTask(new Runnable() {
@Override
public void run() {
la.getParent().enlargeToFit(selection.getAffected());
la.getParent().addTransformStepWithData(col);
}
});
} else if (command.equals("Montage multiple layers")) {
final GenericDialog gd = new GenericDialog("Choose range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
final List<Layer> layers = getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex());
final Collection<Displayable> col = getLayerSet().addTransformStepWithDataForAll(layers);
final Bureaucrat burro = AlignTask.montageLayersTask(layers);
burro.addPostTask(new Runnable() {
@Override
public void run() {
final Collection<Displayable> ds = new ArrayList<Displayable>();
for (final Layer la : layers) ds.addAll(la.getDisplayables(Patch.class));
getLayerSet().enlargeToFit(ds);
getLayerSet().addTransformStepWithData(col);
}
});
} else if (command.equals("Properties ...")) {
// NOTE the space before the dots, to distinguish from the "Properties..." command that works on Displayable objects.
adjustProperties();
} else if (command.equals("Adjust snapping parameters...")) {
AlignTask.p_snap.setup("Snap");
} else if (command.equals("Adjust fast-marching parameters...")) {
Segmentation.fmp.setup();
} else if (command.equals("Adjust arealist paint parameters...")) {
AreaWrapper.PP.setup();
} else if (command.equals("Fill ROI in alpha mask")) {
if (active.getClass() == Patch.class) {
((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), 0, KeyEvent.VK_F, 'f'));
}
} else if (command.equals("Fill inverse ROI in alpha mask")) {
if (active.getClass() == Patch.class) {
((Patch) active).keyPressed(new KeyEvent(getCanvas(), -1, System.currentTimeMillis(), Event.SHIFT_MASK, KeyEvent.VK_F, 'f'));
}
} else if (command.equals("Search...")) {
Search.showWindow();
} else if (command.equals("Select all")) {
selection.selectAll();
repaint(Display.this.layer, selection.getBox(), 0);
} else if (command.equals("Select all visible")) {
selection.selectAllVisible();
repaint(Display.this.layer, selection.getBox(), 0);
} else if (command.equals("Select all that match...")) {
final List<Displayable> ds = find();
selection.selectAll(ds);
Utils.showStatus("Added " + ds.size() + " to selection.");
} else if (command.equals("Select none")) {
final Rectangle box = selection.getBox();
selection.clear();
repaint(Display.this.layer, box, 0);
} else if (command.equals("Restore selection")) {
selection.restore();
} else if (command.equals("Select under ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi)
return;
selection.selectAll(roi, true);
} else if (command.equals("Merge") || command.equals("Split")) {
final Bureaucrat burro = Bureaucrat.create(new Worker.Task(command + "ing AreaLists") {
@Override
public void exec() {
final ArrayList<Displayable> al_sel = selection.getSelected(AreaList.class);
// put active at the beginning, to work as the base on which other's will get merged
al_sel.remove(Display.this.active);
al_sel.add(0, Display.this.active);
final Set<DoStep> dataedits = new HashSet<DoStep>();
if (command.equals("Merge")) {
// Add data undo for active only, which will be edited
dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits);
final AreaList ali = AreaList.merge(al_sel);
if (null != ali) {
// remove all but the first from the selection
for (int i = 1; i < al_sel.size(); i++) {
final Object ob = al_sel.get(i);
if (ob.getClass() == AreaList.class) {
selection.remove((Displayable) ob);
}
}
selection.updateTransform(ali);
repaint(ali.getLayerSet(), ali, 0);
}
} else if (command.equals("Split")) {
// Add data undo for every AreaList
for (final Displayable d : al_sel) {
if (d.getClass() != AreaList.class)
continue;
dataedits.add(new Displayable.DoEdit(d).init(d, new String[] { "data" }));
}
getLayerSet().addChangeTreesStep(dataedits);
try {
List<AreaList> alis = AreaList.split(al_sel);
for (AreaList ali : alis) {
if (selection.contains(ali))
continue;
selection.add(ali);
}
} catch (Exception e) {
IJError.print(e);
getLayerSet().undoOneStep();
}
}
}
}, Display.this.project);
burro.addPostTask(new Runnable() {
@Override
public void run() {
final Set<DoStep> dataedits = new HashSet<DoStep>();
dataedits.add(new Displayable.DoEdit(Display.this.active).init(Display.this.active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits);
}
});
burro.goHaveBreakfast();
} else if (command.equals("Reroot")) {
if (!(active instanceof Tree<?>))
return;
getLayerSet().addDataEditStep(active);
if (((Tree) active).reRoot(((Tree) active).getLastVisited())) {
getLayerSet().addDataEditStep(active);
Display.repaint(getLayerSet());
} else {
getLayerSet().removeLastUndoStep();
}
} else if (command.equals("Part subtree")) {
if (!(active instanceof Tree<?>))
return;
if (!Utils.check("Really part the subtree?"))
return;
final LayerSet.DoChangeTrees step = getLayerSet().addChangeTreesStep();
final Set<DoStep> deps = new HashSet<DoStep>();
// I hate java
deps.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
step.addDependents(deps);
final List<ZDisplayable> ts = ((Tree) active).splitAt(((Tree) active).getLastVisited());
if (null == ts) {
getLayerSet().removeLastUndoStep();
return;
}
final Displayable elder = Display.this.active;
final HashSet<DoStep> deps2 = new HashSet<DoStep>();
for (final ZDisplayable t : ts) {
deps2.add(new Displayable.DoEdit(t).init(t, new String[] { "data" }));
if (t == elder)
continue;
// will change Display.this.active !
getLayerSet().add(t);
project.getProjectTree().addSibling(elder, t);
}
selection.clear();
selection.selectAll(ts);
selection.add(elder);
final LayerSet.DoChangeTrees step2 = getLayerSet().addChangeTreesStep();
step2.addDependents(deps2);
Display.repaint(getLayerSet());
} else if (command.equals("Show tabular view")) {
if (!(active instanceof Tree<?>))
return;
((Tree<?>) active).createMultiTableView();
} else if (command.equals("Mark")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
if (((Tree<?>) active).markNear(p.x, p.y, layer, canvas.getMagnification())) {
Display.repaint(getLayerSet());
}
} else if (command.equals("Clear marks (selected Trees)")) {
for (final Tree<?> t : selection.get(Tree.class)) {
t.unmark();
}
Display.repaint(getLayerSet());
} else if (command.equals("Join")) {
if (!(active instanceof Tree<?>))
return;
final List<Tree<?>> tlines = (List<Tree<?>>) selection.get(active.getClass());
if (((Tree) active).canJoin(tlines)) {
final int nNodes_active = ((Tree) active).getRoot().getSubtreeNodes().size();
String warning = "";
for (final Tree<?> t : tlines) {
if (active == t)
continue;
if (null == t.getRoot()) {
Utils.log("Removed empty tree #" + t.getId() + " from those to join.");
tlines.remove(t);
continue;
}
if (t.getRoot().getSubtreeNodes().size() > nNodes_active) {
warning = "\nWARNING joining into a tree that is not the largest!";
break;
}
}
if (!Utils.check("Join these " + tlines.size() + " trees into the tree " + active + " ?" + warning))
return;
// Record current state
final Set<DoStep> dataedits = new HashSet<DoStep>(tlines.size());
for (final Tree<?> tl : tlines) {
dataedits.add(new Displayable.DoEdit(tl).init(tl, new String[] { "data" }));
}
getLayerSet().addChangeTreesStep(dataedits);
//
((Tree) active).join(tlines);
for (final Tree<?> tl : tlines) {
if (tl == active)
continue;
tl.remove2(false);
}
Display.repaint(getLayerSet());
// Again, to record current state (just the joined tree this time)
final Set<DoStep> dataedits2 = new HashSet<DoStep>(1);
dataedits2.add(new Displayable.DoEdit(active).init(active, new String[] { "data" }));
getLayerSet().addChangeTreesStep(dataedits2);
} else {
Utils.showMessage("Can't do", "Only one tree is selected.\nSelect more than one tree to perform a join operation!");
}
} else if (command.equals("Previous branch node or start")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Treeline) active).findPreviousBranchOrRootPoint(p.x, p.y, layer, canvas));
} else if (command.equals("Next branch node or end")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Tree<?>) active).findNextBranchOrEndPoint(p.x, p.y, layer, canvas));
} else if (command.equals("Root")) {
if (!(active instanceof Tree<?>))
return;
final Point p = canvas.consumeLastPopupPoint();
if (null == p)
return;
center(((Tree) active).createCoordinate(((Tree<?>) active).getRoot()));
} else if (command.equals("Last added node")) {
if (!(active instanceof Tree<?>))
return;
center(((Treeline) active).getLastAdded());
} else if (command.equals("Last edited node")) {
if (!(active instanceof Tree<?>))
return;
center(((Treeline) active).getLastEdited());
} else if (command.equals("Reverse point order")) {
if (!(active instanceof Pipe))
return;
getLayerSet().addDataEditStep(active);
((Pipe) active).reverse();
Display.repaint(Display.this.layer);
getLayerSet().addDataEditStep(active);
} else if (command.equals("View orthoslices")) {
if (!(active instanceof Patch))
return;
Display3D.showOrthoslices(((Patch) active));
} else if (command.equals("View volume")) {
if (!(active instanceof Patch))
return;
Display3D.showVolume(((Patch) active));
} else if (command.equals("Show in 3D")) {
for (final ZDisplayable zd : selection.get(ZDisplayable.class)) {
Display3D.show(zd.getProject().findProjectThing(zd));
}
// handle profile lists ...
final HashSet<ProjectThing> hs = new HashSet<ProjectThing>();
for (final Profile d : selection.get(Profile.class)) {
final ProjectThing profile_list = (ProjectThing) d.getProject().findProjectThing(d).getParent();
if (!hs.contains(profile_list)) {
Display3D.show(profile_list);
hs.add(profile_list);
}
}
} else if (command.equals("Snap")) {
// Take the active if it's a Patch
if (!(active instanceof Patch))
return;
Display.snap((Patch) active);
} else if (command.equals("Blend") || command.equals("Blend (selected images)...")) {
final HashSet<Patch> patches = new HashSet<Patch>(selection.get(Patch.class));
if (patches.size() > 1) {
final GenericDialog gd = new GenericDialog("Blending");
gd.addCheckbox("Respect current alpha mask", true);
gd.showDialog();
if (gd.wasCanceled())
return;
Blending.blend(patches, gd.getNextBoolean());
} else {
IJ.log("Please select more than one overlapping image.");
}
} else if (command.equals("Blend (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Blending");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Respect current alpha mask", true);
gd.addMessage("Filter:");
gd.addStringField("Use only images whose title matches:", "", 30);
gd.addCheckbox("Blend visible patches only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final boolean respect_alpha_mask = gd.getNextBoolean();
final String toMatch = gd.getNextString().trim();
final String regex = 0 == toMatch.length() ? null : ".*" + toMatch + ".*";
final boolean visible_only = gd.getNextBoolean();
Blending.blendLayerWise(getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex()), respect_alpha_mask, new Filter<Patch>() {
@Override
public final boolean accept(final Patch patch) {
if (visible_only && !patch.isVisible())
return false;
if (null == regex)
return true;
return patch.getTitle().matches(regex);
}
});
} else if (command.equals("Match intensities (layer-wise)...")) {
Bureaucrat.createAndStart(new Worker.Task("Match intensities") {
@Override
public void exec() {
final MatchIntensities matching = new MatchIntensities();
matching.invoke(getActive());
}
}, project);
} else if (command.equals("Remove intensity maps (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Remove intensity maps");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
Bureaucrat.createAndStart(new Worker.Task("Match intensities") {
@Override
public void exec() {
for (final Layer layer : getLayerSet().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex())) {
for (final Displayable p : layer.getDisplayables(Patch.class)) {
final Patch patch = (Patch) p;
if (patch.clearIntensityMap()) {
patch.updateMipMaps();
}
}
}
}
}, project);
} else if (command.equals("Montage")) {
final Set<Displayable> affected = new HashSet<Displayable>(selection.getAffected());
// make an undo step!
final LayerSet ls = layer.getParent();
ls.addTransformStepWithData(affected);
final Bureaucrat burro = AlignTask.alignSelectionTask(selection);
burro.addPostTask(new Runnable() {
@Override
public void run() {
ls.enlargeToFit(affected);
ls.addTransformStepWithData(affected);
}
});
} else if (command.equals("Lens correction")) {
final Layer la = layer;
la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
final Bureaucrat burro = DistortionCorrectionTask.correctDistortionFromSelection(selection);
burro.addPostTask(new Runnable() {
@Override
public void run() {
// no means to know which where modified and from which layers!
la.getParent().addDataEditStep(new HashSet<Displayable>(la.getParent().getDisplayables()));
}
});
} else if (command.equals("Link images...")) {
final GenericDialog gd = new GenericDialog("Options");
gd.addMessage("Linking images to images (within their own layer only):");
final String[] options = { "all images to all images", "each image with any other overlapping image" };
gd.addChoice("Link: ", options, options[1]);
final String[] options2 = { "selected images only", "all images in this layer", "all images in all layers, within the layer only", "all images in all layers, within and across consecutive layers" };
gd.addChoice("Apply to: ", options2, options2[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer lay = layer;
final HashSet<Displayable> ds = new HashSet<Displayable>(lay.getParent().getDisplayables());
lay.getParent().addDataEditStep(ds, new String[] { "data" });
final boolean overlapping_only = 1 == gd.getNextChoiceIndex();
Collection<Displayable> coll = null;
switch(gd.getNextChoiceIndex()) {
case 0:
coll = selection.getSelected(Patch.class);
Patch.crosslink(coll, overlapping_only);
break;
case 1:
coll = lay.getDisplayables(Patch.class);
Patch.crosslink(coll, overlapping_only);
break;
case 2:
coll = new ArrayList<Displayable>();
for (final Layer la : lay.getParent().getLayers()) {
final Collection<Displayable> acoll = la.getDisplayables(Patch.class);
Patch.crosslink(acoll, overlapping_only);
coll.addAll(acoll);
}
break;
case 3:
final ArrayList<Layer> layers = lay.getParent().getLayers();
Collection<Displayable> lc1 = layers.get(0).getDisplayables(Patch.class);
if (lay == layers.get(0))
coll = lc1;
for (int i = 1; i < layers.size(); i++) {
final Collection<Displayable> lc2 = layers.get(i).getDisplayables(Patch.class);
if (null == coll && Display.this.layer == layers.get(i))
coll = lc2;
final Collection<Displayable> both = new ArrayList<Displayable>();
both.addAll(lc1);
both.addAll(lc2);
Patch.crosslink(both, overlapping_only);
lc1 = lc2;
}
break;
}
if (null != coll)
Display.updateCheckboxes(coll, DisplayablePanel.LINK_STATE, true);
lay.getParent().addDataEditStep(ds);
} else if (command.equals("Unlink all selected images")) {
if (Utils.check("Really unlink selected images?")) {
final Collection<Displayable> ds = selection.getSelected(Patch.class);
for (final Displayable d : ds) {
d.unlink();
}
Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
}
} else if (command.equals("Unlink all")) {
if (Utils.check("Really unlink all objects from all layers?")) {
final Collection<Displayable> ds = layer.getParent().getDisplayables();
for (final Displayable d : ds) {
d.unlink();
}
Display.updateCheckboxes(ds, DisplayablePanel.LINK_STATE);
}
} else if (command.equals("Calibration...")) {
try {
IJ.run(canvas.getFakeImagePlus(), "Properties...", "");
Display.updateTitle(getLayerSet());
// repaint layer names
project.getLayerTree().updateUILater();
} catch (final RuntimeException re) {
Utils.log2("Calibration dialog canceled.");
}
} else if (command.equals("Grid overlay...")) {
if (null == gridoverlay)
gridoverlay = new GridOverlay();
gridoverlay.setup(canvas.getFakeImagePlus().getRoi());
canvas.repaint(false);
} else if (command.equals("Enhance contrast (selected images)...")) {
final Layer la = layer;
final ArrayList<Displayable> selected = selection.getSelected(Patch.class);
final HashSet<Displayable> ds = new HashSet<Displayable>(selected);
la.getParent().addDataEditStep(ds);
final Displayable active = Display.this.getActive();
final Patch ref = active.getClass() == Patch.class ? (Patch) active : null;
final Bureaucrat burro = getProject().getLoader().enhanceContrast(selected, ref);
burro.addPostTask(new Runnable() {
@Override
public void run() {
la.getParent().addDataEditStep(ds);
}
});
} else if (command.equals("Enhance contrast layer-wise...")) {
// ask for range of layers
final GenericDialog gd = new GenericDialog("Choose range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.showDialog();
if (gd.wasCanceled())
return;
// exclusive end
final java.util.List<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final HashSet<Displayable> ds = new HashSet<Displayable>();
for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().enhanceContrast(layers);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Adjust image filters (selected images)")) {
if (selection.isEmpty() || !(active instanceof Patch))
return;
FilterEditor.GUI(selection.get(Patch.class), (Patch) active);
} else if (command.equals("Set Min and Max layer-wise...")) {
final Displayable active = getActive();
double min = 0;
double max = 0;
if (null != active && active.getClass() == Patch.class) {
min = ((Patch) active).getMin();
max = ((Patch) active).getMax();
}
final GenericDialog gd = new GenericDialog("Min and Max");
gd.addMessage("Set min and max to all images in the layer range");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addNumericField("min: ", min, 2);
gd.addNumericField("max: ", max, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
//
min = gd.getNextNumber();
max = gd.getNextNumber();
final ArrayList<Displayable> al = new ArrayList<Displayable>();
for (final Layer la : layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1)) {
// exclusive end
al.addAll(la.getDisplayables(Patch.class));
}
final HashSet<Displayable> ds = new HashSet<Displayable>(al);
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().setMinAndMax(al, min, max);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Set Min and Max (selected images)...")) {
final Displayable active = getActive();
double min = 0;
double max = 0;
if (null != active && active.getClass() == Patch.class) {
min = ((Patch) active).getMin();
max = ((Patch) active).getMax();
}
final GenericDialog gd = new GenericDialog("Min and Max");
gd.addMessage("Set min and max to all selected images");
gd.addNumericField("min: ", min, 2);
gd.addNumericField("max: ", max, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
//
min = gd.getNextNumber();
max = gd.getNextNumber();
final HashSet<Displayable> ds = new HashSet<Displayable>(selection.getSelected(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().setMinAndMax(selection.getSelected(Patch.class), min, max);
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Adjust min and max (selected images)...")) {
adjustMinAndMaxGUI();
} else if (command.equals("Mask image borders (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Mask borders");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addMessage("Borders:");
gd.addNumericField("left: ", 6, 2);
gd.addNumericField("top: ", 6, 2);
gd.addNumericField("right: ", 6, 2);
gd.addNumericField("bottom: ", 6, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final HashSet<Displayable> ds = new HashSet<Displayable>();
for (final Layer l : layers) ds.addAll(l.getDisplayables(Patch.class));
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().maskBordersLayerWise(layers, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Mask image borders (selected images)...")) {
final GenericDialog gd = new GenericDialog("Mask borders");
gd.addMessage("Borders:");
gd.addNumericField("left: ", 6, 2);
gd.addNumericField("top: ", 6, 2);
gd.addNumericField("right: ", 6, 2);
gd.addNumericField("bottom: ", 6, 2);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Displayable> patches = selection.getSelected(Patch.class);
final HashSet<Displayable> ds = new HashSet<Displayable>(patches);
getLayerSet().addDataEditStep(ds);
final Bureaucrat burro = project.getLoader().maskBorders(patches, (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
burro.addPostTask(new Runnable() {
@Override
public void run() {
getLayerSet().addDataEditStep(ds);
}
});
} else if (command.equals("Remove alpha masks (layer-wise)...")) {
final GenericDialog gd = new GenericDialog("Remove alpha masks");
Utils.addLayerRangeChoices(Display.this.layer, gd);
gd.addCheckbox("Visible only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final Collection<Layer> layers = layer.getParent().getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
final boolean visible_only = gd.getNextBoolean();
final Collection<Patch> patches = new ArrayList<Patch>();
for (final Layer l : layers) {
patches.addAll((Collection<Patch>) (Collection) l.getDisplayables(Patch.class, visible_only));
}
Display.removeAlphaMasks(patches);
} else if (command.equals("Remove alpha masks (selected images)...")) {
Display.removeAlphaMasks(selection.get(Patch.class));
} else if (command.equals("Split images under polyline ROI")) {
final Roi roi = canvas.getFakeImagePlus().getRoi();
if (null == roi)
return;
if (!(roi.getType() == Roi.POLYLINE || roi.getType() == Roi.FREELINE)) {
Utils.showMessage("Need a polyline or freeline ROI, not just any ROI!");
return;
}
if (!Utils.check("Really split images under the ROI?")) {
return;
}
// OK identify images whose contour intersects the ROI
final Set<Displayable> col = new HashSet<Displayable>();
// FreehandRoi is a subclass of PolygonRoi
final PolygonRoi proi = (PolygonRoi) roi;
final int[] x = proi.getXCoordinates(), y = proi.getYCoordinates();
final Rectangle b = proi.getBounds();
final Polygon[] pols = new Polygon[proi.getNCoordinates() - 1];
for (int i = 0; i < pols.length; i++) {
pols[i] = new Polygon(new int[] { b.x + x[i], b.x + x[i] + 1, b.x + x[i + 1], b.x + x[i + 1] + 1 }, new int[] { b.y + y[i], b.y + y[i], b.y + y[i + 1], b.y + y[i + 1] }, 4);
}
for (final Patch p : getLayer().getAll(Patch.class)) {
if (!p.isVisible())
continue;
final Area a = p.getArea();
for (int i = 0; i < pols.length; i++) {
final Area c = new Area(pols[i]);
c.intersect(a);
if (M.isEmpty(c))
continue;
// Else, add it:
col.add(p);
break;
}
}
if (col.isEmpty()) {
Utils.showMessage("No images intersect the ROI!");
return;
}
for (int i = 1; i < proi.getNCoordinates(); i++) {
for (int k = i + 2; k < proi.getNCoordinates(); k++) {
// check if the two segments intersect
if (null != M.computeSegmentsIntersection(x[i - 1], y[i - 1], x[i], y[i], x[k - 1], y[k - 1], x[k], y[k])) {
Utils.showMessage("Cannot split images with a polygon ROI that intersects itself!");
return;
}
}
}
final Area[] as = M.splitArea(new Area(getLayerSet().get2DBounds()), proi, getLayerSet().get2DBounds());
final Color[] c = new Color[] { Color.blue, Color.red };
int i = 0;
for (final Area a : as) {
// Utils.log2("Added overlay " + i + " with color " + c[i] + " and area " + AreaCalculations.area(a.getPathIterator(null)));
getLayer().getOverlay().add(a, c[i++], null, true, false, 0.4f);
}
Display.repaint(getLayer());
final YesNoDialog yn = new YesNoDialog(frame, "Check", "Does the splitting match your expectations?\nPush 'yes' to split the images.", false);
yn.setModal(false);
for (final WindowListener wl : yn.getWindowListeners()) yn.removeWindowListener(wl);
yn.setClosingTask(new Runnable() {
@Override
public void run() {
try {
// Remove overlay shapes
for (final Area a : as) {
getLayer().getOverlay().remove(a);
}
if (!yn.yesPressed()) {
Utils.log2("Pushed 'no'");
return;
}
// Split intersecting patches
// Duplicate each intersecting patch, and assign a[0] to the original and a[1] to the copy, as mask.
Bureaucrat.createAndStart(new Worker.Task("Spliting images") {
@Override
public void exec() {
final Roi r1 = new ShapeRoi(as[0]), r2 = new ShapeRoi(as[1]);
final ArrayList<Future<?>> fus = new ArrayList<Future<?>>();
for (final Patch p : (Collection<Patch>) (Collection) col) {
final Patch copy = (Patch) p.clone(p.getProject(), false);
p.addAlphaMask(r1, 0);
copy.addAlphaMask(r2, 0);
fus.add(p.updateMipMaps());
fus.add(copy.updateMipMaps());
// after submitting mipmaps, since it will get added to all Displays and repainted.
p.getLayer().add(copy);
}
Utils.wait(fus);
}
}, project);
} catch (final Throwable t) {
IJError.print(t);
} finally {
yn.dispose();
Display.repaint(getLayer());
}
}
});
yn.setVisible(true);
} else if (command.equals("Duplicate")) {
// only Patch and DLabel, i.e. Layer-only resident objects that don't exist in the Project Tree
final HashSet<Class> accepted = new HashSet<Class>();
accepted.add(Patch.class);
accepted.add(DLabel.class);
accepted.add(Stack.class);
final ArrayList<Displayable> originals = new ArrayList<Displayable>();
final ArrayList<Displayable> selected = selection.getSelected();
for (final Displayable d : selected) {
if (accepted.contains(d.getClass())) {
originals.add(d);
}
}
if (originals.size() > 0) {
getLayerSet().addChangeTreesStep();
for (final Displayable d : originals) {
if (d instanceof ZDisplayable) {
d.getLayerSet().add((ZDisplayable) d.clone());
} else {
d.getLayer().add(d.clone());
}
}
getLayerSet().addChangeTreesStep();
} else if (selected.size() > 0) {
Utils.log("Can only duplicate images and text labels.\nDuplicate *other* objects in the Project Tree.\n");
}
} else if (command.equals("Create subproject")) {
// Choose a 2D rectangle
final Roi roi = canvas.getFakeImagePlus().getRoi();
Rectangle bounds;
if (null != roi) {
if (!Utils.check("Use bounds as defined by the ROI:\n" + roi.getBounds() + " ?"))
return;
bounds = roi.getBounds();
} else
bounds = getLayerSet().get2DBounds();
// Choose a layer range, and whether to ignore hidden images
final GenericDialog gd = new GenericDialog("Choose layer range");
Utils.addLayerRangeChoices(layer, gd);
gd.addCheckbox("Ignore hidden images", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final Layer first = layer.getParent().getLayer(gd.getNextChoiceIndex());
final Layer last = layer.getParent().getLayer(gd.getNextChoiceIndex());
final boolean ignore_hidden_patches = gd.getNextBoolean();
final Project sub = getProject().createSubproject(bounds, first, last, ignore_hidden_patches);
if (null == sub) {
Utils.log("ERROR: failed to create subproject.");
return;
}
final LayerSet subls = sub.getRootLayerSet();
Display.createDisplay(sub, subls.getLayer(0));
} else if (command.startsWith("Image stack under selected Arealist")) {
if (null == active || active.getClass() != AreaList.class)
return;
final GenericDialog gd = new GenericDialog("Stack options");
final String[] types = { "8-bit", "16-bit", "32-bit", "RGB" };
gd.addChoice("type:", types, types[0]);
gd.addSlider("Scale: ", 1, 100, 100);
gd.showDialog();
if (gd.wasCanceled())
return;
final int type;
switch(gd.getNextChoiceIndex()) {
case 0:
type = ImagePlus.GRAY8;
break;
case 1:
type = ImagePlus.GRAY16;
break;
case 2:
type = ImagePlus.GRAY32;
break;
case 3:
type = ImagePlus.COLOR_RGB;
break;
default:
type = ImagePlus.GRAY8;
break;
}
final ImagePlus imp = ((AreaList) active).getStack(type, gd.getNextNumber() / 100);
if (null != imp)
imp.show();
} else if (command.equals("Fly through selected Treeline/AreaTree")) {
if (null == active || !(active instanceof Tree<?>))
return;
Bureaucrat.createAndStart(new Worker.Task("Creating fly through", true) {
@Override
public void exec() {
final GenericDialog gd = new GenericDialog("Fly through");
gd.addNumericField("Width", 512, 0);
gd.addNumericField("Height", 512, 0);
final String[] types = new String[] { "8-bit gray", "Color RGB" };
gd.addChoice("Image type", types, types[0]);
gd.addSlider("scale", 0, 100, 100);
gd.addCheckbox("save to file", false);
gd.showDialog();
if (gd.wasCanceled())
return;
final int w = (int) gd.getNextNumber();
final int h = (int) gd.getNextNumber();
final int type = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY8 : ImagePlus.COLOR_RGB;
final double scale = gd.getNextNumber();
if (w <= 0 || h <= 0) {
Utils.log("Invalid width or height: " + w + ", " + h);
return;
}
if (0 == scale || Double.isNaN(scale)) {
Utils.log("Invalid scale: " + scale);
return;
}
String dir = null;
if (gd.getNextBoolean()) {
final DirectoryChooser dc = new DirectoryChooser("Target directory");
dir = dc.getDirectory();
// canceled
if (null == dir)
return;
dir = Utils.fixDir(dir);
}
final ImagePlus imp = ((Tree<?>) active).flyThroughMarked(w, h, scale / 100, type, dir);
if (null == imp) {
Utils.log("Mark a node first!");
return;
}
imp.show();
}
}, project);
} else if (command.startsWith("Arealists as labels")) {
final GenericDialog gd = new GenericDialog("Export labels");
gd.addSlider("Scale: ", 1, 100, 100);
final String[] options = { "All area list", "Selected area lists" };
gd.addChoice("Export: ", options, options[0]);
Utils.addLayerRangeChoices(layer, gd);
gd.addCheckbox("Visible only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final float scale = (float) (gd.getNextNumber() / 100);
final java.util.List<Displayable> al = (java.util.List<Displayable>) (0 == gd.getNextChoiceIndex() ? layer.getParent().getZDisplayables(AreaList.class) : selection.getSelectedSorted(AreaList.class));
if (null == al) {
Utils.log("No area lists found to export.");
return;
}
// Generics are ... a pain? I don't understand them? They fail when they shouldn't? And so easy to workaround that they are a shame?
final int first = gd.getNextChoiceIndex();
final int last = gd.getNextChoiceIndex();
final boolean visible_only = gd.getNextBoolean();
if (-1 != command.indexOf("(amira)")) {
AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, true, true);
} else if (-1 != command.indexOf("(tif)")) {
AreaList.exportAsLabels(al, canvas.getFakeImagePlus().getRoi(), scale, first, last, visible_only, false, false);
}
} else if (command.equals("Project properties...")) {
project.adjustProperties();
} else if (command.equals("Release memory...")) {
Bureaucrat.createAndStart(new Worker("Releasing memory") {
@Override
public void run() {
startedWorking();
try {
final GenericDialog gd = new GenericDialog("Release Memory");
final int max = (int) (IJ.maxMemory() / 1000000);
gd.addSlider("Megabytes: ", 0, max, max / 2);
gd.showDialog();
if (!gd.wasCanceled()) {
final int n_mb = (int) gd.getNextNumber();
project.getLoader().releaseToFit((long) n_mb * 1000000);
}
} catch (final Throwable e) {
IJError.print(e);
} finally {
finishedWorking();
}
}
}, project);
} else if (command.equals("Create sibling project with retiled layers")) {
final GenericDialog gd = new GenericDialog("Export flattened layers");
gd.addNumericField("Tile_width", 2048, 0);
gd.addNumericField("Tile_height", 2048, 0);
final String[] types = new String[] { "16-bit", "RGB color" };
gd.addChoice("Export_image_type", types, types[0]);
gd.addCheckbox("Create mipmaps", true);
gd.addNumericField("Number_of_threads_to_use", Runtime.getRuntime().availableProcessors(), 0);
gd.showDialog();
if (gd.wasCanceled())
return;
final DirectoryChooser dc = new DirectoryChooser("Choose target folder");
final String folder = dc.getDirectory();
if (null == folder)
return;
final int tileWidth = (int) gd.getNextNumber(), tileHeight = (int) gd.getNextNumber();
if (tileWidth < 0 || tileHeight < 0) {
Utils.showMessage("Invalid tile sizes: " + tileWidth + ", " + tileHeight);
return;
}
if (tileWidth != tileHeight) {
if (!Utils.check("The tile width (" + tileWidth + ") differs from the tile height (" + tileHeight + ").\nContinue anyway?")) {
return;
}
}
final int imageType = 0 == gd.getNextChoiceIndex() ? ImagePlus.GRAY16 : ImagePlus.COLOR_RGB;
final boolean createMipMaps = gd.getNextBoolean();
final int nThreads = (int) gd.getNextNumber();
Bureaucrat.createAndStart(new Worker.Task("Export flattened sibling project") {
@Override
public void exec() {
try {
ProjectTiler.createRetiledSibling(project, folder, tileWidth, tileHeight, imageType, true, nThreads, createMipMaps);
} catch (final Throwable t) {
Utils.showMessage("ERROR: " + t);
IJError.print(t);
}
}
}, project);
} else if (command.equals("Flush image cache")) {
Loader.releaseAllCaches();
} else if (command.equals("Regenerate all mipmaps")) {
project.getLoader().regenerateMipMaps(getLayerSet().getDisplayables(Patch.class));
} else if (command.equals("Regenerate mipmaps (selected images)")) {
project.getLoader().regenerateMipMaps(selection.getSelected(Patch.class));
} else if (command.equals("Tags...")) {
// get a file first
final File f = Utils.chooseFile(null, "tags", ".xml");
if (null == f)
return;
if (!Utils.saveToFile(f, getLayerSet().exportTags())) {
Utils.logAll("ERROR when saving tags to file " + f.getAbsolutePath());
}
} else if (command.equals("Tags ...")) {
final String[] ff = Utils.selectFile("Import tags");
if (null == ff)
return;
final GenericDialog gd = new GenericDialog("Import tags");
final String[] modes = new String[] { "Append to current tags", "Replace current tags" };
gd.addChoice("Import tags mode:", modes, modes[0]);
gd.addMessage("Replacing current tags\nwill remove all tags\n from all nodes first!");
gd.showDialog();
if (gd.wasCanceled())
return;
getLayerSet().importTags(new StringBuilder(ff[0]).append('/').append(ff[1]).toString(), 1 == gd.getNextChoiceIndex());
} else if (command.equals("Connectivity graph...")) {
Bureaucrat.createAndStart(new Worker.Task("Connectivity graph") {
@Override
public void exec() {
Graph.extractAndShowGraph(getLayerSet());
}
}, getProject());
} else if (command.equals("NeuroML...")) {
final GenericDialog gd = new GenericDialog("Export NeuroML");
final String[] a = new String[] { "NeuroML (arbors and synapses)", "MorphML (arbors)" };
gd.addChoice("Type:", a, a[0]);
final String[] b = new String[] { "All treelines and areatrees", "Selected treelines and areatrees" };
gd.addChoice("Export:", b, b[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
final int type = gd.getNextChoiceIndex();
final int export = gd.getNextChoiceIndex();
//
final SaveDialog sd = new SaveDialog("Choose .mml file", null, ".mml");
final String filename = sd.getFileName();
// canceled
if (null == filename)
return;
final File f = new File(sd.getDirectory() + filename);
//
Bureaucrat.createAndStart(new Worker.Task("Export NeuroML") {
@Override
public void exec() {
OutputStreamWriter w = null;
try {
final Set<Tree<?>> trees = new HashSet<Tree<?>>();
Collection<? extends Displayable> ds = null;
switch(export) {
case 0:
ds = getLayerSet().getZDisplayables();
break;
case 1:
ds = selection.getSelected();
break;
}
for (final Displayable d : ds) {
if (d.getClass() == Treeline.class || d.getClass() == AreaTree.class) {
trees.add((Tree<?>) d);
}
}
if (trees.isEmpty()) {
Utils.showMessage("No trees to export!");
return;
}
//
// encoding in Latin 1 (for macosx not to mess around
w = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(f), 65536), "8859_1");
//
switch(type) {
case 0:
NeuroML.exportNeuroML(trees, w);
break;
case 1:
NeuroML.exportMorphML(trees, w);
break;
}
//
w.flush();
w.close();
//
} catch (final Throwable t) {
IJError.print(t);
try {
if (null != w)
w.close();
} catch (final Exception ee) {
IJError.print(ee);
}
}
}
}, getProject());
} else if (command.equals("Measure")) {
if (selection.isEmpty()) {
Utils.log("Nothing selected to measure!");
return;
}
selection.measure();
} else if (command.equals("Area interpolation options...")) {
final GenericDialog gd = new GenericDialog("Area interpolation");
final boolean a = project.getBooleanProperty(AreaUtils.always_interpolate_areas_with_distance_map);
gd.addCheckbox("Always use distance map method", a);
gd.showDialog();
if (gd.wasCanceled())
return;
project.setProperty(AreaUtils.always_interpolate_areas_with_distance_map, gd.getNextBoolean() ? "true" : null);
} else {
Utils.log2("Display: don't know what to do with command " + command);
}
}
});
}
Aggregations