Skip to content

Instantly share code, notes, and snippets.

@Svidro
Last active October 15, 2024 06:14
Show Gist options
  • Save Svidro/33558ac3bd9f68a5ec2428f74550831f to your computer and use it in GitHub Desktop.
Save Svidro/33558ac3bd9f68a5ec2428f74550831f to your computer and use it in GitHub Desktop.
Scripts mostly taken from Pete, and also from the forums. For easy access and reference.
TOC
Remove detections outside annotations.groovy - Removes detections without a parent object.
Removing measurements by Weka file.groovy - Uses the results of Weka classification analysis of your training set
to select the "best" measurements plus any specific ones you want to keep. Then it removes the rest. Use this to clean up
large amounts measurements like LBP, Haralick, Smoothed etc.
Removing measurements by keyword.groovy - Variant of the above, but clean up your measurement lists by keyword. Useful for
removing ALL smoothed measurements as part of a script.
Remove objects by class name.groovy - Remove objects that have a class with a certain string in the name
Remove subcells after 0.2.0m5.groovy - collect and remove subcellular detections
Removing small annotation bits.groovy - Cleans up small tissue bits, though this can often be done by using better settings
during Simple Tissue Detection. Can be useful if your script fragments your annotations at a later point.
removing specific annotations.groovy - An example of deleting objects by creating a list, then removing the objects in the list.
Generally you will want to remove objects either by selecting them and using:
clearSelectedObjects(false);
or creating a list and using:
removeObjects(yourList,true)
True and false in the above statements indicate whether you also want to remove objects within the object you are deleting,
such as cells within an annotation. True indicates that you want to keep the contained objects, while false removes everything.
//Remove all clusters 0.2.0m5+
// def subcellular = getDetectionObjects().findAll {it.getParent()?.isDetection()}
//def subcellular2 = getCellObjects().collect({it.getChildObjects()}).flatten()
removeObjects(getDetectionObjects().findAll{it.getPathClass().toString().contains("Subcellular")},true)
/*
* Identify annotations touching the image boundary
https://forum.image.sc/t/filter-out-annotations-touching-image-border/37570/2?u=research_associate
*/
def server = getCurrentServer()
// To get the annotations
def annotations = getAnnotationObjects().findAll { touchingBoundary(server, it.getROI()) }
removeObjects(annotations, false)
// To select the annotations
//selectObjects {it.isAnnotation() && it.hasROI() && touchingBoundary(server, it.getROI())}
// Using full lambda to get the annotations (just a different syntax)
//def annotations2 = getAnnotationObjects().findAll(annotation -> touchingBoundary(server, annotation.getROI()))
boolean touchingBoundary(server, roi) {
return roi.getBoundsX() <= 0 ||
roi.getBoundsY() <= 0 ||
roi.getBoundsX() + roi.getBoundsWidth() >= server.getWidth()-1 ||
roi.getBoundsY() + roi.getBoundsHeight() >= server.getHeight()-1
}
//Useful if you are trimming an annotation after having generated detections, and want a quick way to eliminate
//cells now outside of your annotated regions.
selectObjects{p -> (p.getLevel()==1) && (p.isAnnotation() == false)};
clearSelectedObjects(false);
//Clean up bad objects
removal = getCellObjects().findAll{it.getPathClass().toString().contains("Trash")}
removeObjects(removal, true)
//Replace the text in it.contains("keyword") in order to remove all measurements that contain that text.
//This can be useful after Smoothing in order to remove some of the large numbers of measurements you probably do not need
import qupath.lib.classifiers.PathClassificationLabellingHelper
def toRemove = PathClassificationLabellingHelper.getAvailableFeatures(getDetectionObjects()).findAll { it.contains("keyword") }
print toRemove
//PathTileObject for SLICs, PathCellObject for cells, TMACoreObject for TMAs
removeMeasurements(qupath.lib.objects.PathTileObject, toRemove as String[])
fireHierarchyUpdate()
//V1.0 attempting to read in an arff file as Strings.
//Note that you may need to change pathCellObject to pathTileObject at the end
import qupath.lib.classifiers.PathClassificationLabellingHelper
File arff = new File('C:\\filePath\\fileName.arff')
def lines = arff.readLines()
def start = false
def variableList = []
//create a list with elements that are your measurements from Weka
for (def i=0; i<lines.size()-1; i++){
if (start == true){
variableList.add(lines[i].trim())
}
if (lines[i].contains("Selected attributes:")){
start = true
}
}
def listTotal = []
//convert hashlinkedset into list so that the subtractions on the next line does not error out
listTotal.addAll(0,PathClassificationLabellingHelper.getAvailableFeatures(getDetectionObjects()))
//Potentially keep some necessary measurements that are not used?
variableList.addAll(['Nucleus: Area', 'Cytoplasm: Eosin OD mean'])
//subtract the list of variables from the arff file from the list of variables you want to remove
listTotal.removeAll(variableList)
//PathTileObject for SLICs PathCellObject for cells
removeMeasurements(qupath.lib.objects.PathCellObject, listTotal as String[])
fireHierarchyUpdate()
println("measurements removed")
import qupath.lib.roi.*
import qupath.lib.objects.*
//Choose the area threshold below which the annotations will be deleted
def ANNOTATION_AREA_MICRONS = 5
//PART 1
//This section splits ALL annotations into contiguous areas, so that any pieces off on their own can be deleted.
//Use only Part 2 if you already have individual annotations.
annotationList = getAnnotationObjects()
for (selected in annotationList){
if (!(selected.getROI() instanceof AreaROI)) {
print 'Selected object does not have an AreaROI!'
return
}
// Try to do split, and ensure holes are taken into consideration
def polygons = PathROIToolsAwt.splitAreaToPolygons(selected.getROI())
def newPolygons = polygons[1].collect {
updated = it
for (hole in polygons[0])
updated = PathROIToolsAwt.combineROIs(updated, hole, PathROIToolsAwt.CombineOp.SUBTRACT)
return updated
}
// Remove original annotation, add new ones
annotations = newPolygons.collect {new PathAnnotationObject(it)}
resetSelection()
removeObject(selected, true)
addObjects(annotations)
}
//PART2
//This section
def server = getCurrentImageData().getServer()
double pixelWidth = server.getPixelWidthMicrons()
double pixelHeight = server.getPixelHeightMicrons()
def smallAnnotations = getAnnotationObjects().findAll {it.getROI().getScaledArea(pixelWidth, pixelHeight) < ANNOTATION_AREA_MICRONS}
removeObjects(smallAnnotations, true)
fireHierarchyUpdate()
//PART3
//Merge annotations back into a single annotation if this is desired for data analysis.
//selectAnnotations()
//mergeSelectedAnnotations()
//removing annotations of class 1 that do not have children of class 2
//use of .any
// Define classes
class1 = getPathClass('class1')
class2 = getPathClass('class2')
// Get all the class1 annotations that don't contain a class2 object as a direct child
toRemove = getAnnotationObjects().findAll {
if (it.getPathClass() != class1)
return false
children = it.getChildObjects()
return !children.any {it.getPathClass() == class2}
}
// Remove annotations meeting that criteria
removeObjects(toRemove, true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment