-
-
Save NicoKiaru/f45f56e3ff2d1fb708821c110fbdee62 to your computer and use it in GitHub Desktop.
/** | |
* ABBA Script : performs a cell detection on the root node annotation | |
* imported from ABBA and restores the child objects after the detection has been performed | |
* To use and modify like you need / want | |
* You need to have imported the regions before running this script. See https://gist.github.com/NicoKiaru/723d8e628a3bb03902bb3f0f2f0fa466 for instance | |
* See https://biop.github.io/ijp-imagetoatlas/ | |
* Author: Olivier Burri, Nicolas Chiaruttini, BIOP, EPFL | |
* Date: 2022-01-26 | |
*/ | |
// setImageType('FLUORESCENCE'); // if your image is fluorescent | |
// If you just want to clear the detections and keep the previously ABBA imported annotations | |
clearDetections() | |
// or, if you want to reset and re-import all annotations from ABBA | |
// clearAllObjects(); | |
// qupath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", true); | |
def project = getProject() | |
// We want to run cell detection only once on the entire brain, which means we need to select the Root node. We can find it by name | |
def root = getAnnotationObjects().find{ it.getName().equals( 'Root' ) } | |
// Duplicate root node. It is a bit contrived but this is how you can copy an annotation | |
def regionMeasured = PathObjectTools.transformObject( root, null, true ) | |
// Temporary name | |
regionMeasured.setName( "Measured Region" ) | |
// Need to add it to the current hierarchy | |
addObject( regionMeasured ) | |
// So that we can select it | |
setSelectedObject( regionMeasured ) | |
// RUN CELL DETECTION | |
// Modify the line below by inserting your cell detection plugin line | |
// ********************************************************************* | |
// ********************************************************************* | |
runPlugin( 'qupath.imagej.detect.cells.WatershedCellDetection', | |
'{"detectionImage": "FL CY3", "requestedPixelSizeMicrons": 2.0, "backgroundRadiusMicrons": 8.0, "medianRadiusMicrons": 0.0, "sigmaMicrons": 2.0, "minAreaMicrons": 20.0, "maxAreaMicrons": 400.0, "threshold": 200.0, "watershedPostProcess": true, "cellExpansionMicrons": 0.0, "includeNuclei": true, "smoothBoundaries": true, "makeMeasurements": true}') | |
// ********************************************************************* | |
// ********************************************************************* | |
// We no longer need the object we used for detection. We remove it but keep the child objects, which are the cells | |
removeObject( regionMeasured, true ) | |
// We can now add the cells to the original root object | |
def cells = getDetectionObjects() | |
root.addPathObjects( cells ) | |
// Update the view for the user | |
fireHierarchyUpdate() | |
// From here, the rest of the script adds to all cells their coordinates in the reference atlas | |
// to their measurement list | |
// Get ABBA transform file located in entry path | |
def targetEntry = getProjectEntry() | |
def targetEntryPath = targetEntry.getEntryPath() | |
def fTransform = new File(targetEntryPath.toFile(), "ABBA-Transform-Adult Mouse Brain - Allen Brain Atlas V3p1.json" ) | |
if ( !fTransform.exists() ) { | |
logger.error( "ABBA transformation file not found for entry {}", targetEntry ) | |
return | |
} | |
def pixelToCCFTransform = Warpy.getRealTransform( fTransform ).inverse() // Needs the inverse transform | |
getDetectionObjects().forEach{ detection -> | |
def ccfCoordinates = new RealPoint(3) | |
def ml = detection.getMeasurementList() | |
ccfCoordinates.setPosition( [detection.getROI().getCentroidX(),detection.getROI().getCentroidY(), 0] as double[] ) | |
// The Z=0 pixel coordinate is automatically transformed to the right atlas position in Z thanks to the fact that the slice | |
// position is already known by the transform | |
// This applies the transform in place to cffCoordinates | |
pixelToCCFTransform.apply(ccfCoordinates, ccfCoordinates) | |
// Fianlly: Add the coordinates as measurements | |
ml.addMeasurement("Allen CCFv3 X mm", ccfCoordinates.getDoublePosition(0) ) | |
ml.addMeasurement("Allen CCFv3 Y mm", ccfCoordinates.getDoublePosition(1) ) | |
ml.addMeasurement("Allen CCFv3 Z mm", ccfCoordinates.getDoublePosition(2) ) | |
ml.addMeasurement("Count: Num Spots", 1 ) | |
} | |
// imports | |
import qupath.ext.biop.warpy.* | |
import net.imglib2.RealPoint | |
import qupath.lib.measurements.MeasurementList | |
import qupath.lib.objects.PathObjectTools | |
import qupath.lib.objects.PathObjects | |
import qupath.lib.objects.PathCellObject | |
import qupath.lib.objects.PathObject | |
import qupath.lib.objects.PathDetectionObject | |
import qupath.lib.roi.ROIs | |
import qupath.lib.regions.ImagePlane |
Hi, I found there are some mistakes in my coding.
1, during ABBA annotation importing: qupath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", false);
, false
should be changed to true
2, during cell detection: in my case, "ABBA-Transform-Adult Mouse Brain - Allen Brain Atlas V3.json"
should be changed to "ABBA-Transform-Adult Mouse Brain - Allen Brain Atlas V3p1.json"
3, I by order ran the script 0,1,2 and happened to meet some problems, but i simple integrated all the script with some codes deleted, thing went more smooth.
My workflow code like this, basically they are based on NicoKiaru's scripts:
// imports
import qupath.ext.biop.warpy.*
import net.imglib2.RealPoint
import qupath.lib.measurements.MeasurementList
import qupath.lib.objects.PathObjectTools
// import annotation from ABBA
setImageType('FLUORESCENCE');
clearAllObjects();
qupath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", true);
// cell detection
clearDetections()
def project = getProject()
// We want to run cell detection only once on the entire brain, which means we need to select the Root node. We can find it by name
def root = getAnnotationObjects().find{ it.getName().equals( 'Root' ) }
// Duplicate root node. It is a bit contrived but this is how you can copy an annotation
def regionMeasured = PathObjectTools.transformObject( root, null, true )
// Temporary name
regionMeasured.setName( "Measured Region" )
// Need to add it to the current hierarchy
addObject( regionMeasured )
// So that we can select it
setSelectedObject( regionMeasured )
// RUN CELL DETECTION
// Modify the line below by inserting your cell detection plugin line
// *********************************************************************
// *********************************************************************
runPlugin( 'qupath.imagej.detect.cells.WatershedCellDetection',
'{"detectionImage": "Cy3", "requestedPixelSizeMicrons": 1.0, "backgroundRadiusMicrons": 8.0, "medianRadiusMicrons": 0.0, "sigmaMicrons": 2.0, "minAreaMicrons": 20.0, "maxAreaMicrons": 200.0, "threshold": 50.0, "watershedPostProcess": true, "cellExpansionMicrons": 10.0, "includeNuclei": True, "smoothBoundaries": true, "makeMeasurements": true}')
// *********************************************************************
// *********************************************************************
// re-loading annotation
qupath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", true);
// Get ABBA transform file located in entry path
def targetEntry = getProjectEntry()
def targetEntryPath = targetEntry.getEntryPath()
def fTransform = new File(targetEntryPath.toFile(), "ABBA-Transform-Adult Mouse Brain - Allen Brain Atlas V3p1.json" )
if ( !fTransform.exists() ) {
logger.error( "ABBA transformation file not found for entry {}", targetEntry )
return
}
def pixelToCCFTransform = Warpy.getRealTransform( fTransform ).inverse() // Needs the inverse transform
getDetectionObjects().forEach{ detection ->
def ccfCoordinates = new RealPoint(3)
def ml = detection.getMeasurementList()
ccfCoordinates.setPosition( [detection.getROI().getCentroidX(),detection.getROI().getCentroidY(), 0] as double[] )
// The Z=0 pixel coordinate is automatically transformed to the right atlas position in Z thanks to the fact that the slice
// position is already known by the transform
// This applies the transform in place to cffCoordinates
pixelToCCFTransform.apply(ccfCoordinates, ccfCoordinates)
// Fianlly: Add the coordinates as measurements
ml.addMeasurement("Allen CCFv3 X mm", ccfCoordinates.getDoublePosition(0) )
ml.addMeasurement("Allen CCFv3 Y mm", ccfCoordinates.getDoublePosition(1) )
ml.addMeasurement("Allen CCFv3 Z mm", ccfCoordinates.getDoublePosition(2) )
ml.addMeasurement("Count: Num Spots", 1 )
}
// To execute before:
// 0 - https://gist.github.com/NicoKiaru/723d8e628a3bb03902bb3f0f2f0fa466
// 1 - https://gist.github.com/NicoKiaru/f45f56e3ff2d1fb708821c110fbdee62
// save annotations
File directory = new File(buildFilePath(PROJECT_BASE_DIR,'export'));
directory.mkdirs();
def imageData = getCurrentImageData();
imageName = ServerTools.getDisplayableImageName(imageData.getServer())
def filename = imageName//.take(imageName.indexOf('.'))
saveMeasurements(
imageData,
PathDetectionObject.class,
buildFilePath(directory.toString(),filename + '.tsv'),
"Class",
"Allen CCFv3 X mm",
"Allen CCFv3 Y mm",
"Allen CCFv3 Z mm",
"Count: Num Spots"
);
import qupath.lib.objects.PathObjects
import qupath.lib.objects.PathObject
import qupath.lib.objects.PathDetectionObject
import qupath.lib.objects.PathCellObject
import qupath.lib.roi.ROIs
import qupath.lib.regions.ImagePlane
import qupath.lib.measurements.MeasurementList
import qupath.lib.objects.PathCellObject
Thanks a lot @AthiemoneZero , I'll update my script based on your modifications, indeed some parts are not up to date
It is really tricky somehow. I reopen my project, re-export on ABBA, and re-import using codes on the document:
setImageType('FLUORESCENCE'); clearAllObjects(); qupath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", false);
The entry folder this time shows the ABBA files. Strangely
But this time it raise a new error:
This could be sovled by changing
false
intotrue
within this codequpath.ext.biop.abba.AtlasTools.loadWarpedAtlasAnnotations(getCurrentImageData(), "acronym", false);
but again when going to run 'DetectCellsABBA.groovy' code, the bug is still here:
Indeed, the ABBA transformation file is on the folder.
