use of qupath.lib.gui.dialogs.Dialogs.DialogButton in project qupath by qupath.
the class EstimateStainVectorsCommand method promptToEstimateStainVectors.
public static void promptToEstimateStainVectors(ImageData<BufferedImage> imageData) {
if (imageData == null) {
Dialogs.showNoImageError(TITLE);
return;
}
if (imageData == null || !imageData.isBrightfield() || imageData.getServer() == null || !imageData.getServer().isRGB()) {
Dialogs.showErrorMessage(TITLE, "No brightfield, RGB image selected!");
return;
}
ColorDeconvolutionStains stains = imageData.getColorDeconvolutionStains();
if (stains == null || !stains.getStain(3).isResidual()) {
Dialogs.showErrorMessage(TITLE, "Sorry, stain editing is only possible for brightfield, RGB images with 2 stains");
return;
}
PathObject pathObject = imageData.getHierarchy().getSelectionModel().getSelectedObject();
ROI roi = pathObject == null ? null : pathObject.getROI();
if (roi == null)
roi = ROIs.createRectangleROI(0, 0, imageData.getServer().getWidth(), imageData.getServer().getHeight(), ImagePlane.getDefaultPlane());
double downsample = Math.max(1, Math.sqrt((roi.getBoundsWidth() * roi.getBoundsHeight()) / MAX_PIXELS));
RegionRequest request = RegionRequest.createInstance(imageData.getServerPath(), downsample, roi);
BufferedImage img = null;
try {
img = imageData.getServer().readBufferedImage(request);
} catch (IOException e) {
Dialogs.showErrorMessage("Estimate stain vectors", e);
logger.error("Unable to obtain pixels for " + request.toString(), e);
}
// Apply small amount of smoothing to reduce compression artefacts
img = EstimateStainVectors.smoothImage(img);
// Check modes for background
int[] rgb = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
int[] rgbMode = EstimateStainVectors.getModeRGB(rgb);
int rMax = rgbMode[0];
int gMax = rgbMode[1];
int bMax = rgbMode[2];
// Check if the background values may need to be changed
if (rMax != stains.getMaxRed() || gMax != stains.getMaxGreen() || bMax != stains.getMaxBlue()) {
DialogButton response = Dialogs.showYesNoCancelDialog(TITLE, String.format("Modal RGB values %d, %d, %d do not match current background values - do you want to use the modal values?", rMax, gMax, bMax));
if (response == DialogButton.CANCEL)
return;
else if (response == DialogButton.YES) {
stains = stains.changeMaxValues(rMax, gMax, bMax);
imageData.setColorDeconvolutionStains(stains);
}
}
ColorDeconvolutionStains stainsUpdated = null;
logger.info("Requesting region for stain vector editing: ", request);
try {
stainsUpdated = showStainEditor(img, stains);
} catch (Exception e) {
Dialogs.showErrorMessage(TITLE, "Error with stain estimation: " + e.getLocalizedMessage());
logger.error("{}", e.getLocalizedMessage(), e);
// JOptionPane.showMessageDialog(qupath.getFrame(), "Error with stain estimation: " + e.getLocalizedMessage(), "Estimate stain vectors", JOptionPane.ERROR_MESSAGE, null);
return;
}
if (!stains.equals(stainsUpdated)) {
String suggestedName;
String collectiveNameBefore = stainsUpdated.getName();
if (collectiveNameBefore.endsWith("default"))
suggestedName = collectiveNameBefore.substring(0, collectiveNameBefore.lastIndexOf("default")) + "estimated";
else
suggestedName = collectiveNameBefore;
String newName = Dialogs.showInputDialog(TITLE, "Set name for stain vectors", suggestedName);
if (newName == null)
return;
if (!newName.isBlank())
stainsUpdated = stainsUpdated.changeName(newName);
imageData.setColorDeconvolutionStains(stainsUpdated);
}
}
use of qupath.lib.gui.dialogs.Dialogs.DialogButton in project qupath by qupath.
the class LegacyDetectionClassifierCommand method run.
@Override
public void run() {
if (dialog == null) {
dialog = new Stage();
if (qupath != null)
dialog.initOwner(qupath.getStage());
dialog.setTitle(name);
BorderPane pane = new BorderPane();
RTreesClassifier defaultClassifier = new RTreesClassifier();
List<OpenCvClassifier<?>> classifierList = Arrays.asList(defaultClassifier, new DTreesClassifier(), new BoostClassifier(), new BayesClassifier(), new KNearestClassifier(), new SVMClassifier(), new NeuralNetworksClassifier());
Collections.sort(classifierList, (c1, c2) -> c1.getName().compareTo(c2.getName()));
panel = new ClassifierBuilderPane<>(qupath, classifierList, defaultClassifier);
pane.setCenter(panel.getPane());
ScrollPane scrollPane = new ScrollPane(pane);
scrollPane.setFitToWidth(true);
scrollPane.setFitToHeight(true);
dialog.setScene(new Scene(scrollPane));
}
dialog.setOnCloseRequest(e -> {
// If we don't have a classifier yet, just remove completely
if (panel.getSelectedFeatures().isEmpty()) {
resetPanel();
return;
}
// If we have a classifier, give option to hide
DialogButton button = Dialogs.showYesNoCancelDialog("Classifier builder", "Retain classifier for later use?");
if (button == DialogButton.CANCEL)
e.consume();
else if (button == DialogButton.NO) {
resetPanel();
}
});
dialog.show();
dialog.setMinWidth(dialog.getWidth());
if (dialog.getHeight() < javafx.stage.Screen.getPrimary().getVisualBounds().getHeight()) {
dialog.setMinHeight(dialog.getHeight() / 2);
}
// if (dialog.getHeight() < javafx.stage.Screen.getPrimary().getVisualBounds().getHeight())
// dialog.setResizable(false);
}
use of qupath.lib.gui.dialogs.Dialogs.DialogButton in project qupath by qupath.
the class DefaultScriptEditor method promptToClose.
boolean promptToClose(final ScriptTab tab) {
int ind = listScripts.getItems().indexOf(tab);
if (ind < 0)
return false;
// Check if we need to save
if (tab.isModifiedProperty().get() && tab.hasScript()) {
// TODO: Consider that this previously had a different parent for the dialog... and probably should
DialogButton option = Dialogs.showYesNoCancelDialog("Close " + tab.getName(), String.format("Save %s before closing?", tab.getName()));
if (option == DialogButton.CANCEL)
return false;
if (option == DialogButton.YES) {
if (!save(tab, false))
return false;
}
}
// Update selection, or close window if all scripts have been closed
listScripts.getItems().remove(ind);
if (ind >= listScripts.getItems().size())
ind--;
if (ind < 0) {
dialog.close();
dialog = null;
} else
listScripts.getSelectionModel().select(ind);
return true;
}
use of qupath.lib.gui.dialogs.Dialogs.DialogButton in project qupath by qupath.
the class QuPathGUI method promptToSaveChangesOrCancel.
/**
* Show a prompt to save changes for an ImageData.
* <p>
* Note the return value indicates whether the user cancelled or not, rather than whether the data
* was saved or not.
*
* @param dialogTitle
* @param imageData
* @return true if the prompt 'succeeded' (i.e. user chose 'Yes' or 'No'), false if it was cancelled.
*/
private boolean promptToSaveChangesOrCancel(String dialogTitle, ImageData<BufferedImage> imageData) {
var project = getProject();
var entry = project == null ? null : project.getEntry(imageData);
File filePrevious = null;
if (entry == null) {
String lastPath = imageData.getLastSavedPath();
filePrevious = lastPath == null ? null : new File(lastPath);
}
DialogButton response = DialogButton.YES;
if (imageData.isChanged()) {
response = Dialogs.showYesNoCancelDialog(dialogTitle, "Save changes to " + ServerTools.getDisplayableImageName(imageData.getServer()) + "?");
}
if (response == DialogButton.CANCEL)
return false;
if (response == DialogButton.YES) {
if (filePrevious == null && entry == null) {
filePrevious = Dialogs.promptToSaveFile("Save image data", filePrevious, ServerTools.getDisplayableImageName(imageData.getServer()), "QuPath Serialized Data", PathPrefs.getSerializationExtension());
if (filePrevious == null)
return false;
}
try {
if (entry != null) {
entry.saveImageData(imageData);
// Should make sure we save the project in case metadata has changed as well
project.syncChanges();
} else
PathIO.writeImageData(filePrevious, imageData);
} catch (IOException e) {
Dialogs.showErrorMessage("Save ImageData", e);
}
}
return true;
}
use of qupath.lib.gui.dialogs.Dialogs.DialogButton in project qupath by qupath.
the class RigidObjectEditorCommand method commitChanges.
private void commitChanges(final boolean ignoreChanges) {
if (this.originalObject == null)
return;
// PathObject pathObject = null;
if (!ignoreChanges) {
DialogButton option = Dialogs.showYesNoCancelDialog("Affine object editing", "Confirm object changes?");
if (option == DialogButton.CANCEL)
return;
if (option == DialogButton.NO) {
for (Entry<PathObject, ROI> entry : originalObjectROIs.entrySet()) ((PathROIObject) entry.getKey()).setROI(entry.getValue());
} else {
var transform = transformer.transform;
var values = transform.getMatrixEntries();
logger.info("Applied ROI transform: {}", String.format("\n %f, %f, %f,\n%f, %f, %f", values[0], values[1], values[2], values[3], values[4], values[5]));
// Apply clipping now
for (Entry<PathObject, ROI> entry : originalObjectROIs.entrySet()) {
ROI roiTransformed = transformer.getTransformedROI(entry.getValue(), true);
((PathROIObject) entry.getKey()).setROI(roiTransformed);
}
viewer.getHierarchy().fireHierarchyChangedEvent(this, originalObject);
}
}
// Update the mode if the viewer is still active
qupath.setToolSwitchingEnabled(true);
if (viewer == qupath.getViewer())
viewer.setActiveTool(qupath.getSelectedTool());
viewer.getView().removeEventHandler(MouseEvent.ANY, mouseListener);
viewer.getCustomOverlayLayers().remove(overlay);
viewer.removeViewerListener(this);
// if (pathObject != null)
// viewer.getHierarchy().addPathObject(pathObject, true);
// // Ensure the object is selected
// viewer.setSelectedObject(pathObject);
viewer = null;
overlay = null;
originalObjectROIs.clear();
originalObject = null;
transformer = null;
}
Aggregations