use of qupath.lib.images.ImageData in project qupath by qupath.
the class Commands method promptToSimplifySelectedAnnotations.
/**
* Show a prompt to selected annotations in a hierarchy.
* @param imageData the current image data
* @param altitudeThreshold default altitude value for simplification
*/
public static void promptToSimplifySelectedAnnotations(ImageData<?> imageData, double altitudeThreshold) {
PathObjectHierarchy hierarchy = imageData.getHierarchy();
List<PathObject> pathObjects = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p.hasROI() && p.isEditable() && !p.getROI().isPoint()).collect(Collectors.toList());
if (pathObjects.isEmpty()) {
Dialogs.showErrorMessage("Simplify annotations", "No unlocked shape annotations selected!");
return;
}
String input = Dialogs.showInputDialog("Simplify shape", "Set altitude threshold in pixels.\nHigher values give simpler shapes.", Double.toString(altitudeThreshold));
if (input == null || !(input instanceof String) || ((String) input).trim().length() == 0)
return;
try {
altitudeThreshold = Double.parseDouble(((String) input).trim());
} catch (NumberFormatException e) {
logger.error("Could not parse altitude threshold from {}", input);
return;
}
if (altitudeThreshold <= 0) {
Dialogs.showErrorMessage("Simplify shape", "Amplitude threshold should be greater than zero!");
return;
}
long startTime = System.currentTimeMillis();
for (var pathObject : pathObjects) {
ROI pathROI = pathObject.getROI();
if (pathROI instanceof PolygonROI) {
PolygonROI polygonROI = (PolygonROI) pathROI;
pathROI = ShapeSimplifier.simplifyPolygon(polygonROI, altitudeThreshold);
} else {
pathROI = ShapeSimplifier.simplifyShape(pathROI, altitudeThreshold);
}
((PathAnnotationObject) pathObject).setROI(pathROI);
}
long endTime = System.currentTimeMillis();
logger.debug("Shapes simplified in " + (endTime - startTime) + " ms");
hierarchy.fireObjectsChangedEvent(hierarchy, pathObjects);
}
use of qupath.lib.images.ImageData in project qupath by qupath.
the class GuiTools method createAnnotationsMenuImpl.
private static void createAnnotationsMenuImpl(QuPathGUI qupath, Object menu) {
// Add annotation options
CheckMenuItem miLockAnnotations = new CheckMenuItem("Lock");
CheckMenuItem miUnlockAnnotations = new CheckMenuItem("Unlock");
miLockAnnotations.setOnAction(e -> setSelectedAnnotationLock(qupath.getImageData(), true));
miUnlockAnnotations.setOnAction(e -> setSelectedAnnotationLock(qupath.getImageData(), false));
MenuItem miSetProperties = new MenuItem("Set properties");
miSetProperties.setOnAction(e -> {
var hierarchy = qupath.getViewer().getHierarchy();
if (hierarchy != null)
GuiTools.promptToSetActiveAnnotationProperties(hierarchy);
});
var actionInsertInHierarchy = qupath.createImageDataAction(imageData -> Commands.insertSelectedObjectsInHierarchy(imageData));
actionInsertInHierarchy.setText("Insert in hierarchy");
var miInsertHierarchy = ActionTools.createMenuItem(actionInsertInHierarchy);
var actionMerge = qupath.createImageDataAction(imageData -> Commands.mergeSelectedAnnotations(imageData));
actionMerge.setText("Merge selected");
var actionSubtract = qupath.createImageDataAction(imageData -> Commands.combineSelectedAnnotations(imageData, CombineOp.SUBTRACT));
actionSubtract.setText("Subtract selected");
var actionIntersect = qupath.createImageDataAction(imageData -> Commands.combineSelectedAnnotations(imageData, CombineOp.INTERSECT));
actionIntersect.setText("Intersect selected");
var actionInverse = qupath.createImageDataAction(imageData -> Commands.makeInverseAnnotation(imageData));
actionInverse.setText("Make inverse");
Menu menuCombine = MenuTools.createMenu("Edit multiple", actionMerge, // TODO: Make this less ambiguous!
actionSubtract, actionIntersect);
Menu menuEdit = MenuTools.createMenu("Edit single", actionInverse, qupath.createPluginAction("Split", SplitAnnotationsPlugin.class, null));
// Menu menuPoints = MenuTools.createMenu(
// "Points",
// QuPathGUI.createCommandAction(new MergePointsCommand(qupath, true), "Merge all points for class"),
// QuPathGUI.createCommandAction(new MergePointsCommand(qupath, true), "Merge selected points for class")
// );
MenuItem separator = new SeparatorMenuItem();
Runnable validator = () -> {
var imageData = qupath.getImageData();
PathObject selected = null;
Collection<PathObject> allSelected = Collections.emptyList();
boolean allSelectedAnnotations = false;
boolean hasSelectedAnnotation = false;
if (imageData != null) {
selected = imageData.getHierarchy().getSelectionModel().getSelectedObject();
allSelected = new ArrayList<>(imageData.getHierarchy().getSelectionModel().getSelectedObjects());
hasSelectedAnnotation = selected != null && selected.isAnnotation();
allSelectedAnnotations = allSelected.stream().allMatch(p -> p.isAnnotation());
}
miLockAnnotations.setDisable(!hasSelectedAnnotation);
miUnlockAnnotations.setDisable(!hasSelectedAnnotation);
if (hasSelectedAnnotation) {
boolean isLocked = selected.isLocked();
miLockAnnotations.setSelected(isLocked);
miUnlockAnnotations.setSelected(!isLocked);
}
miSetProperties.setDisable(!hasSelectedAnnotation);
miInsertHierarchy.setVisible(selected != null);
menuEdit.setVisible(hasSelectedAnnotation);
menuCombine.setVisible(allSelectedAnnotations && allSelected.size() > 1);
separator.setVisible(menuEdit.isVisible() || menuCombine.isVisible());
};
List<MenuItem> items;
if (menu instanceof Menu) {
Menu m = (Menu) menu;
items = m.getItems();
m.setOnMenuValidation(e -> validator.run());
} else if (menu instanceof ContextMenu) {
ContextMenu m = (ContextMenu) menu;
items = m.getItems();
m.setOnShowing(e -> validator.run());
} else
throw new IllegalArgumentException("Menu must be either a standard Menu or a ContextMenu!");
MenuTools.addMenuItems(items, miLockAnnotations, miUnlockAnnotations, miSetProperties, miInsertHierarchy, separator, menuEdit, menuCombine);
}
Aggregations