use of qupath.lib.objects.PathObject 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.PathObject in project qupath by qupath.
the class Commands method requestShapeFeatures.
private static void requestShapeFeatures(ImageData<?> imageData, Collection<ShapeFeatures> features) {
if (imageData == null)
return;
var featureArray = features.toArray(ShapeFeatures[]::new);
if (featureArray.length == 0)
return;
Collection<PathObject> selected = imageData.getHierarchy().getSelectionModel().getSelectedObjects();
if (selected.isEmpty()) {
Dialogs.showWarningNotification("Shape features", "No objects selected!");
} else {
selected = new ArrayList<>(selected);
String featureString = Arrays.stream(featureArray).map(f -> "\"" + f.name() + "\"").collect(Collectors.joining(", "));
QP.addShapeMeasurements(imageData, selected, featureArray);
imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Add shape measurements", String.format("addShapeMeasurements(%s)", featureString)));
if (selected.size() == 1)
Dialogs.showInfoNotification("Shape features", "Shape features calculated for one object");
else
Dialogs.showInfoNotification("Shape features", "Shape features calculated for " + selected.size() + " objects");
}
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class CountingPanelCommand method makeButtonPanel.
@SuppressWarnings("deprecation")
private Pane makeButtonPanel() {
if (qupath == null)
return null;
VBox panel = new VBox();
panel.setSpacing(10);
// TilePane panel = new TilePane(Orientation.VERTICAL);
// panel.setBorder(BorderFactory.createEmptyBorder(5, 10, 10, 10));
sliderRadius = new Slider(1, 100, PathPrefs.pointRadiusProperty().get());
sliderRadius.valueProperty().addListener(event -> {
PathPrefs.pointRadiusProperty().set((int) sliderRadius.getValue());
// PathPrefs.setMinPointSeparation(sliderRadius.getValue());
qupath.getViewer().repaint();
});
// panel.setSpacing(10);
BorderPane sliderPane = new BorderPane();
sliderPane.setLeft(new Label("Point size"));
sliderPane.setCenter(sliderRadius);
// Add load/save buttons
btnLoad = new Button("Load points");
btnLoad.setOnAction(event -> {
if (hierarchy == null)
return;
File file = Dialogs.promptForFile(null, null, "TSV (Tab delimited)", new String[] { "tsv" });
if (file == null)
return;
try {
List<PathObject> pointsList = null;
if (file.toPath().toString().endsWith(".zip"))
pointsList = PointIO.readPointsObjectList(file);
else if (file.toPath().toString().endsWith(".tsv"))
pointsList = PointIO.readPoints(file);
if (pointsList != null) {
for (PathObject points : pointsList) hierarchy.addPathObject(points);
}
} catch (IOException e) {
Dialogs.showErrorMessage("Load points error", e);
}
});
btnSave = new Button("Save points");
btnSave.setOnAction(event -> {
if (countingPanel == null)
return;
// Prompt the user with choice over which annotations to save
ListView<PathObject> listView = countingPanel.getListView();
var selection = listView.getSelectionModel().getSelectedItems();
List<PathObject> pointsList = countingPanel.getPathObjects();
if (!selection.isEmpty()) {
ArrayList<String> choiceList = new ArrayList<>();
choiceList.addAll(Arrays.asList("All point annotations", "Selected objects"));
var choice = Dialogs.showChoiceDialog("Save points", "Choose point annotations to save", Arrays.asList("All points", "Selected points"), savingOption);
if (choice == null)
return;
if (choice.equals("Selected points"))
pointsList = selection;
savingOption = choice;
}
if (pointsList.isEmpty()) {
Dialogs.showErrorMessage("Save points", "No points available!");
return;
}
String defaultName = null;
try {
// Sorry, this is lazy...
defaultName = ServerTools.getDisplayableImageName(qupath.getViewer().getServer()) + "-points.tsv";
} catch (Exception e) {
// Ignore...
}
;
File file = Dialogs.promptToSaveFile(null, null, defaultName, "TSV (Tab delimited)", "tsv");
if (file == null)
return;
try {
PointIO.writePoints(file, pointsList);
} catch (IOException e) {
Dialogs.showErrorMessage("Save points error", e);
}
});
GridPane panelLoadSave = PaneTools.createColumnGridControls(btnLoad, btnSave);
var actionConvexPoints = ActionTools.createSelectableAction(PathPrefs.showPointHullsProperty(), "Show point convex hull");
var actionSelectedColor = ActionTools.createSelectableAction(PathPrefs.useSelectedColorProperty(), "Highlight selected objects by color");
var actionDetectionsToPoints = qupath.createImageDataAction(imageData -> Commands.convertDetectionsToPoints(imageData, true));
actionDetectionsToPoints.setText("Convert detections to points");
var btnConvert = ActionTools.createButton(actionDetectionsToPoints, false);
var convertPane = new Pane(btnConvert);
btnConvert.prefWidthProperty().bind(convertPane.widthProperty());
var cbConvex = ActionTools.createCheckBox(actionConvexPoints);
var cbSelected = ActionTools.createCheckBox(actionSelectedColor);
// panel.setSpacing(5);
panel.getChildren().addAll(cbConvex, cbSelected, sliderPane, convertPane, panelLoadSave);
return panel;
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class CountingPanelCommand method attemptToSelectPoints.
private void attemptToSelectPoints() {
if (hierarchy == null || countingPanel == null)
return;
logger.trace("Attempting to select");
PathObject pathObjectSelected = hierarchy.getSelectionModel().getSelectedObject();
// Try to set selected object to be a Point object
if (pathObjectSelected == null || !PathObjectTools.hasPointROI(pathObjectSelected)) {
List<PathObject> pointObjects = countingPanel.getPathObjects();
if (pointObjects.isEmpty())
hierarchy.getSelectionModel().setSelectedObject(null);
else
// Use the first point object
hierarchy.getSelectionModel().setSelectedObject(pointObjects.get(0));
}
}
use of qupath.lib.objects.PathObject in project qupath by qupath.
the class ExportObjectsCommand method runGeoJsonExport.
/**
* Run the path object GeoJSON export command.
* @param qupath
* @return success
* @throws IOException
*/
public static boolean runGeoJsonExport(QuPathGUI qupath) throws IOException {
// Get ImageData
var imageData = qupath.getImageData();
if (imageData == null)
return false;
// Get hierarchy
PathObjectHierarchy hierarchy = imageData.getHierarchy();
String allObjects = "All objects";
String selectedObjects = "Selected objects";
String defaultObjects = hierarchy.getSelectionModel().noSelection() ? allObjects : selectedObjects;
// Params
var parameterList = new ParameterList().addChoiceParameter("exportOptions", "Export ", defaultObjects, Arrays.asList(allObjects, selectedObjects), "Choose which objects to export - run a 'Select annotations/detections' command first if needed").addBooleanParameter("excludeMeasurements", "Exclude measurements", false, "Exclude object measurements during export - for large numbers of detections this can help reduce the file size").addBooleanParameter("doPretty", "Pretty JSON", false, "Pretty GeoJSON is more human-readable but results in larger file sizes").addBooleanParameter("doFeatureCollection", "Export as FeatureCollection", true, "Export as a 'FeatureCollection', which is a standard GeoJSON way to represent multiple objects; if not, a regular JSON object/array will be export").addBooleanParameter("doZip", "Compress data (zip)", false, "Compressed files take less memory");
if (!Dialogs.showParameterDialog("Export objects", parameterList))
return false;
Collection<PathObject> toProcess;
var comboChoice = parameterList.getChoiceParameterValue("exportOptions");
if (comboChoice.equals("Selected objects")) {
if (hierarchy.getSelectionModel().noSelection()) {
Dialogs.showErrorMessage("No selection", "No selection detected!");
return false;
}
toProcess = hierarchy.getSelectionModel().getSelectedObjects();
} else
toProcess = hierarchy.getObjects(null, null);
// Remove PathRootObject
toProcess = toProcess.stream().filter(e -> !e.isRootObject()).collect(Collectors.toList());
// Check if includes ellipse(s), as they will need to be polygonized
var nEllipses = toProcess.stream().filter(ann -> isEllipse(ann)).count();
if (nEllipses > 0) {
String message = nEllipses == 1 ? "1 ellipse will be polygonized, continue?" : String.format("%d ellipses will be polygonized, continue?", nEllipses);
var response = Dialogs.showYesNoDialog("Ellipse polygonization", message);
if (!response)
return false;
}
File outFile;
// Get default name & output directory
var project = qupath.getProject();
String defaultName = imageData.getServer().getMetadata().getName();
if (project != null) {
var entry = project.getEntry(imageData);
if (entry != null)
defaultName = entry.getImageName();
}
defaultName = GeneralTools.getNameWithoutExtension(defaultName);
File defaultDirectory = project == null || project.getPath() == null ? null : project.getPath().toFile();
while (defaultDirectory != null && !defaultDirectory.isDirectory()) defaultDirectory = defaultDirectory.getParentFile();
if (parameterList.getBooleanParameterValue("doZip"))
outFile = Dialogs.promptToSaveFile("Export to file", defaultDirectory, defaultName + ".zip", "ZIP archive", ".zip");
else
outFile = Dialogs.promptToSaveFile("Export to file", defaultDirectory, defaultName + ".geojson", "GeoJSON", ".geojson");
// If user cancels
if (outFile == null)
return false;
List<GeoJsonExportOptions> options = new ArrayList<>();
if (parameterList.getBooleanParameterValue("excludeMeasurements"))
options.add(GeoJsonExportOptions.EXCLUDE_MEASUREMENTS);
if (parameterList.getBooleanParameterValue("doPretty"))
options.add(GeoJsonExportOptions.PRETTY_JSON);
if (parameterList.getBooleanParameterValue("doFeatureCollection"))
options.add(GeoJsonExportOptions.FEATURE_COLLECTION);
// Export
QP.exportObjectsToGeoJson(toProcess, outFile.getAbsolutePath(), options.toArray(GeoJsonExportOptions[]::new));
// Notify user of success
int nObjects = toProcess.size();
String message = nObjects == 1 ? "1 object was exported to " + outFile.getAbsolutePath() : String.format("%d objects were exported to %s", nObjects, outFile.getAbsolutePath());
Dialogs.showInfoNotification("Succesful export", message);
// Get history workflow
var historyWorkflow = imageData.getHistoryWorkflow();
// args for workflow step
Map<String, String> map = new LinkedHashMap<>();
map.put("path", outFile.getPath());
String method = comboChoice.equals(allObjects) ? "exportAllObjectsToGeoJson" : "exportSelectedObjectsToGeoJson";
String methodTitle = comboChoice.equals(allObjects) ? "Export all objects" : "Export selected objects";
String optionsString = options.stream().map(o -> "\"" + o.name() + "\"").collect(Collectors.joining(", "));
map.put("options", optionsString);
if (!optionsString.isEmpty())
optionsString = ", " + optionsString;
String methodString = String.format("%s(%s%s)", method, "\"" + GeneralTools.escapeFilePath(outFile.getPath()) + "\"", optionsString);
historyWorkflow.addStep(new DefaultScriptableWorkflowStep(methodTitle, map, methodString));
return true;
}
Aggregations