Skip to content

Instantly share code, notes, and snippets.

@caner-ercan
Last active June 20, 2025 01:12
Show Gist options
  • Select an option

  • Save caner-ercan/806696a604bdb73ea6437dca1c863784 to your computer and use it in GitHub Desktop.

Select an option

Save caner-ercan/806696a604bdb73ea6437dca1c863784 to your computer and use it in GitHub Desktop.
QuPath _ AI-TIL #QuPath
//0.2.0 version of https://forum.image.sc/t/assign-point-objects-to-different-rois-by-overlap/26905/2?u=research_associate
// Convert points into detections, resolve the heirarchy so they are now child objects of any annotations.
import qupath.lib.roi.EllipseROI;
import qupath.lib.objects.PathDetectionObject
points = getAnnotationObjects().findAll{it.getROI().isPoint() }
print points[0].getROI()
describe(points[0].getROI())
//Cycle through each points object (which is a collection of points)
points.each{
//Cycle through all points within a points object
pathClass = it.getPathClass()
it.getROI().getAllPoints().each{
//for each point, create a circle on top of it that is "size" pixels in diameter
x = it.getX()
y = it.getY()
size = 5
def roi = ROIs.createEllipseROI(x-size/2,y-size/2,size,size, ImagePlane.getDefaultPlane())
def aCell = new PathDetectionObject(roi, pathClass)
addObject(aCell)
}
}
print points[0].getROI()
//remove points if desired.
removeObjects(points, false)
resolveHierarchy()
folder = buildFilePath(PROJECT_BASE_DIR, "tsv")
def checkDir = new File(folder)
if(!checkDir.exists()) {
checkDir.mkdir()
}
name= GeneralTools.getNameWithoutExtension(getProjectEntry().getImageName())
File fileName = new File(buildFilePath(folder,name+".tsv"))
def points = []
selectAnnotations()
anns = getSelectedObjects()
for (ann in anns) {
if(ann.getROI().getRoiName() == "Points")
points.add(ann)
}
PointIO.writePoints(file = fileName, pathObjects = points)
/*
Purpose:
This QuPath script import annotations from AI-sTIL's output CSV file.
The output file must be copied into the following directory in Polyscope:
'.../aitil/4_cell_class/CellPos/{image_name}_cellPos.csv'
Works with any version of QuPath—until further notice (or disaster).
Author: Caner Ercan
*/
// before running this code, be sure that AI_TIL output cell positions were not rounded. 'step4_cell_class/subpackages/cellPos.py' line: 41-42.
// In addition, check if the output is downsampled (the fixed ratio is 16)[ same file, line 36]
// Also you need to know pixel_size of your image
import qupath.lib.geom.Point2
// def pixel_size = 0.5013
def pixelSize= getCurrentServer().getPixelCalibration().getAveragedPixelSize()
def folder = "/Volumes/rsrch6/home/trans_mol_path/yuan_lab/TIER2/anaplasticThyroid_XiaoZhao/aitil/4_cell_class/CellPos"
def plane = getCurrentViewer().getImagePlane()
def imagename = getProjectEntry().getImageName()
def fileName = buildFilePath(folder,imagename+'_cellPos.csv')
def coords = []
def skipFirstLine = true
clearAllObjects()
// Read the TSV file line by line
new File(fileName).eachLine { line ->
if (skipFirstLine) {
skipFirstLine = false
return
}
print line
// // Process each line here
//
def rowContent = line.split(',')
//
//
double cx = (rowContent [2] as double) * 0.44 / pixelSize
double cy = (rowContent[3] as double) * 0.44 / pixelSize
// def coords = (cx,cy)
// print coords
def pointsROI = ROIs.createPointsROI(cx,cy, plane);
def annotation = PathObjects.createAnnotationObject(pointsROI, getPathClass(rowContent[0]) )
// hierarchy.addPathObject(annotation, true)
QP.addObject(annotation)
}
// there is a bug, I could not merge all the cells with one run. If you want to keep your cells seperately, deactivate the following part. May slow down the visualisation. Test it first.
fireHierarchyUpdate()
for (i = 0; i < 10; i++) {
PathObjectTools.mergePointsForAllClasses(getCurrentHierarchy())
}
//referenceFile.eachLine { line ->
// def (name, reference) = line.split(/\t/)
import org.apache.commons.io.FilenameUtils
import qupath.lib.geom.Point2
def pathSingleton = getCurrentServer().getURIs()[0]
def path = pathSingleton.getPath()
selectAllObjects()
def obj = getSelectedObjects()
if (obj.empty){
print "importing cells"
//
def slideName = FilenameUtils.getName(path)
def project_path = buildFilePath(PROJECT_BASE_DIR)
def folder = new File(project_path)
def parentFolderPath = folder.getParent()
def fileName = buildFilePath(parentFolderPath, "output", "4_cell_class","CellPos", slideName+"_cellPos.csv")
// def pixel_size = 0.5013
def pixelSize= getCurrentServer().getPixelCalibration().getAveragedPixelSize()
//def folder = "/Volumes/rsrch6/home/trans_mol_path/yuan_lab/TIER2/anaplasticThyroid_XiaoZhao/aitil/4_cell_class/CellPos"
def plane = getCurrentViewer().getImagePlane()
def imagename = getProjectEntry().getImageName()
//def fileName = buildFilePath(folder,imagename+'_cellPos.csv')
def coords = []
def skipFirstLine = true
//clearAllObjects()
// Read the TSV file line by line
new File(fileName).eachLine { line ->
if (skipFirstLine) {
skipFirstLine = false
return
}
// print line
// // Process each line here
//
def rowContent = line.split(',')
//
//
double cx = (rowContent[1] as double) *16 *0.44 / pixelSize
double cy = (rowContent[2] as double) *16 *0.44 / pixelSize
// def coords = (cx,cy)
// print coords
def pointsROI = ROIs.createPointsROI(cx,cy, plane);
def annotation = PathObjects.createDetectionObject(pointsROI, getPathClass(rowContent[0]) )
// hierarchy.addPathObject(annotation, true)
QP.addObject(annotation)
}
// there is a bug, I could not merge all the cells with one run. If you want to keep your cells seperately, deactivate the following part. May slow down the visualisation. Test it first.
//for (i = 0; i < 10; i++) {
// PathObjectTools.mergePointsForAllClasses(getCurrentHierarchy())
//}
fireHierarchyUpdate()
}else {
print "skipped "+ getCurrentImageName()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment