Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save beosro/da77af6247c51d047cf5663ee678b366 to your computer and use it in GitHub Desktop.
Save beosro/da77af6247c51d047cf5663ee678b366 to your computer and use it in GitHub Desktop.

Revisions

  1. @Svidro Svidro revised this gist Jun 16, 2020. 15 changed files with 22 additions and 10 deletions.
    2 changes: 1 addition & 1 deletion A simple cell classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    // from http://forum.imagej.net/t/counting-double-labeled-cells-in-fiji/3832/2

    //0.1.2 and 0.2.0 (though channel names have changed in 0.2.0)
    positive = getPathClass('Positive')
    negative = getPathClass('Negative')
    for (cell in getCellObjects()) {
    2 changes: 1 addition & 1 deletion A simple classifier 2.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    // From Pete's post on Gitter, another way of applying cell classifications

    //0.1.2 and 0.2.0 (though channel names have changed in 0.2.0)
    // Get cells & reset all the classifications
    def cells = getCellObjects()
    resetDetectionClassifications()
    2 changes: 2 additions & 0 deletions Annotation Classifications to Name field.groovy
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    //Remove annotation classification and rename the annotation to the original class
    //0.1.2 and 0.2.0

    for (annotation in getAnnotationObjects()) {
    def pathClass = annotation.getPathClass()
    if (pathClass == null)
    2 changes: 2 additions & 0 deletions Annotation classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    //Here I used optical density only. You will need to add any intensity features you want to the classifier
    //0.1.2 and 0.2.0

    import qupath.lib.objects.classes.PathClassFactory

    //Use add intensity features to add whatever values you need to determine a class
    2 changes: 2 additions & 0 deletions Classifier sample.groovy
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,8 @@
    //It has to be character for character the same as what the program uses, sorry! Some of the scripts in Coding Helper Functions
    //might help with this if you are having trouble.

    //0.1.2 and 0.2.0

    import qupath.lib.objects.classes.PathClass
    import qupath.lib.objects.classes.PathClassFactory

    2 changes: 1 addition & 1 deletion JSON classifier on specific objects.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    //https://forum.image.sc/t/selecting-slic-tiles/34942/12
    //Running a classifier on a specific set of objects, M9
    //0.2.0

    def imageData = getCurrentImageData()
    def classifier = loadObjectClassifier('Other tiles')
    2 changes: 2 additions & 0 deletions JSON object classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    //https://forum.image.sc/t/scripting-json-classifiers-in-qupath-0-2-0-m9/34614/2?u=research_associate
    //0.2.0
    //You can also copy the classifier into the current project folder (from a locked in source location) as part of the script, to use this command.

    runObjectClassifier("My classifier name")
    4 changes: 4 additions & 0 deletions OneStep Classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,6 @@
    //Classify cells only by one value. This can be any measurement, including one you created.

    //0.1.2 and 0.2.0
    // This can be run on top of other classifications, making any current classifications both their original clas, and the subclass positive or negative

    setCellIntensityClassifications("Cytoplasm: DAB OD mean", 0.15)
    2 changes: 1 addition & 1 deletion Pete base classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    /**
    /** 0.1.2
    * Create a QuPath classifier by scripting, rather than the 'standard' way with annotations.
    *
    * This selects training regions according to a specified criterion based on staining,
    1 change: 1 addition & 0 deletions Reclassify one class with derived classes.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    //Based off of script by melvingelbard
    //https://forum.image.sc/t/setcellintensityclassifications-for-a-certain-class/33347/3
    //0.2.0
    def measurementName = "Nucleus: Hematoxylin OD min";
    def thresholds = [0.05, 0.2] as double[];

    2 changes: 2 additions & 0 deletions Reset Cell Classifications only.groovy
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,6 @@
    //Useful if you want to reset your classifier but do NOT want to reset other classifications, such as subcellular detections
    //0.1.2 and 0.2.0

    for (def cell : getCellObjects())
    cell.setPathClass(null)
    fireHierarchyUpdate()
    3 changes: 0 additions & 3 deletions Run Object Classifier M9.groovy
    Original file line number Diff line number Diff line change
    @@ -1,3 +0,0 @@
    //https://forum.image.sc/t/scripting-json-classifiers-in-qupath-0-2-0-m9/34614/2?u=research_associate

    runObjectClassifier("My classifier name")
    2 changes: 1 addition & 1 deletion Set Selected Object Class.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    //Select an object or several objects before running.

    //0.1.2 and 0.2.0
    //Change Tumor to the class you want to add
    def Class = getPathClass('Tumor')

    2 changes: 1 addition & 1 deletion Subcellular detection to nuclear or cyto.groovy
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    //Classify your subcellular detections based on their X-Y coordinate centers.
    // https://github.com/qupath/qupath/wiki/Spot-detection

    //0.1.2
    def clusters = getObjects({p -> p.class == qupath.imagej.detect.cells.SubcellularDetection.SubcellularObject.class})

    // Loop through all clusters
    2 changes: 1 addition & 1 deletion Training set combining.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    //https://github.com/qupath/qupath/issues/256

    //0.1.2
    // Paths to training files (here, both relative to the current project)
    paths = [
    buildFilePath(PROJECT_BASE_DIR, 'training', 'my_training.qptrain'),
  2. @Svidro Svidro revised this gist Mar 30, 2020. 2 changed files with 5 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,8 @@ Classifier sample.groovy - Another cell classifier, but more complicated format.

    JSON classifier on specific objects.groovy - How to target specific objects with the new classifiers as of M9

    JSON object classifier.groovy - simple one line script

    OneStep Classifier.groovy - In case I forget the name of the function.

    Pete base classifier.groovy - One of the original classification scripts, has the most protections against errors.
    3 changes: 3 additions & 0 deletions JSON object classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    //https://forum.image.sc/t/scripting-json-classifiers-in-qupath-0-2-0-m9/34614/2?u=research_associate

    runObjectClassifier("My classifier name")
  3. @Svidro Svidro revised this gist Mar 13, 2020. 2 changed files with 11 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -14,6 +14,8 @@ Annotation classifier.groovy - Classify annotations.

    Classifier sample.groovy - Another cell classifier, but more complicated format.

    JSON classifier on specific objects.groovy - How to target specific objects with the new classifiers as of M9

    OneStep Classifier.groovy - In case I forget the name of the function.

    Pete base classifier.groovy - One of the original classification scripts, has the most protections against errors.
    9 changes: 9 additions & 0 deletions JSON classifier on specific objects.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    //https://forum.image.sc/t/selecting-slic-tiles/34942/12
    //Running a classifier on a specific set of objects, M9

    def imageData = getCurrentImageData()
    def classifier = loadObjectClassifier('Other tiles')

    def tiles = getDetectionObjects().findAll {it.isTile()}
    classifier.classifyObjects(imageData, tiles, true)
    fireHierarchyUpdate()
  4. @Svidro Svidro revised this gist Mar 3, 2020. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Run Object Classifier M9.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    //https://forum.image.sc/t/scripting-json-classifiers-in-qupath-0-2-0-m9/34614/2?u=research_associate

    runObjectClassifier("My classifier name")
  5. @Svidro Svidro revised this gist Jan 27, 2020. 2 changed files with 10 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,8 @@ OneStep Classifier.groovy - In case I forget the name of the function.

    Pete base classifier.groovy - One of the original classification scripts, has the most protections against errors.

    Reclassify one class with derived classes.groovy - Takes the Tumor class and allows derived classes based on hematoxylin thresholds

    Rename and recolor a class.groovy - Not included here, see: https://gist.github.com/Svidro/e00021dff92ea1173e535008854be72e#file-rename-and-recolor-a-class-groovy

    Reset Cell Classifications only.groovy - Important when you have subcellular detections. You would not want to reset their class as that
    8 changes: 8 additions & 0 deletions Reclassify one class with derived classes.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    //Based off of script by melvingelbard
    //https://forum.image.sc/t/setcellintensityclassifications-for-a-certain-class/33347/3
    def measurementName = "Nucleus: Hematoxylin OD min";
    def thresholds = [0.05, 0.2] as double[];

    classCells = getCellObjects().findAll{it.getPathClass() == getPathClass("Tumor")}

    setIntensityClassifications(classCells, measurementName, thresholds);
  6. @Svidro Svidro revised this gist Aug 16, 2019. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -29,3 +29,11 @@ Subcellular detection to nuclear or cyto.groovy - Pete's script for checking whe
    Creates a derived class.

    Training set combining.groovy - combine two or more training set files from different projects/images

    *Many of these scripts are out of date, and you can get a list of active classes various ways:
    Set classList = []
    for (object in getAllObjects().findAll{it.isDetection() /*|| it.isAnnotation()*/}) {
    classList << object.getPathClass()
    }

    def classifications = new ArrayList<>(getDetectionObjects().collect {it.getPathClass()} as Set)
  7. @Svidro Svidro revised this gist Jun 13, 2019. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    Collection of scripts mostly from Pete, but also taken from the forums
    Collection of scripts mostly from Pete, but also taken from the forums. Note you can always run a saved classifier using the
    runClassifier() command, with the file path included as a string.

    TOC

  8. @Svidro Svidro revised this gist Jan 27, 2019. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -17,6 +17,8 @@ OneStep Classifier.groovy - In case I forget the name of the function.

    Pete base classifier.groovy - One of the original classification scripts, has the most protections against errors.

    Rename and recolor a class.groovy - Not included here, see: https://gist.github.com/Svidro/e00021dff92ea1173e535008854be72e#file-rename-and-recolor-a-class-groovy

    Reset Cell Classifications only.groovy - Important when you have subcellular detections. You would not want to reset their class as that
    alters the summary values in the cell measurement list.

  9. @Svidro Svidro revised this gist Jan 18, 2019. 2 changed files with 43 additions and 0 deletions.
    1 change: 1 addition & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -25,3 +25,4 @@ Set Selected Object Class.groovy - Change the class of a specific object. Much l
    Subcellular detection to nuclear or cyto.groovy - Pete's script for checking whether a subcellular detection is within the nucleus.
    Creates a derived class.

    Training set combining.groovy - combine two or more training set files from different projects/images
    42 changes: 42 additions & 0 deletions Training set combining.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    //https://github.com/qupath/qupath/issues/256

    // Paths to training files (here, both relative to the current project)
    paths = [
    buildFilePath(PROJECT_BASE_DIR, 'training', 'my_training.qptrain'),
    buildFilePath(PROJECT_BASE_DIR, 'training', 'my_training2.qptrain'),
    ]

    // Path to output training file
    pathOutput = buildFilePath(PROJECT_BASE_DIR, 'training', 'merged.qptrain')

    // Count mostly helps to ensure we're adding with unique keys
    count = 0

    // Loop through training files
    def result = null
    for (path in paths) {
    // .qptrain files just have one object but class isn't public, so
    // we take the first one that is deserialized
    new File(path).withObjectInputStream {
    saved = it.readObject()
    }
    // Add the training objects, appending an extra number which
    // (probably, unless very unfortunate with image names?) means they are unique
    map = new HashMap<>(saved.getMap())
    if (result == null) {
    result = saved
    result.clear()
    }
    for (entry in map.entrySet())
    result.put(entry.getKey() + '-' + count, entry.getValue())
    count++
    }

    // Check how big the map is & what it contains
    print result.size()
    print result.getMap().keySet().each { println it }

    // Write out a new training file
    new File(pathOutput).withObjectOutputStream {
    it.writeObject(result)
    }
  10. @Svidro Svidro revised this gist Jan 18, 2019. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions A simple classifier 2.groovy
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,5 @@
    // From Pete's post on Gitter, another way of applying cell classifications

    import static qupath.lib.scripting.QPEx.*

    // Get cells & reset all the classifications
    def cells = getCellObjects()
    resetDetectionClassifications()
  11. @Svidro Svidro revised this gist Jan 2, 2019. 4 changed files with 28 additions and 1 deletion.
    28 changes: 27 additions & 1 deletion !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -1 +1,27 @@
    Collection of scripts mostly from Pete, but also taken from the forums
    Collection of scripts mostly from Pete, but also taken from the forums

    TOC

    A simple cell classifier.groovy - One way to classify cells.

    A simple classifier 2.groovy - Another way.

    Annotation Classifications to Name field.groovy - Sets the Name of the annotation to its classification. Useful for applying a second
    classifier without losing the results of the first.

    Annotation classifier.groovy - Classify annotations.

    Classifier sample.groovy - Another cell classifier, but more complicated format.

    OneStep Classifier.groovy - In case I forget the name of the function.

    Pete base classifier.groovy - One of the original classification scripts, has the most protections against errors.

    Reset Cell Classifications only.groovy - Important when you have subcellular detections. You would not want to reset their class as that
    alters the summary values in the cell measurement list.

    Set Selected Object Class.groovy - Change the class of a specific object. Much like the annotation context menu, but works for detections

    Subcellular detection to nuclear or cyto.groovy - Pete's script for checking whether a subcellular detection is within the nucleus.
    Creates a derived class.

    File renamed without changes.
    File renamed without changes.
    1 change: 1 addition & 0 deletions Subcellular detection to nuclear or cyto.groovy
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    //Classify your subcellular detections based on their X-Y coordinate centers.
    // https://github.com/qupath/qupath/wiki/Spot-detection

    def clusters = getObjects({p -> p.class == qupath.imagej.detect.cells.SubcellularDetection.SubcellularObject.class})

  12. @Svidro Svidro revised this gist Nov 20, 2018. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions Set Selected Object Class.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,9 @@
    //Select an object or several objects before running.

    //Change Tumor to the class you want to add
    def Class = getPathClass('Tumor')


    selected = getSelectedObjects()
    for (def detection in selected){
    detection.setPathClass(Class)
  13. @Svidro Svidro revised this gist Nov 20, 2018. 1 changed file with 4 additions and 7 deletions.
    11 changes: 4 additions & 7 deletions Set Selected Object Class.groovy
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,8 @@
    import qupath.lib.objects.classes.PathClass
    import qupath.lib.objects.classes.PathClassFactory
    //Change the class to the one you want
    def YourClass = "Tumor"
    def Class = PathClassFactory.getPathClass(YourClass)
    //Change Tumor to the class you want to add
    def Class = getPathClass('Tumor')
    selected = getSelectedObjects()
    for (def thing in selected){
    thing.setPathClass(Class)
    for (def detection in selected){
    detection.setPathClass(Class)
    }
    fireHierarchyUpdate()
    println("Done!")
  14. @Svidro Svidro revised this gist Aug 21, 2018. 1 changed file with 22 additions and 0 deletions.
    22 changes: 22 additions & 0 deletions A simple classifier 2.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    // From Pete's post on Gitter, another way of applying cell classifications

    import static qupath.lib.scripting.QPEx.*

    // Get cells & reset all the classifications
    def cells = getCellObjects()
    resetDetectionClassifications()

    cells.each {it.setPathClass(getPathClass('Negative'))}

    // Get channel 1 & 2 positives
    def ch1Pos = cells.findAll {measurement(it, "Nucleus: Channel 1 mean") > 5}
    ch1Pos.each {it.setPathClass(getPathClass('Ch 1 positive'))}

    def ch2Pos = cells.findAll {measurement(it, "Nucleus: Channel 2 mean") > 0.2}
    ch2Pos.each {it.setPathClass(getPathClass('Ch 2 positive'))}

    // Overwrite classifications for double positives
    def doublePos = ch1Pos.intersect(ch2Pos)
    doublePos.each {it.setPathClass(getPathClass('Double positive'))}

    fireHierarchyUpdate()
  15. @Svidro Svidro revised this gist Aug 21, 2018. No changes.
  16. @Svidro Svidro revised this gist Jul 17, 2018. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions Annotation Classifications to Name field.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    //Remove annotation classification and rename the annotation to the original class
    for (annotation in getAnnotationObjects()) {
    def pathClass = annotation.getPathClass()
    if (pathClass == null)
    continue
    annotation.setName(pathClass.getName())
    // annotation.setColorRGB(pathClass.getColor())
    annotation.setPathClass(null)
    }
    fireHierarchyUpdate()

    //Restore the classification based on the annotation name (reverse the above effects)
    for (annotation in getAnnotationObjects()) {
    def name = annotation.getName()
    if (name == null)
    continue
    def pathClass = getPathClass(name)
    annotation.setPathClass(pathClass)
    }
    fireHierarchyUpdate()
  17. @Svidro Svidro revised this gist Jun 30, 2018. 1 changed file with 66 additions and 0 deletions.
    66 changes: 66 additions & 0 deletions Create a classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    /**
    * Create a QuPath classifier by scripting, rather than the 'standard' way with annotations.
    *
    * This selects training regions according to a specified criterion based on staining,
    * and then creates a classifier that uses other features.
    *
    * The main aim is to show the general idea of creating a classifier by scripting.
    *
    * @author Pete Bankhead
    */

    import qupath.lib.classifiers.Normalization
    import qupath.lib.classifiers.PathClassificationLabellingHelper
    import qupath.lib.objects.PathObject
    import qupath.lib.objects.classes.PathClassFactory
    import qupath.lib.scripting.QPEx

    // Optionally check what will be used for training -
    // setting the training classification for each cell & not actually building the classifier
    // (i.e. just do a sanity check)
    boolean checkTraining = false

    // Get all cells
    def cells = QPEx.getCellObjects()

    // Split by some kind of DAB measurement
    def isTumor = {PathObject cell -> return cell.getMeasurementList().getMeasurementValue('Cell: DAB OD mean') > 0.2}
    def tumorCells = cells.findAll {isTumor(it)}
    def nonTumorCells = cells.findAll {!isTumor(it)}
    print 'Number of tumor cells: ' + tumorCells.size()
    print 'Number of non-tumor cells: ' + nonTumorCells.size()

    // Create a relevant map for training
    def map = [:]
    map.put(PathClassFactory.getPathClass('Tumor'), tumorCells)
    map.put(PathClassFactory.getPathClass('Stroma'), nonTumorCells)

    // Check training... if necessary
    if (checkTraining) {
    print 'Showing training classifications (not building a classifier!)'
    map.each {classification, list ->
    list.each {it.setPathClass(classification)}
    }
    QPEx.fireHierarchyUpdate()
    return
    }

    // Get features & filter out the ones that shouldn't be used (here, any connected to intensities)
    def features = PathClassificationLabellingHelper.getAvailableFeatures(cells)
    features = features.findAll {!it.toLowerCase().contains(': dab') && !it.toLowerCase().contains(': hematoxylin')}

    // Print the features
    print Integer.toString(features.size()) + ' features: \n\t' + String.join('\n\t', features)

    // Create a new random trees classifier with default settings & no normalization
    print 'Training classifier...'
    // This would show available parameters
    // print classifier.getParameterList().getParameters().keySet()
    def classifier = new qupath.opencv.classify.RTreesClassifier()
    classifier.updateClassifier(map, features as List, Normalization.NONE)

    // Actually run the trained classifier
    print 'Applying classifier...'
    classifier.classifyPathObjects(cells)
    QPEx.fireHierarchyUpdate()
    print 'Done!'
  18. @Svidro Svidro revised this gist Jun 5, 2018. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions A simple cell classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    // from http://forum.imagej.net/t/counting-double-labeled-cells-in-fiji/3832/2

    positive = getPathClass('Positive')
    negative = getPathClass('Negative')
    for (cell in getCellObjects()) {
    ch1 = measurement(cell, 'Cell: Channel 1 mean')
    ch2 = measurement(cell, 'Cell: Channel 2 mean')
    if (ch1 > 100 && ch2 > 200)
    cell.setPathClass(positive)
    else
    cell.setPathClass(negative)
    }
    fireHierarchyUpdate()
  19. @Svidro Svidro revised this gist Feb 17, 2018. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Classifier sample.groovy
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,8 @@
    //Simplified script for classifying cells based on their values. Can easily be dramatically expanded as much as you may like
    //by adding features and thresholds
    //If all of your results are showing up as one class, it is probably because the feature variable is not exaaaactly correct.
    //It has to be character for character the same as what the program uses, sorry! Some of the scripts in Coding Helper Functions
    //might help with this if you are having trouble.

    import qupath.lib.objects.classes.PathClass
    import qupath.lib.objects.classes.PathClassFactory
  20. @Svidro Svidro revised this gist Feb 17, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Classifier sample.groovy
    Original file line number Diff line number Diff line change
    @@ -48,7 +48,7 @@ for (def cell : getCellObjects()) {
    cell.setPathClass(Low)
    }else if ( spots > 1 ){
    cell.setPathClass(Lowest)
    }else pathObject.setPathClass(Negative)
    }else cell.setPathClass(Negative)

    }

  21. @Svidro Svidro revised this gist Feb 8, 2018. 2 changed files with 60 additions and 1 deletion.
    1 change: 0 additions & 1 deletion Annotation classifier
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,6 @@
    import qupath.lib.objects.classes.PathClassFactory

    //Use add intensity features to add whatever values you need to determine a class
    //Here I used optical density only.
    selectAnnotations();

    //If you have already added features to your annotations, you will not need this line
    60 changes: 60 additions & 0 deletions Classifier sample.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    //Simplified script for classifying cells based on their values. Can easily be dramatically expanded as much as you may like
    //by adding features and thresholds

    import qupath.lib.objects.classes.PathClass
    import qupath.lib.objects.classes.PathClassFactory


    //This part resets the classifier so that you can run it again. Clearing detection classifications would also clear your subcellular detections

    for (def cell : getCellObjects())
    cell.setPathClass(null)
    fireHierarchyUpdate()


    // Parameters to modify
    def feature = "Subcellular: Channel 2: Num spots estimated"

    //Not using these in this example, but they could be used to further expand the classifier below
    //def threshold = 1
    //def feature2 = "Cytoplasm: Channel 2 mean"
    //def threshold2 = 30


    // Check what base classifications we should be worried about
    // It's possible to specify 'All', or select specific classes and exclude others

    def Negative = PathClassFactory.getPathClass("Negative")
    def Lowest = PathClassFactory.getPathClass("1-3 spots")
    def Low = PathClassFactory.getPathClass("4-9 spots")
    def Medium = PathClassFactory.getPathClass("10-15 spots")
    def High = PathClassFactory.getPathClass("15+ spots")


    // Loop through all cells
    for (def cell : getCellObjects()) {
    //Assign the measurement for "feature" from above for this cell to a variable. In this case I named it spots
    double spots = cell.getMeasurementList().getMeasurementValue(feature)

    //If you need further measurements for your classifier, get them here
    //double val2 = pathObject.getMeasurementList().getMeasurementValue(feature2)

    // Set class based on the value(s) obtained
    if ( spots > 15){
    cell.setPathClass(High)
    }else if ( spots > 9 ){
    cell.setPathClass(Medium)
    }else if ( spots > 3 ){
    cell.setPathClass(Low)
    }else if ( spots > 1 ){
    cell.setPathClass(Lowest)
    }else pathObject.setPathClass(Negative)

    }

    // Fire update event
    fireHierarchyUpdate()

    // Make sure we know we're done
    println("Done!")

  22. @Svidro Svidro revised this gist Jan 25, 2018. 4 changed files with 41 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions OneStep Classifier.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    //Classify cells only by one value. This can be any measurement, including one you created.
    setCellIntensityClassifications("Cytoplasm: DAB OD mean", 0.15)
    5 changes: 5 additions & 0 deletions Reset Cell Classifications only.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    //Useful if you want to reset your classifier but do NOT want to reset other classifications, such as subcellular detections
    for (def cell : getCellObjects())
    cell.setPathClass(null)
    fireHierarchyUpdate()
    println("Done!")
    11 changes: 11 additions & 0 deletions Set Selected Object Class.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    import qupath.lib.objects.classes.PathClass
    import qupath.lib.objects.classes.PathClassFactory
    //Change the class to the one you want
    def YourClass = "Tumor"
    def Class = PathClassFactory.getPathClass(YourClass)
    selected = getSelectedObjects()
    for (def thing in selected){
    thing.setPathClass(Class)
    }
    fireHierarchyUpdate()
    println("Done!")
    23 changes: 23 additions & 0 deletions Subcellular detection to nuclear or cyto.groovy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    //Classify your subcellular detections based on their X-Y coordinate centers.

    def clusters = getObjects({p -> p.class == qupath.imagej.detect.cells.SubcellularDetection.SubcellularObject.class})

    // Loop through all clusters
    for (c in clusters) {
    // Find the containing cell
    def cell = c.getParent()
    // Check the current classification - remove the last part if it
    // was generated by a previous run of this command
    def pathClass = c.getPathClass()
    if (["Nuclear", "Cytoplasmic"].contains(c.getName())) {
    pathClass = pathClass.getParentClass()
    }
    // Check the location of the cluster centroid relative to the nucleus,
    // and classify accordingly
    def nucleus = cell.getNucleusROI()
    if (nucleus != null && nucleus.contains(c.getROI().getCentroidX(), c.getROI().getCentroidY())) {
    c.setPathClass(getDerivedPathClass(c.getPathClass(), "Nuclear"))
    } else
    c.setPathClass(getDerivedPathClass(c.getPathClass(), "Cytoplasmic"))
    }
    fireHierarchyUpdate()
  23. @Svidro Svidro created this gist Jan 25, 2018.
    1 change: 1 addition & 0 deletions !Classifying objects in QuPath
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Collection of scripts mostly from Pete, but also taken from the forums
    28 changes: 28 additions & 0 deletions Annotation classifier
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    //Here I used optical density only. You will need to add any intensity features you want to the classifier
    import qupath.lib.objects.classes.PathClassFactory

    //Use add intensity features to add whatever values you need to determine a class
    //Here I used optical density only.
    selectAnnotations();

    //If you have already added features to your annotations, you will not need this line
    runPlugin('qupath.lib.algorithms.IntensityFeaturesPlugin', '{"pixelSizeMicrons": 2.0, "region": "ROI", "tileSizeMicrons": 25.0, "colorOD": true, "colorStain1": false, "colorStain2": false, "colorStain3": false, "colorRed": false, "colorGreen": false, "colorBlue": false, "colorHue": false, "colorSaturation": false, "colorBrightness": false, "doMean": true, "doStdDev": false, "doMinMax": false, "doMedian": false, "doHaralick": false, "haralickDistance": 1, "haralickBins": 32}');


    def ClassA = PathClassFactory.getPathClass("ClassA")
    def ClassB = PathClassFactory.getPathClass("ClassB")

    //feature has to be exact, including spaces. This can be tricky
    //for the above you would need: "ROI: 2.00 " + qupath.lib.common.GeneralTools.micrometerSymbol() + " per pixel: OD Sum: Mean"
    def feature = "ROI: 2.00 " + qupath.lib.common.GeneralTools.micrometerSymbol() + " per pixel: OD Sum: Mean"
    //get all annotations in the image
    Annotations = getAnnotationObjects();
    Annotations.each {
    double value = it.getMeasurementList().getMeasurementValue(feature)
    print(it.getMeasurementList())
    //use logic here to determine whether each "it" or annotation will be a given class
    //this can be as complicated as you want, or as simple as a single if statement.
    if (value > 0.45) {it.setPathClass(ClassA)}
    else { it.setPathClass(ClassB)}
    }
    println("Annotation classification done")