Skip to content

Instantly share code, notes, and snippets.

@romainGuiet
Last active August 21, 2025 08:54
Show Gist options
  • Save romainGuiet/8c19bde080c5cc42397e21bffccc56b2 to your computer and use it in GitHub Desktop.
Save romainGuiet/8c19bde080c5cc42397e21bffccc56b2 to your computer and use it in GitHub Desktop.
The script expects to find a "Tissue" annotation (optionally this annotation can be generated it via a PixelClassifier, line 40 ) , and then creates defined nbr of boxes in the annotation. #biop #qupath
// Change the name of the tissue classifier here if needed
def tissueFinder = "Tissue"
// Which Name should they have ?
// if annotation with the same name exist they will be deleted
def annotation_name = "Analysis"
// START OF SCRIPT
import qupath.lib.roi.RectangleROI
// Annotations info
def size = 1024// in pixel
// Define a maximum number of new annotations
def max_annotation_nbr = 10
// Annotation Strategy
def onlyInside = true
//// Runner
//
//
//
// Get some infos
//
def imageData = getCurrentImageData()
// Get the server
def img_server = getCurrentServer()
// Get the file name from the current server
def img_name = getProjectEntry().getImageName()
// get image size
def image_width = img_server.getWidth()
def image_height = img_server.getHeight()
// Run Tissue Finder , usin a PixelClassifier
//createAnnotationsFromPixelClassifier(tissueFinder, 100000.0, 1.0E14, "SPLIT", "DELETE_EXISTING")
// remove pre-existing annotations having the defined name
def all_annotations = getAnnotationObjects()
def annotations_to_remove = all_annotations.findAll{ it.getName() =~ /${ annotation_name }/ }
removeObjects( annotations_to_remove, true)
// Define the squares within the Annotation
def annotations = getAnnotationObjects()
println annotations
if (annotations== []){
createSelectAllObject(true)
annotations = getAnnotationObjects()
}
annotations.each{ annot ->
currentBoxes = []
annot.clearPathObjects()
def p_roi = annot.getROI()
def cx = p_roi.getBoundsX()
def cy = p_roi.getBoundsY()
def w = p_roi.getBoundsWidth()
def h = p_roi.getBoundsHeight()
def startx = cx
def starty = cy
def box_c = 0
def tryNbr = 0
// limit the number of trial
// in case the annotation can not contain so many sub-annotations
while(( box_c < max_annotation_nbr ) && (tryNbr < 100* max_annotation_nbr ) ){
def newX = startx + w * Math.random()
def newY = starty + h * Math.random()
def newRoi = ROIs.createRectangleROI( newX, newY, size, size, null)
// check if the sub-annotation is in the Main-annotation
if( annot.getROI().getGeometry().contains( newRoi.getGeometry() ) || !onlyInside ){
if(!currentBoxes.any{ it.getROI().getGeometry().overlaps( newRoi.getGeometry() ) }) {
def rect = PathObjects.createAnnotationObject( newRoi, getPathClass(annotation_name) )
rect.setName( annotation_name + "-"+ box_c.toString().padLeft(4, '0') )
annot.addPathObject( rect )
currentBoxes.add( rect )
box_c++
println("Number of Boxes: "+box_c)
}
}
tryNbr++ // escape variable increment
}
}
fireHierarchyUpdate()
def anyOverlap( X, Y, Size, annotation_name, all_annotations ) {
// any() returns true if at least one return condition is true
def is_overlap = all_annotations.any{
if (it.getName() =~ /${ annotation_name }/) {
def roi = it.getROI()
def x = roi.getBoundsX()
def y = roi.getBoundsY()
return doOverlap( X,Y,x,y,Size)
}
}
return is_overlap
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment