use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class RefineAnnotationsPlugin 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<>(1);
PathObjectHierarchy hierarchy = getHierarchy(runner);
double minFragmentSize;
double maxHoleSize, maxHoleSizeTemp;
ImageServer<T> server = getServer(runner);
PixelCalibration cal = server.getPixelCalibration();
if (cal.hasPixelSizeMicrons()) {
double pixelAreaMicrons = cal.getPixelWidthMicrons() * cal.getPixelHeightMicrons();
minFragmentSize = params.getDoubleParameterValue("minFragmentSizeMicrons") / pixelAreaMicrons;
maxHoleSizeTemp = params.getDoubleParameterValue("maxHoleSizeMicrons") / pixelAreaMicrons;
} else {
minFragmentSize = params.getDoubleParameterValue("minFragmentSizePixels");
maxHoleSizeTemp = params.getDoubleParameterValue("maxHoleSizePixels");
}
// Handle negative values
if (maxHoleSizeTemp < 0)
maxHoleSize = Double.POSITIVE_INFINITY;
else
maxHoleSize = maxHoleSizeTemp;
// Want to reset selection
PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
Collection<PathObject> previousSelection = new ArrayList<>(hierarchy.getSelectionModel().getSelectedObjects());
tasks.add(() -> {
List<PathObject> toRemove = new ArrayList<>();
Map<PathROIObject, ROI> toUpdate = new HashMap<>();
for (PathObject pathObject : parentObjects) {
ROI roiOrig = pathObject.getROI();
if (roiOrig == null || !roiOrig.isArea())
continue;
ROI roiUpdated = RoiTools.removeSmallPieces(roiOrig, minFragmentSize, maxHoleSize);
if (roiUpdated == null || roiUpdated.isEmpty())
toRemove.add(pathObject);
else if (roiOrig != roiUpdated && pathObject instanceof PathROIObject) {
toUpdate.put((PathROIObject) pathObject, roiUpdated);
}
}
if (toRemove.isEmpty() && toUpdate.isEmpty())
return;
hierarchy.getSelectionModel().clearSelection();
if (!toRemove.isEmpty())
hierarchy.removeObjects(toRemove, true);
if (!toUpdate.isEmpty()) {
hierarchy.removeObjects(toUpdate.keySet(), true);
toUpdate.forEach((p, r) -> p.setROI(r));
hierarchy.addPathObjects(toUpdate.keySet());
}
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 IntensityFeaturesPlugin method getPreferredTileSizePixels.
private static ImmutableDimension getPreferredTileSizePixels(final ImageServer<BufferedImage> server, final ParameterList params) {
// Determine tile size
int tileWidth, tileHeight;
PixelCalibration cal = server.getPixelCalibration();
if (cal.hasPixelSizeMicrons()) {
double tileSize = params.getDoubleParameterValue("tileSizeMicrons");
tileWidth = (int) Math.round(tileSize / cal.getPixelWidthMicrons());
tileHeight = (int) Math.round(tileSize / cal.getPixelHeightMicrons());
} else {
tileWidth = (int) Math.round(params.getDoubleParameterValue("tileSizePixels"));
tileHeight = tileWidth;
}
return ImmutableDimension.getInstance(tileWidth, tileHeight);
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class DelaunayTools method createGeometryExtractor.
private static Function<PathObject, Collection<Coordinate>> createGeometryExtractor(PixelCalibration cal, boolean preferNucleus, double densifyFactor, double erosion) {
PrecisionModel precision = calibrated(cal) ? null : GeometryTools.getDefaultFactory().getPrecisionModel();
AffineTransformation transform = calibrated(cal) ? AffineTransformation.scaleInstance(cal.getPixelWidth().doubleValue(), cal.getPixelHeight().doubleValue()) : null;
return p -> {
var roi = PathObjectTools.getROI(p, preferNucleus);
if (roi == null || roi.isEmpty())
return Collections.emptyList();
var geom = roi.getGeometry();
if (transform != null)
geom = transform.transform(geom);
// Shared boundaries can be problematic, so try to buffer away from these
double buffer = -Math.abs(erosion);
if (buffer < 0 && geom instanceof Polygonal) {
var geomBefore = geom;
geom = GeometryTools.attemptOperation(geom, g -> g.buffer(buffer));
// Do not permit Geometry to disappear
if (geom.isEmpty()) {
geom = geomBefore;
}
}
// Therefore we take extra care in case empty geometries are being generated accidentally.
if (precision != null) {
var geom2 = GeometryTools.attemptOperation(geom, g -> GeometryPrecisionReducer.reduce(g, precision));
if (!geom2.isEmpty())
geom = geom2;
}
if (densifyFactor > 0) {
var geom2 = GeometryTools.attemptOperation(geom, g -> Densifier.densify(g, densifyFactor));
if (!geom2.isEmpty())
geom = geom2;
}
// if (!(geom instanceof Polygon))
// logger.warn("Unexpected Geometry: {}", geom);
// Making precise is essential! Otherwise there can be small artifacts occurring
var coords = geom.getCoordinates();
var output = new LinkedHashSet<Coordinate>();
var p2 = precision;
Coordinate lastCoordinate = null;
if (p2 == null)
p2 = GeometryTools.getDefaultFactory().getPrecisionModel();
// Add coordinates, unless they are extremely close to an existing coordinate
int n = coords.length;
if (n == 0) {
logger.warn("Empty Geometry found for {}", p);
return Collections.emptyList();
}
double minDistance = densifyFactor * 0.5;
var firstCoordinate = coords[0];
while (n > 2 && firstCoordinate.distance(coords[n - 1]) < minDistance) n--;
for (int i = 0; i < n; i++) {
var c = coords[i];
p2.makePrecise(c);
if (i == 0 || c.distance(lastCoordinate) > minDistance) {
output.add(c);
lastCoordinate = c;
}
}
return output;
};
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class ClassificationResolution method getDefaultResolutions.
/**
* Get a list of default resolutions to show, derived from {@link PixelCalibration} objects.
* @param imageData
* @param selected
* @return
*/
public static List<ClassificationResolution> getDefaultResolutions(ImageData<?> imageData, ClassificationResolution selected) {
var temp = new ArrayList<ClassificationResolution>();
PixelCalibration cal = imageData.getServer().getPixelCalibration();
int scale = 1;
for (String name : resolutionNames) {
var newResolution = new ClassificationResolution(name, cal.createScaledInstance(scale, scale, 1));
if (Objects.equals(selected, newResolution))
temp.add(selected);
else
temp.add(newResolution);
scale *= 2;
}
if (selected == null)
selected = temp.get(0);
else if (!temp.contains(selected))
temp.add(selected);
return temp;
}
use of qupath.lib.images.servers.PixelCalibration in project qupath by qupath.
the class PixelClassifierPane method addResolution.
private boolean addResolution() {
var imageData = qupath.getImageData();
ImageServer<BufferedImage> server = imageData == null ? null : imageData.getServer();
if (server == null) {
Dialogs.showNoImageError("Add resolution");
return false;
}
String units = null;
Double pixelSize = null;
PixelCalibration cal = server.getPixelCalibration();
if (cal.hasPixelSizeMicrons()) {
pixelSize = Dialogs.showInputDialog("Add resolution", "Enter requested pixel size in " + GeneralTools.micrometerSymbol(), 1.0);
units = PixelCalibration.MICROMETER;
} else {
pixelSize = Dialogs.showInputDialog("Add resolution", "Enter requested downsample factor", 1.0);
}
if (pixelSize == null)
return false;
ClassificationResolution res;
if (PixelCalibration.MICROMETER.equals(units)) {
double scale = pixelSize / cal.getAveragedPixelSizeMicrons();
res = new ClassificationResolution("Custom", cal.createScaledInstance(scale, scale, 1));
} else
res = new ClassificationResolution("Custom", cal.createScaledInstance(pixelSize, pixelSize, 1));
List<ClassificationResolution> temp = new ArrayList<>(resolutions);
temp.add(res);
Collections.sort(temp, Comparator.comparingDouble((ClassificationResolution w) -> w.cal.getAveragedPixelSize().doubleValue()));
resolutions.setAll(temp);
comboResolutions.getSelectionModel().select(res);
return true;
}
Aggregations