use of qupath.lib.objects.TMACoreObject in project qupath by qupath.
the class QP method clearTMAGrid.
/**
* Remove the TMA grid from the current {@code PathObjectHierarchy}.
*
* @see #getCurrentHierarchy
*/
public static void clearTMAGrid() {
PathObjectHierarchy hierarchy = getCurrentHierarchy();
if (hierarchy == null)
return;
hierarchy.setTMAGrid(null);
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
if (selected instanceof TMACoreObject)
hierarchy.getSelectionModel().setSelectedObject(null);
}
use of qupath.lib.objects.TMACoreObject in project qupath by qupath.
the class Commands method promptToDeleteObjects.
/**
* Prompt to delete objects of a specified type, or all objects.
* @param imageData
* @param cls
*/
public static void promptToDeleteObjects(ImageData<?> imageData, Class<? extends PathObject> cls) {
if (imageData == null)
return;
PathObjectHierarchy hierarchy = imageData.getHierarchy();
// Handle no specified class - indicates all objects of all types should be cleared
if (cls == null) {
int n = hierarchy.nObjects();
if (n == 0)
return;
String message;
if (n == 1)
message = "Delete object?";
else
message = "Delete all " + n + " objects?";
if (Dialogs.showYesNoDialog("Delete objects", message)) {
hierarchy.clearAll();
hierarchy.getSelectionModel().setSelectedObject(null);
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Clear all objects", "clearAllObjects();"));
}
return;
}
// Handle clearing TMA grid
if (TMACoreObject.class.equals(cls)) {
if (hierarchy.getTMAGrid() != null) {
if (Dialogs.showYesNoDialog("Delete objects", "Clear TMA grid?")) {
hierarchy.setTMAGrid(null);
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
if (selected instanceof TMACoreObject)
hierarchy.getSelectionModel().setSelectedObject(null);
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Clear TMA Grid", "clearTMAGrid();"));
}
return;
}
}
// Handle clearing objects of another specified type
Collection<PathObject> pathObjects = hierarchy.getObjects(null, cls);
if (pathObjects.isEmpty())
return;
int n = pathObjects.size();
String message = n == 1 ? "Delete 1 object?" : "Delete " + n + " objects?";
if (Dialogs.showYesNoDialog("Delete objects", message)) {
hierarchy.removeObjects(pathObjects, true);
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
if (selected != null && selected.getClass().isAssignableFrom(cls))
hierarchy.getSelectionModel().setSelectedObject(null);
if (selected != null && selected.getClass().isAssignableFrom(cls))
hierarchy.getSelectionModel().setSelectedObject(null);
if (cls == PathDetectionObject.class)
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Clear detections", "clearDetections();"));
else if (cls == PathAnnotationObject.class)
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Clear annotations", "clearAnnotations();"));
else if (cls == TMACoreObject.class)
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Clear TMA grid", "clearTMAGrid();"));
else
logger.warn("Cannot clear all objects for class {}", cls);
}
}
use of qupath.lib.objects.TMACoreObject in project qupath by qupath.
the class TMACommands method promptToDeleteTMAGridRowOrColumn.
private static boolean promptToDeleteTMAGridRowOrColumn(ImageData<?> imageData, TMARemoveType type) {
String typeString = type.toString();
String title = "Delete TMA " + typeString;
boolean removeRow = type == TMARemoveType.ROW;
if (imageData == null) {
Dialogs.showNoImageError(title);
return false;
}
if (imageData.getHierarchy().getTMAGrid() == null) {
Dialogs.showErrorMessage(title, "No image with dearrayed TMA cores selected!");
return false;
}
PathObjectHierarchy hierarchy = imageData.getHierarchy();
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
TMACoreObject selectedCore = null;
if (selected != null)
selectedCore = PathObjectTools.getAncestorTMACore(selected);
// Try to identify the row/column that we want
TMAGrid grid = hierarchy.getTMAGrid();
int row = -1;
int col = -1;
if (selectedCore != null) {
for (int y = 0; y < grid.getGridHeight(); y++) {
for (int x = 0; x < grid.getGridWidth(); x++) {
if (grid.getTMACore(y, x) == selectedCore) {
row = y;
col = x;
break;
}
}
}
}
// We need a selected core to know what to remove
if (row < 0 || col < 0) {
Dialogs.showErrorMessage(title, "Please select a TMA core to indicate which " + typeString + " to remove");
return false;
}
// Check we have enough rows/columns - if not, this is just a clear operation
if ((removeRow && grid.getGridHeight() <= 1) || (!removeRow && grid.getGridWidth() <= 1)) {
if (Dialogs.showConfirmDialog(title, "Are you sure you want to delete the entire TMA grid?"))
hierarchy.setTMAGrid(null);
return false;
}
// Confirm the removal - add 1 due to 'base 0' probably not being expected by most users...
int num = removeRow ? row : col;
if (!Dialogs.showConfirmDialog(title, "Are you sure you want to delete " + typeString + " " + (num + 1) + " from TMA grid?"))
return false;
// Create a new grid
List<TMACoreObject> coresNew = new ArrayList<>();
for (int r = 0; r < grid.getGridHeight(); r++) {
if (removeRow && row == r)
continue;
for (int c = 0; c < grid.getGridWidth(); c++) {
if (!removeRow && col == c)
continue;
coresNew.add(grid.getTMACore(r, c));
}
}
int newWidth = removeRow ? grid.getGridWidth() : grid.getGridWidth() - 1;
TMAGrid gridNew = DefaultTMAGrid.create(coresNew, newWidth);
hierarchy.setTMAGrid(gridNew);
hierarchy.getSelectionModel().clearSelection();
// Request new labels
promptToRelabelTMAGrid(imageData);
return true;
}
use of qupath.lib.objects.TMACoreObject in project qupath by qupath.
the class TMAGridView method initializeData.
private void initializeData(ImageData<BufferedImage> imageData) {
if (this.imageData != imageData) {
if (this.imageData != null)
this.imageData.getHierarchy().removePathObjectListener(this);
this.imageData = imageData;
if (imageData != null) {
imageData.getHierarchy().addPathObjectListener(this);
}
}
if (imageData == null || imageData.getHierarchy().getTMAGrid() == null) {
model.setImageData(null, Collections.emptyList());
grid.getItems().clear();
return;
}
// Request all core thumbnails now
List<TMACoreObject> cores = imageData.getHierarchy().getTMAGrid().getTMACoreList();
ImageServer<BufferedImage> server = imageData.getServer();
CountDownLatch latch = new CountDownLatch(cores.size());
for (TMACoreObject core : cores) {
ROI roi = core.getROI();
if (roi != null) {
qupath.submitShortTask(() -> {
RegionRequest request = createRegionRequest(core);
if (cache.containsKey(request)) {
latch.countDown();
return;
}
BufferedImage img;
try {
img = server.readBufferedImage(request);
} catch (IOException e) {
logger.debug("Unable to get tile for " + request, e);
latch.countDown();
return;
}
Image imageNew = SwingFXUtils.toFXImage(img, null);
if (imageNew != null) {
cache.put(request, imageNew);
// Platform.runLater(() -> updateGridDisplay());
}
latch.countDown();
});
} else
latch.countDown();
}
long startTime = System.currentTimeMillis();
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e1) {
if (latch.getCount() > 0)
logger.warn("Loaded {} cores in 10 seconds", cores.size() - latch.getCount());
}
logger.info("Countdown complete in {} seconds", (System.currentTimeMillis() - startTime) / 1000.0);
model.setImageData(imageData, cores);
backingList.setAll(cores);
String m = measurement.getValue();
sortCores(backingList, model, m, descending.get());
filteredList.setPredicate(p -> {
return !(p.isMissing() || Double.isNaN(model.getNumericValue(p, m)));
});
grid.getItems().setAll(filteredList);
}
use of qupath.lib.objects.TMACoreObject in project qupath by qupath.
the class QuPathGUI method setViewerPopupMenu.
private void setViewerPopupMenu(final QuPathViewerPlus viewer) {
final ContextMenu popup = new ContextMenu();
MenuItem miAddRow = new MenuItem("Add row");
miAddRow.setOnAction(e -> viewerManager.addRow(viewer));
MenuItem miAddColumn = new MenuItem("Add column");
miAddColumn.setOnAction(e -> viewerManager.addColumn(viewer));
MenuItem miRemoveRow = new MenuItem("Remove row");
miRemoveRow.setOnAction(e -> viewerManager.removeViewerRow(viewer));
MenuItem miRemoveColumn = new MenuItem("Remove column");
miRemoveColumn.setOnAction(e -> viewerManager.removeViewerColumn(viewer));
MenuItem miCloseViewer = new MenuItem("Close viewer");
miCloseViewer.setOnAction(e -> {
viewerManager.closeViewer(viewer);
// viewerManager.removeViewer(viewer);
});
MenuItem miResizeGrid = new MenuItem("Reset grid size");
miResizeGrid.setOnAction(e -> {
viewerManager.resetGridSize();
});
MenuItem miToggleSync = ActionTools.createCheckMenuItem(defaultActions.TOGGLE_SYNCHRONIZE_VIEWERS, null);
MenuItem miMatchResolutions = ActionTools.createMenuItem(defaultActions.MATCH_VIEWER_RESOLUTIONS);
Menu menuMultiview = MenuTools.createMenu("Multi-view", miToggleSync, miMatchResolutions, miCloseViewer, null, miResizeGrid, null, // null,
miAddRow, miAddColumn, null, miRemoveRow, miRemoveColumn);
Menu menuView = MenuTools.createMenu("Display", ActionTools.createCheckMenuItem(defaultActions.SHOW_ANALYSIS_PANE, null), defaultActions.BRIGHTNESS_CONTRAST, null, ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 0.25), "400%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 1), "100%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 2), "50%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 10), "10%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 100), "1%"));
ToggleGroup groupTools = new ToggleGroup();
Menu menuTools = MenuTools.createMenu("Set tool", ActionTools.createCheckMenuItem(defaultActions.MOVE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.RECTANGLE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.ELLIPSE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.LINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYGON_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYLINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.BRUSH_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POINTS_TOOL, groupTools), null, ActionTools.createCheckMenuItem(defaultActions.SELECTION_MODE));
// Handle awkward 'TMA core missing' option
CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
Menu menuTMA = new Menu("TMA");
MenuTools.addMenuItems(menuTMA, miTMAValid, miTMAMissing, null, defaultActions.TMA_ADD_NOTE, null, MenuTools.createMenu("Add", createImageDataAction(imageData -> TMACommands.promptToAddRowBeforeSelected(imageData), "Add TMA row before"), createImageDataAction(imageData -> TMACommands.promptToAddRowAfterSelected(imageData), "Add TMA row after"), createImageDataAction(imageData -> TMACommands.promptToAddColumnBeforeSelected(imageData), "Add TMA column before"), createImageDataAction(imageData -> TMACommands.promptToAddColumnAfterSelected(imageData), "Add TMA column after")), MenuTools.createMenu("Remove", createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridRow(imageData), "Remove TMA row"), createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridColumn(imageData), "column")));
// Create an empty placeholder menu
Menu menuSetClass = MenuTools.createMenu("Set class");
// CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
// miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
// CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
// miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
Menu menuCells = MenuTools.createMenu("Cells", ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES_AND_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_CENTROIDS, null));
MenuItem miClearSelectedObjects = new MenuItem("Delete object");
miClearSelectedObjects.setOnAction(e -> {
PathObjectHierarchy hierarchy = viewer.getHierarchy();
if (hierarchy == null)
return;
if (hierarchy.getSelectionModel().singleSelection()) {
GuiTools.promptToRemoveSelectedObject(hierarchy.getSelectionModel().getSelectedObject(), hierarchy);
} else {
GuiTools.promptToClearAllSelectedObjects(viewer.getImageData());
}
});
// Create a standard annotations menu
Menu menuAnnotations = GuiTools.populateAnnotationsMenu(this, new Menu("Annotations"));
SeparatorMenuItem topSeparator = new SeparatorMenuItem();
popup.setOnShowing(e -> {
// Check if we have any cells
ImageData<?> imageData = viewer.getImageData();
if (imageData == null)
menuCells.setVisible(false);
else
menuCells.setVisible(!imageData.getHierarchy().getDetectionObjects().isEmpty());
// Check what to show for TMA cores or annotations
Collection<PathObject> selectedObjects = viewer.getAllSelectedObjects();
PathObject pathObject = viewer.getSelectedObject();
menuTMA.setVisible(false);
if (pathObject instanceof TMACoreObject) {
boolean isMissing = ((TMACoreObject) pathObject).isMissing();
miTMAValid.setSelected(!isMissing);
miTMAMissing.setSelected(isMissing);
menuTMA.setVisible(true);
}
// Add clear objects option if we have more than one non-TMA object
if (imageData == null || imageData.getHierarchy().getSelectionModel().noSelection() || imageData.getHierarchy().getSelectionModel().getSelectedObject() instanceof TMACoreObject)
miClearSelectedObjects.setVisible(false);
else {
if (imageData.getHierarchy().getSelectionModel().singleSelection()) {
miClearSelectedObjects.setText("Delete object");
miClearSelectedObjects.setVisible(true);
} else {
miClearSelectedObjects.setText("Delete objects");
miClearSelectedObjects.setVisible(true);
}
}
boolean hasAnnotations = pathObject instanceof PathAnnotationObject || (!selectedObjects.isEmpty() && selectedObjects.stream().allMatch(p -> p.isAnnotation()));
updateSetAnnotationPathClassMenu(menuSetClass, viewer);
menuAnnotations.setVisible(hasAnnotations);
topSeparator.setVisible(hasAnnotations || pathObject instanceof TMACoreObject);
// Occasionally, the newly-visible top part of a popup menu can have the wrong size?
popup.setWidth(popup.getPrefWidth());
});
// popup.add(menuClassify);
popup.getItems().addAll(miClearSelectedObjects, menuTMA, menuSetClass, menuAnnotations, topSeparator, menuMultiview, menuCells, menuView, menuTools);
popup.setAutoHide(true);
// Enable circle pop-up for quick classification on right-click
CirclePopupMenu circlePopup = new CirclePopupMenu(viewer.getView(), null);
viewer.getView().addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
if ((e.isPopupTrigger() || e.isSecondaryButtonDown()) && e.isShiftDown() && !getAvailablePathClasses().isEmpty()) {
circlePopup.setAnimationDuration(Duration.millis(200));
updateSetAnnotationPathClassMenu(circlePopup, viewer);
circlePopup.show(e.getScreenX(), e.getScreenY());
e.consume();
return;
} else if (circlePopup.isShown())
circlePopup.hide();
if (e.isPopupTrigger() || e.isSecondaryButtonDown()) {
popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
e.consume();
}
});
// // It's necessary to make the Window the owner, since otherwise the context menu does not disappear when clicking elsewhere on the viewer
// viewer.getView().setOnContextMenuRequested(e -> {
// popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
// // popup.show(viewer.getView(), e.getScreenX(), e.getScreenY());
// });
}
Aggregations