use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class PathHierarchyPaintingHelper method paintConnections.
/**
* Paint connections between objects (e.g. from Delaunay triangulation).
*
* @param connections
* @param hierarchy
* @param g2d
* @param color
* @param downsampleFactor
*/
public static void paintConnections(final PathObjectConnections connections, final PathObjectHierarchy hierarchy, Graphics2D g2d, final Color color, final double downsampleFactor) {
if (hierarchy == null || connections == null || connections.isEmpty())
return;
float alpha = (float) (1f - downsampleFactor / 5);
alpha = Math.min(alpha, 0.25f);
float thickness = PathPrefs.detectionStrokeThicknessProperty().get();
if (alpha < .1f || thickness / downsampleFactor <= 0.5)
return;
g2d = (Graphics2D) g2d.create();
// Shape clipShape = g2d.getClip();
g2d.setStroke(getCachedStroke(thickness));
// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha * .5f));
// g2d.setColor(ColorToolsAwt.getColorWithOpacity(getPreferredOverlayColor(), 1));
g2d.setColor(ColorToolsAwt.getColorWithOpacity(color.getRGB(), alpha));
// g2d.setColor(Color.BLACK);
Line2D line = new Line2D.Double();
// We can have trouble whenever two objects are outside the clip, but their connections would be inside it
// Here, we just enlarge the region (by quite a lot)
// It's not guaranteed to work, but it usually does... and avoids much expensive computations
Rectangle bounds = g2d.getClipBounds();
int factor = 1;
Rectangle bounds2 = factor > 0 ? new Rectangle(bounds.x - bounds.width * factor, bounds.y - bounds.height * factor, bounds.width * (factor * 2 + 1), bounds.height * (factor * 2 + 1)) : bounds;
ImageRegion imageRegion = AwtTools.getImageRegion(bounds2, 0, 0);
// ImageRegion imageRegion = AwtTools.getImageRegion(bounds, 0, 0);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
// g2d.draw(g2d.getClipBounds());
Collection<PathObject> pathObjects = hierarchy.getObjectsForRegion(PathDetectionObject.class, imageRegion, null);
// double threshold = downsampleFactor*downsampleFactor*4;
for (PathObject pathObject : pathObjects) {
ROI roi = PathObjectTools.getROI(pathObject, true);
double x1 = roi.getCentroidX();
double y1 = roi.getCentroidY();
for (PathObjectConnectionGroup dt : connections.getConnectionGroups()) {
for (PathObject siblingObject : dt.getConnectedObjects(pathObject)) {
ROI roi2 = PathObjectTools.getROI(siblingObject, true);
double x2 = roi2.getCentroidX();
double y2 = roi2.getCentroidY();
if (bounds.intersectsLine(x1, y1, x2, y2)) {
line.setLine(x1, y1, x2, y2);
g2d.draw(line);
}
}
}
}
g2d.dispose();
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class QuPathViewer method updateRoiEditor.
private void updateRoiEditor() {
PathObject pathObjectSelected = getSelectedObject();
ROI previousROI = roiEditor.getROI();
ROI newROI = pathObjectSelected != null && pathObjectSelected.isEditable() ? pathObjectSelected.getROI() : null;
if (previousROI == newROI)
roiEditor.ensureHandlesUpdated();
else
roiEditor.setROI(newROI);
repaint();
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class IJTools method convertToPathObject.
/**
* Create a {@link PathObject} for a specific ImageJ Roi, using an {@link ImagePlus} to help set properties.
*
* @param roi the ImageJ ROI
* @param downsampleFactor the downsample factor used for rescaling (or 1.0 for no rescaling)
* @param creator a function
* @param imp the {@link ImagePlus} associated with this Roi; it is used to determine the xOrigin, yOrigin and image plane
* @return a {@link PathObject} or null if no object could be created (e.g. the ImageJ roi is null or incompatible)
*
* @see #convertToPathObject(Roi, double, double, double, Function, ImagePlane)
* @since v0.4.0
*/
public static PathObject convertToPathObject(Roi roi, double downsampleFactor, Function<ROI, PathObject> creator, ImagePlus imp) {
Calibration cal = imp == null ? null : imp.getCalibration();
var plane = getImagePlane(roi, imp);
ROI pathROI = IJTools.convertToROI(roi, cal, downsampleFactor, plane);
if (pathROI == null)
return null;
PathObject pathObject = creator.apply(pathROI);
calibrateObject(pathObject, roi);
return pathObject;
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class IJExtension method extractOverlay.
/**
* Extract an ImageJ overlay for the specified region.
* @param hierarchy
* @param request
* @param options options to control which objects are being displayed
* @param filter optional additional filter used to determine which objects will be included (may be used in combination with options)
* @return
*/
public static Overlay extractOverlay(PathObjectHierarchy hierarchy, RegionRequest request, OverlayOptions options, Predicate<PathObject> filter) {
Overlay overlay = new Overlay();
double downsample = request.getDownsample();
double xOrigin = -request.getX() / downsample;
double yOrigin = -request.getY() / downsample;
// TODO: Permit filling/unfilling ROIs
for (PathObject child : hierarchy.getObjectsForRegion(PathObject.class, request, null)) {
if (filter != null && !filter.test(child))
continue;
if (child.hasROI()) {
// Check if this is displayed - skip it not
if (options != null && ((child instanceof PathDetectionObject && !options.getShowDetections()) || (child instanceof PathAnnotationObject && !options.getShowAnnotations()) || (child instanceof TMACoreObject && !options.getShowTMAGrid())))
continue;
boolean isCell = child instanceof PathCellObject;
Color color = ColorToolsAwt.getCachedColor(ColorToolsFX.getDisplayedColorARGB(child));
if (!(isCell && (options == null || !options.getShowCellBoundaries()))) {
Roi roi = IJTools.convertToIJRoi(child.getROI(), xOrigin, yOrigin, downsample);
roi.setStrokeColor(color);
roi.setName(child.getDisplayedName());
// roi.setStrokeWidth(2);
overlay.add(roi);
}
if (isCell && (options == null || options.getShowCellNuclei())) {
ROI nucleus = ((PathCellObject) child).getNucleusROI();
if (nucleus == null)
continue;
Roi roi = IJTools.convertToIJRoi(((PathCellObject) child).getNucleusROI(), xOrigin, yOrigin, downsample);
roi.setStrokeColor(color);
roi.setName(child.getDisplayedName() + " - nucleus");
overlay.add(roi);
}
}
}
return overlay;
}
use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.
the class IJExtension method extractROIWithOverlay.
/**
* Extract an image region as an ImagePlus, optionally setting ImageJ Rois corresponding to QuPath objects.
*
* @param server server from which pixels should be requested
* @param pathObject the primary object, which may have its ROI set on the image
* @param hierarchy object hierarchy containing objects whose ROIs should be added to the ImagePlus overlay
* @param request the region being requested
* @param setROI if true, the ROI of the pathObject will be set on the image as the 'main' ROI (i.e. not an overlay)
* @param options options determining which kinds of objects will have ROIs added, to match with the display in the QuPath viewer
* @return
* @throws IOException
*/
public static PathImage<ImagePlus> extractROIWithOverlay(ImageServer<BufferedImage> server, PathObject pathObject, PathObjectHierarchy hierarchy, RegionRequest request, boolean setROI, OverlayOptions options) throws IOException {
ROI pathROI;
if (pathObject == null || !pathObject.hasROI()) {
pathROI = ROIs.createRectangleROI(0, 0, server.getWidth(), server.getHeight(), ImagePlane.getDefaultPlane());
// logger.error("No ROI found to extract!");
// return null;
} else
pathROI = pathObject.getROI();
// Extract the image
PathImage<ImagePlus> pathImage = extractROI(server, pathROI, request, setROI);
if (pathImage == null)
return pathImage;
// Add the overlay
if (hierarchy != null) {
ImagePlus imp = pathImage.getImage();
var regionPredicate = PathObjectTools.createImageRegionPredicate(request);
Overlay overlay = extractOverlay(hierarchy, request, options, p -> p != pathObject && regionPredicate.test(p));
if (overlay.size() > 0) {
imp.setOverlay(overlay);
}
}
IJTools.setTitleFromObject(pathImage, pathObject);
return pathImage;
}
Aggregations