use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class ImageDetailsPane method promptToSetPixelSize.
static boolean promptToSetPixelSize(ImageData<BufferedImage> imageData, boolean requestZSpacing) {
var server = imageData.getServer();
var hierarchy = imageData.getHierarchy();
var selected = hierarchy.getSelectionModel().getSelectedObject();
var roi = selected == null ? null : selected.getROI();
PixelCalibration cal = server.getPixelCalibration();
double pixelWidthMicrons = cal.getPixelWidthMicrons();
double pixelHeightMicrons = cal.getPixelHeightMicrons();
double zSpacingMicrons = cal.getZSpacingMicrons();
// Use line or area ROI if possible
if (!requestZSpacing && roi != null && !roi.isEmpty() && (roi.isArea() || roi.isLine())) {
boolean setPixelHeight = true;
boolean setPixelWidth = true;
String message;
String units = GeneralTools.micrometerSymbol();
double pixelWidth = cal.getPixelWidthMicrons();
double pixelHeight = cal.getPixelHeightMicrons();
if (!Double.isFinite(pixelWidth))
pixelWidth = 1;
if (!Double.isFinite(pixelHeight))
pixelHeight = 1;
Double defaultValue = null;
if (roi.isLine()) {
setPixelHeight = roi.getBoundsHeight() != 0;
setPixelWidth = roi.getBoundsWidth() != 0;
message = "Enter selected line length";
defaultValue = roi.getScaledLength(pixelWidth, pixelHeight);
} else {
message = "Enter selected ROI area";
units = units + "^2";
defaultValue = roi.getScaledArea(pixelWidth, pixelHeight);
}
// }
if (Double.isNaN(defaultValue))
defaultValue = 1.0;
var params = new ParameterList().addDoubleParameter("inputValue", message, defaultValue, units, "Enter calibrated value in " + units + " for the selected ROI to calculate the pixel size").addBooleanParameter("squarePixels", "Assume square pixels", true, "Set the pixel width to match the pixel height");
params.setHiddenParameters(setPixelHeight && setPixelWidth, "squarePixels");
if (!Dialogs.showParameterDialog("Set pixel size", params))
return false;
Double result = params.getDoubleParameterValue("inputValue");
setPixelHeight = setPixelHeight || params.getBooleanParameterValue("squarePixels");
setPixelWidth = setPixelWidth || params.getBooleanParameterValue("squarePixels");
// Double result = Dialogs.showInputDialog("Set pixel size", message, defaultValue);
// if (result == null)
// return false;
double sizeMicrons;
if (roi.isLine())
sizeMicrons = result.doubleValue() / roi.getLength();
else
sizeMicrons = Math.sqrt(result.doubleValue() / roi.getArea());
if (setPixelHeight)
pixelHeightMicrons = sizeMicrons;
if (setPixelWidth)
pixelWidthMicrons = sizeMicrons;
} else {
// Prompt for all required values
ParameterList params = new ParameterList().addDoubleParameter("pixelWidth", "Pixel width", pixelWidthMicrons, GeneralTools.micrometerSymbol(), "Enter the pixel width").addDoubleParameter("pixelHeight", "Pixel height", pixelHeightMicrons, GeneralTools.micrometerSymbol(), "Entry the pixel height").addDoubleParameter("zSpacing", "Z-spacing", zSpacingMicrons, GeneralTools.micrometerSymbol(), "Enter the spacing between slices of a z-stack");
params.setHiddenParameters(server.nZSlices() == 1, "zSpacing");
if (!Dialogs.showParameterDialog("Set pixel size", params))
return false;
if (server.nZSlices() != 1) {
zSpacingMicrons = params.getDoubleParameterValue("zSpacing");
}
pixelWidthMicrons = params.getDoubleParameterValue("pixelWidth");
pixelHeightMicrons = params.getDoubleParameterValue("pixelHeight");
}
if ((pixelWidthMicrons <= 0 || pixelHeightMicrons <= 0) || (server.nZSlices() > 1 && zSpacingMicrons <= 0)) {
if (!Dialogs.showConfirmDialog("Set pixel size", "You entered values <= 0, do you really want to remove this pixel calibration information?")) {
return false;
}
zSpacingMicrons = server.nZSlices() > 1 && zSpacingMicrons > 0 ? zSpacingMicrons : Double.NaN;
if (pixelWidthMicrons <= 0 || pixelHeightMicrons <= 0) {
pixelWidthMicrons = Double.NaN;
pixelHeightMicrons = Double.NaN;
}
}
if (QP.setPixelSizeMicrons(imageData, pixelWidthMicrons, pixelHeightMicrons, zSpacingMicrons)) {
// Log for scripts
WorkflowStep step;
if (server.nZSlices() == 1) {
var map = Map.of("pixelWidthMicrons", pixelWidthMicrons, "pixelHeightMicrons", pixelHeightMicrons);
String script = String.format("setPixelSizeMicrons(%f, %f)", pixelWidthMicrons, pixelHeightMicrons);
step = new DefaultScriptableWorkflowStep("Set pixel size " + GeneralTools.micrometerSymbol(), map, script);
} else {
var map = Map.of("pixelWidthMicrons", pixelWidthMicrons, "pixelHeightMicrons", pixelHeightMicrons, "zSpacingMicrons", zSpacingMicrons);
String script = String.format("setPixelSizeMicrons(%f, %f, %f)", pixelWidthMicrons, pixelHeightMicrons, zSpacingMicrons);
step = new DefaultScriptableWorkflowStep("Set pixel size " + GeneralTools.micrometerSymbol(), map, script);
}
imageData.getHistoryWorkflow().addStep(step);
return true;
} else
return false;
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class ImageDetailsPane method getValue.
private Object getValue(ImageDetailRow rowType) {
if (imageData == null)
return null;
ImageServer<BufferedImage> server = imageData.getServer();
PixelCalibration cal = server.getPixelCalibration();
switch(rowType) {
case NAME:
var project = QuPathGUI.getInstance().getProject();
var entry = project == null ? null : project.getEntry(imageData);
if (entry == null)
return ServerTools.getDisplayableImageName(server);
else
return entry.getImageName();
case URI:
Collection<URI> uris = server.getURIs();
if (uris.isEmpty())
return "Not available";
if (uris.size() == 1)
return decodeURI(uris.iterator().next());
return "[" + String.join(", ", uris.stream().map(ImageDetailsPane::decodeURI).collect(Collectors.toList())) + "]";
case IMAGE_TYPE:
return imageData.getImageType();
case METADATA_CHANGED:
return hasOriginalMetadata(imageData.getServer()) ? "No" : "Yes";
case PIXEL_TYPE:
String type = server.getPixelType().toString().toLowerCase();
if (server.isRGB())
type += " (rgb)";
return type;
case MAGNIFICATION:
double mag = server.getMetadata().getMagnification();
if (Double.isNaN(mag))
return "Unknown";
return mag;
case WIDTH:
if (cal.hasPixelSizeMicrons())
return String.format("%s px (%.2f %s)", server.getWidth(), server.getWidth() * cal.getPixelWidthMicrons(), GeneralTools.micrometerSymbol());
else
return String.format("%s px", server.getWidth());
case HEIGHT:
if (cal.hasPixelSizeMicrons())
return String.format("%s px (%.2f %s)", server.getHeight(), server.getHeight() * cal.getPixelHeightMicrons(), GeneralTools.micrometerSymbol());
else
return String.format("%s px", server.getHeight());
case DIMENSIONS:
return String.format("%d x %d x %d", server.nChannels(), server.nZSlices(), server.nTimepoints());
case PIXEL_WIDTH:
if (cal.hasPixelSizeMicrons())
return String.format("%.4f %s", cal.getPixelWidthMicrons(), GeneralTools.micrometerSymbol());
else
return "Unknown";
case PIXEL_HEIGHT:
if (cal.hasPixelSizeMicrons())
return String.format("%.4f %s", cal.getPixelHeightMicrons(), GeneralTools.micrometerSymbol());
else
return "Unknown";
case Z_SPACING:
if (cal.hasZSpacingMicrons())
return String.format("%.4f %s", cal.getZSpacingMicrons(), GeneralTools.micrometerSymbol());
else
return "Unknown";
case UNCOMPRESSED_SIZE:
double size = server.getWidth() / 1024.0 * server.getHeight() / 1024.0 * server.getPixelType().getBytesPerPixel() * server.nChannels() * server.nZSlices() * server.nTimepoints();
String units = " MB";
if (size > 1000) {
size /= 1024.0;
units = " GB";
}
return GeneralTools.formatNumber(size, 1) + units;
case SERVER_TYPE:
return server.getServerType();
case PYRAMID:
if (server.nResolutions() == 1)
return "No";
return GeneralTools.arrayToString(Locale.getDefault(Locale.Category.FORMAT), server.getPreferredDownsamples(), 1);
case STAIN_1:
return imageData.getColorDeconvolutionStains().getStain(1);
case STAIN_2:
return imageData.getColorDeconvolutionStains().getStain(2);
case STAIN_3:
return imageData.getColorDeconvolutionStains().getStain(3);
case BACKGROUND:
ColorDeconvolutionStains stains = imageData.getColorDeconvolutionStains();
double[] whitespace = new double[] { stains.getMaxRed(), stains.getMaxGreen(), stains.getMaxBlue() };
return whitespace;
default:
return null;
}
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class DilateAnnotationPlugin method getTasks.
@Override
protected Collection<Runnable> getTasks(final PluginRunner<T> runner) {
Collection<? extends PathObject> parentObjects = getParentObjects(runner);
if (parentObjects == null || parentObjects.isEmpty())
return Collections.emptyList();
// Add a single task, to avoid multithreading - which may complicate setting parents
List<Runnable> tasks = new ArrayList<>(parentObjects.size());
ImageServer<T> server = getServer(runner);
Rectangle bounds = new Rectangle(0, 0, server.getWidth(), server.getHeight());
PathObjectHierarchy hierarchy = getHierarchy(runner);
double radiusPixels;
PixelCalibration cal = server.getPixelCalibration();
if (cal.hasPixelSizeMicrons())
radiusPixels = params.getDoubleParameterValue("radiusMicrons") / cal.getAveragedPixelSizeMicrons();
else
radiusPixels = params.getDoubleParameterValue("radiusPixels");
boolean constrainToParent = params.getBooleanParameterValue("constrainToParent");
boolean removeInterior = params.getBooleanParameterValue("removeInterior");
LineCap cap = params.containsKey("lineCap") ? (LineCap) params.getChoiceParameterValue("lineCap") : LineCap.ROUND;
// Want to reset selection
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
Collection<PathObject> previousSelection = new ArrayList<>(hierarchy.getSelectionModel().getSelectedObjects());
tasks.add(() -> {
for (PathObject pathObject : parentObjects) {
addExpandedAnnotation(bounds, hierarchy, pathObject, radiusPixels, constrainToParent, removeInterior, cap);
}
hierarchy.getSelectionModel().selectObjects(previousSelection);
hierarchy.getSelectionModel().setSelectedObject(selected, true);
});
return tasks;
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class ShapeFeaturesPlugin method addRunnableTasks.
@Override
protected void addRunnableTasks(final ImageData<T> imageData, final PathObject parentObject, List<Runnable> tasks) {
PixelCalibration cal = imageData == null ? null : imageData.getServer().getPixelCalibration();
boolean useMicrons = params.getBooleanParameterValue("useMicrons") && cal != null && cal.hasPixelSizeMicrons();
double pixelWidth = useMicrons ? cal.getPixelWidthMicrons() : 1;
double pixelHeight = useMicrons ? cal.getPixelHeightMicrons() : 1;
String unit = useMicrons ? GeneralTools.micrometerSymbol() : "px";
boolean doArea = params.getBooleanParameterValue("area");
boolean doPerimeter = params.getBooleanParameterValue("perimeter");
boolean doCircularity = params.getBooleanParameterValue("circularity");
ROI roi = (parentObject.hasROI() && parentObject.getROI().isArea()) ? parentObject.getROI() : null;
if (roi != null) {
tasks.add(new Runnable() {
@Override
public void run() {
try {
MeasurementList measurementList = parentObject.getMeasurementList();
ROI roi;
if (parentObject instanceof PathCellObject) {
roi = ((PathCellObject) parentObject).getNucleusROI();
if (roi != null && roi.isArea())
addMeasurements(measurementList, roi, "Nucleus Shape: ", pixelWidth, pixelHeight, unit, doArea, doPerimeter, doCircularity);
roi = parentObject.getROI();
if (roi != null && roi.isArea())
addMeasurements(measurementList, roi, "Cell Shape: ", pixelWidth, pixelHeight, unit, doArea, doPerimeter, doCircularity);
} else {
roi = parentObject.getROI();
if (roi != null && roi.isArea())
addMeasurements(measurementList, roi, "ROI Shape: ", pixelWidth, pixelHeight, unit, doArea, doPerimeter, doCircularity);
}
measurementList.close();
} catch (Exception e) {
e.printStackTrace();
throw (e);
}
}
});
}
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class SmoothFeaturesPlugin method addRunnableTasks.
@Override
protected void addRunnableTasks(final ImageData<T> imageData, final PathObject parentObject, List<Runnable> tasks) {
double fwhm;
ImageServer<T> server = imageData.getServer();
String fwhmStringTemp;
PixelCalibration cal = server == null ? null : server.getPixelCalibration();
if (cal != null && cal.hasPixelSizeMicrons()) {
fwhm = getParameterList(imageData).getDoubleParameterValue("fwhmMicrons");
fwhmStringTemp = GeneralTools.createFormatter(2).format(fwhm) + " " + GeneralTools.micrometerSymbol();
fwhm /= cal.getAveragedPixelSizeMicrons();
// params.addDoubleParameter("fwhmPixels", "Radius (FWHM)", fwhm, "pixels"); // Set the FWHM in pixels too
} else {
fwhm = getParameterList(imageData).getDoubleParameterValue("fwhmPixels");
fwhmStringTemp = GeneralTools.createFormatter(2).format(fwhm) + " px";
}
// sigma = 50;
final String fwhmString = fwhmStringTemp;
final double fwhmPixels = fwhm;
final boolean withinClass = params.getBooleanParameterValue("smoothWithinClasses");
final boolean useLegacyNames = params.containsKey("useLegacyNames") && Boolean.TRUE.equals(params.getBooleanParameterValue("useLegacyNames"));
tasks.add(new Runnable() {
@Override
public void run() {
try {
if (!parentObject.hasChildren())
return;
// System.out.println("Smoothing with FWHM " +fwhmPixels);
// TODO: MAKE A MORE ELEGANT LIST!!!!
List<PathObject> pathObjects = PathObjectTools.getFlattenedObjectList(parentObject, null, false);
Iterator<PathObject> iterObjects = pathObjects.iterator();
while (iterObjects.hasNext()) {
PathObject temp = iterObjects.next();
if (!(temp instanceof PathDetectionObject || temp instanceof PathTileObject))
iterObjects.remove();
}
if (pathObjects.isEmpty())
return;
// TODO: ACCESS & USE THE CLASSIFIER DATA!!!!
List<String> measurements = new ArrayList<>(PathClassifierTools.getAvailableFeatures(pathObjects));
Iterator<String> iter = measurements.iterator();
while (iter.hasNext()) {
String name = iter.next().toLowerCase();
if (name.endsWith("smoothed") || name.startsWith("smoothed") || name.contains(" - smoothed (fwhm ") || name.startsWith("smoothed denominator (local density, ") || name.startsWith("nearby detection counts"))
iter.remove();
}
logger.debug(String.format("Smooth features: %s (FWHM: %.2f px)", parentObject.getDisplayedName(), fwhmPixels));
smoothMeasurements(pathObjects, measurements, fwhmPixels, fwhmString, withinClass, useLegacyNames);
// // REMOVE - the purpose was to test a 'difference of Gaussians' type of thing
// List<String> namesAdded1 = new ArrayList<>(smoothMeasurements(pathObjects, measurements, fwhmPixels));
// List<String> namesAdded2 = new ArrayList<>(smoothMeasurements(pathObjects, measurements, fwhmPixels * 2));
// for (PathObject pathObject : pathObjects) {
// MeasurementList ml = pathObject.getMeasurementList();
// ml.ensureListOpen();
// for (int i = 0; i < namesAdded1.size(); i++) {
// String name1 = namesAdded1.get(i);
// String name2 = namesAdded2.get(i);
// double m1 = ml.getMeasurementValue(name1);
// double m2 = ml.getMeasurementValue(name2);
// ml.addMeasurement(name1 + " - " + name2, m1 - m2);
// }
// ml.closeList();
// }
} catch (Exception e) {
e.printStackTrace();
throw (e);
}
}
});
}
Aggregations