Last active
August 21, 2025 08:54
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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