Color changes in QuPath
Collections of scripts to alter object colors harvested mainly from Pete, but also picked up from the forums | |
TOC | |
Adjust fluorescence contrast.groovy - Adjusts the display channels. Only works if the image is currently visible. Version 0.1.3 saves | |
these changes once made, but this can keep consistent display coloring between images. | |
Change IF channel color.groovy - Change the LUT for individual channels. Does not work with OpenSlide servers (check Image tab). | |
Change colors by subclass.groovy - Detection object color adjustment when using subclasses. | |
Change subcellular detection color - Hugely useful when working with subcellular detections as, by default, they are a derived class | |
and cannot be altered directly through the Annotation tab interface. | |
Density heatmap by class.groovy - Add a measurement to cells that can be used to visually identify hotspots per class | |
Density heatmap by class with blur.groovy - better looking heatmap than above. | |
Measurement map buttons.groovy - create some fixed buttons to make viewing consistent measurement maps much easeier. | |
Measurement Maps color lock.groovy - set fixed values for the measurement maps. Useful when comparing two images to each other and | |
keeping the same relative color display values. | |
Measurement Maps in 0.2.0.groovy - a code example for how to use measurement maps in version 0.2.0 | |
Rename and recolor a class.groovy - <-- what it says | |
Show specific classes of objects v3.groovy - adds in checkboxes for groups of similarly named classes | |
Specific Object Color changes.groovy - A way of cycling through objects and set each object to a different color | |
TMA heatmap by color.groovy - Create detection objects in each TMA core, giving them measurements that are summaries of what is | |
in the core. When Measurement maps are used and one of the summary measurments is selected, the whole TMA turns into a heatmap | |
1 | |
From Gitter: | |
If you have a class already created, you can alter the color for that class (replace pathClass with the class) | |
pathClass.setColor(getColorRGB(0, 200, 0)) | |
This requires having the class as a variable, for example: | |
stroma = getPathClass('Stroma') | |
recolored would be: | |
stroma.setColor(getColorRGB(0, 200, 0)) |
//From https://github.com/qupath/qupath/issues/191 | |
//https://groups.google.com/forum/#!searchin/qupath-users/viewer%7Csort:date/qupath-users/uBMxJ_3JnBM/GkDahJw7EAAJ | |
// Get access to the display info for each channel | |
//0.1.2 | |
//For 0.2.0 use viewer.getImageDisplay().availableChannels() | |
def viewer = getCurrentViewer() | |
def channels = viewer.getImageDisplay().getAvailableChannels() | |
// Set the range for the first two channels | |
channels[0].setMinDisplay(0) | |
channels[0].setMaxDisplay(100) | |
channels[1].setMinDisplay(0) | |
channels[1].setMaxDisplay(500) | |
// Ensure the updates are visible | |
viewer.repaintEntireImage() | |
// Usually a good idea to print something, so we know it finished | |
print 'Done!' |
// https://groups.google.com/forum/#!topic/qupath-users/rBCRysCZEzM | |
//0.1.2 and 0.2.0 | |
// Access the 'Stroma: Positive' sub-classification | |
stroma = getPathClass('Stroma') | |
stromaPositive = getDerivedPathClass(stroma, 'Positive') | |
// Set the color, using a packed RGB value | |
color = getColorRGB(200, 0, 0) | |
stromaPositive.setColor(color) | |
// Update the GUI | |
fireHierarchyUpdate() |
// Get access to the display info for each channel | |
//For 0.2.0+ use: https://forum.image.sc/t/a-bug-in-batch-processing/40956/2?u=research_associate | |
setChannelColors( | |
getColorRGB(0, 0, 255), | |
getColorRGB(0, 255, 0), | |
getColorRGB(255, 0, 255), | |
getColorRGB(255, 0, 0) | |
) | |
//https://forum.image.sc/t/script-to-rename-channels-and-adjust-brightness-contrast/40984/4?u=research_associate | |
//setChannelColor | |
//setChannelNames | |
//setChannelDisplayRange | |
//This function changed between 0.1.2 and 0.2.0, in 0.2.0 use viewer.getImageDisplay().availableChannels() | |
def viewer = getCurrentViewer() | |
def channels = viewer.getImageDisplay().getAvailableChannels() | |
// Set the LUT color for the first channel & repaint | |
channels[0].setLUTColor(0, 0, 255) | |
channels[1].setLUTColor(255, 255, 255) | |
channels[2].setLUTColor(0, 255, 0) | |
channels[3].setLUTColor(255, 0, 0) | |
// Ensure the updates are visible | |
viewer.repaintEntireImage() | |
// Usually a good idea to print something, so we know it finished | |
print 'Done!' |
//0.1.2 and 0.2.0 | |
getDerivedPathClass(getPathClass('Subcellular cluster'), 'DAB object').setColor(qupath.lib.common.ColorTools.makeRGB(30, 30, 30)) |
// https://forum.image.sc/t/cell-density-map/40050/16 | |
/** | |
* Create a 'counts' image in QuPath that can be used to compute the local density of specific objects. | |
* | |
* This implementation uses ImageJ to create and display the image, which can then be filtered as required. | |
* | |
* Written for QuPath v0.2.0. | |
* | |
* @author Pete Bankhead | |
*/ | |
// Define the resolution at which the image should be generated | |
double requestedPixelSizeMicrons = 50 | |
double sigma = 1.5 | |
double accuracy = 0.01 | |
classList = getCurrentHierarchy().getDetectionObjects().collect{it.getPathClass()} as Set | |
// Get the current image | |
def imageData = getCurrentImageData() | |
def server = imageData.getServer() | |
// Set the downsample directly (without using the requestedPixelSize) if you want; 1.0 indicates the full resolution | |
double downsample = requestedPixelSizeMicrons / server.getPixelCalibration().getAveragedPixelSizeMicrons() | |
def request = RegionRequest.createInstance(server, downsample) | |
def imp = IJTools.convertToImagePlus(server, request).getImage() | |
// Get the objects you want to count | |
// Potentially you can add filters for specific objects, e.g. to get only those with a 'Positive' classification | |
def detections = getDetectionObjects() | |
classList.each{c-> | |
cellList = getCellObjects().findAll{it.getPathClass() == c} | |
// Create a counts image in ImageJ, where each pixel corresponds to the number of centroids at that pixel | |
int width = imp.getWidth() | |
int height = imp.getHeight() | |
def fp = new FloatProcessor(width, height) | |
for (detection in cellList) { | |
// Get ROI for a detection; this method gets the nucleus if we have a cell object (and the only ROI for anything else) | |
def roi = PathObjectTools.getROI(detection, true) | |
int x = (int)(roi.getCentroidX() / downsample) | |
int y = (int)(roi.getCentroidY() / downsample) | |
fp.setf(x, y, fp.getf(x, y) + 1 as float) | |
} | |
//Here we blur fp. Increase sigma for more blurring. | |
def g = new GaussianBlur(); | |
g.blurGaussian(fp, sigma, sigma, accuracy); | |
for (detection in detections) { | |
// Get ROI for a detection; this method gets the nucleus if we have a cell object (and the only ROI for anything else) | |
def roi = PathObjectTools.getROI(detection, true) | |
int x = (int)(roi.getCentroidX() / downsample) | |
int y = (int)(roi.getCentroidY() / downsample) | |
detection.getMeasurementList().putMeasurement(c.toString()+' Density', fp.getf(x, y)) | |
} | |
} | |
import ij.ImagePlus | |
import ij.process.FloatProcessor | |
import ij.plugin.filter.GaussianBlur; | |
//import ij.plugin.filter.PlugInFilter; | |
import qupath.imagej.gui.IJExtension | |
import qupath.lib.objects.PathObjectTools | |
import qupath.lib.regions.RegionRequest | |
import static qupath.lib.gui.scripting.QPEx.* | |
import qupath.imagej.tools.IJTools |
// QP 0.2.3 | |
// This script takes the values generated by the Add smoothed features plugin to create a cell density map that can be viewed in Measure->Measurement Maps | |
// For example, Tumor cells would show up in the Measurement List as "Nearby cells - Tumor" | |
// Local density will be based on the radius used during Add smoothed features. | |
//////////CHANGE THIS ////// | |
String smoothedRadius = 15 | |
//////////////////////////// | |
//Alternatively, remove this line and use the Analyze->Calculate Features-> Add smoothed features with Smooth within classes checked. | |
selectAnnotations() | |
runPlugin('qupath.lib.plugins.objects.SmoothFeaturesPlugin', '{"fwhmMicrons": '+smoothedRadius+', "smoothWithinClasses": true}'); | |
classList = getCurrentHierarchy().getDetectionObjects().collect{it.getPathClass()} as Set | |
//Find the smoothed count | |
classList.each{c-> | |
cellList = getCellObjects().findAll{it.getPathClass() == c} | |
cellList.each{ | |
it.getMeasurementList().putMeasurement("Nearby cells - "+ c.toString(), measurement(it,"Smoothed: "+smoothedRadius+" µm: Nearby detection counts")) | |
} | |
//getCellObjects().findAll{it.getPathClass() != c}.each{it.getMeasurementList().putMeasurement("Nearby cells - "+ c.toString(), 0)} | |
} | |
print "Done" |
/** | |
* Set a MeasurementMapper in QuPath v0.1.2 to control the display in a script. | |
* | |
* Created for https://groups.google.com/d/msg/qupath-users/9kMNlg4sgAs/dUHQpROLDwAJ | |
* | |
* @author Pete Bankhead | |
*/ | |
import qupath.lib.gui.helpers.MeasurementMapper | |
import static qupath.lib.scripting.QPEx.* | |
// Define measurement & display range | |
def name = "Nucleus/Cell area ratio" // Set to null to reset | |
double minValue = 0.0 | |
double maxValue = 1.0 | |
// Request current viewer & objects | |
def viewer = getCurrentViewer() | |
def options = viewer.getOverlayOptions() | |
def detections = getDetectionObjects() | |
// Update the display | |
if (name) { | |
print String.format('Setting measurement map: %s (%.2f - %.2f)', name, minValue, maxValue) | |
def mapper = new MeasurementMapper(name, detections) | |
mapper.setDisplayMinValue(minValue) | |
mapper.setDisplayMaxValue(maxValue) | |
options.setMeasurementMapper(mapper) | |
} else { | |
print 'Resetting measurement map' | |
options.setMeasurementMapper(null) | |
} |
// from https://forum.image.sc/t/problem-running-script-from-publication/35542/7 | |
//0.2.0 | |
import qupath.lib.gui.tools.* | |
// Print the names (just to check which you want) | |
println MeasurementMapper.loadDefaultColorMaps() | |
// Choose one of them | |
def colorMapper = MeasurementMapper.loadDefaultColorMaps().find {it.getName() == 'Magma'} | |
// Create a measurement mapper | |
def detections = getDetectionObjects() | |
def measurementMapper = new MeasurementMapper(colorMapper, 'Nucleus: DAB OD mean', detections) | |
// Show the measurement mapper in the current viewer | |
def viewer = getCurrentViewer() | |
def overlayOptions = viewer.getOverlayOptions() | |
overlayOptions.setMeasurementMapper(measurementMapper) |
//0.1.2 - This is much easier to do through the interface or scripting in 0.2.0 | |
//To use in 0.2.0 swap the ColorToolsFX import to import qupath.lib.gui.tools.ColorToolsFX | |
import javafx.application.Platform | |
import javafx.beans.property.SimpleLongProperty | |
import javafx.geometry.Insets | |
import javafx.scene.Scene | |
import javafx.geometry.Pos | |
import javafx.scene.control.Button | |
import javafx.scene.control.Label | |
import javafx.scene.control.TextField | |
import javafx.scene.control.ColorPicker | |
import javafx.scene.control.ComboBox | |
import javafx.scene.control.TableColumn | |
import javafx.scene.layout.BorderPane | |
import javafx.scene.layout.GridPane | |
import javafx.scene.control.Tooltip | |
import javafx.stage.Stage | |
import qupath.lib.gui.QuPathGUI | |
import qupath.lib.gui.helpers.ColorToolsFX; | |
import javafx.scene.paint.Color; | |
int col = 0 | |
int row = 0 | |
int textFieldWidth = 120 | |
int labelWidth = 150 | |
def gridPane = new GridPane() | |
gridPane.setPadding(new Insets(10, 10, 10, 10)); | |
gridPane.setVgap(2); | |
gridPane.setHgap(10); | |
def titleLabel = new Label("Alter the color and name of a class of objects") | |
gridPane.add(titleLabel,col, row++, 3, 1) | |
def requestLabel = new Label("Original Name") | |
gridPane.add(requestLabel,col++, row, 1, 1) | |
def requestLabel2 = new Label("New Name") | |
gridPane.add(requestLabel2,col++, row, 1, 1) | |
def requestLabel3 = new Label("New Color") | |
gridPane.add(requestLabel3,col++, row++, 1, 1) | |
//new row | |
col = 0 | |
//generate a list of all in-use classes | |
Set classList = [] | |
for (object in getAllObjects().findAll{it.isDetection() || it.isAnnotation()}) { | |
classList << object.getPathClass() | |
} | |
//place all classes in a combobox | |
def ComboBox classText = new ComboBox(); | |
classList.each{classText.getItems().add(it)} | |
gridPane.add(classText, col++, row, 1, 1) | |
def TextField classText2 = new TextField("MyNewClass"); | |
classText2.setMaxWidth( textFieldWidth); | |
classText2.setAlignment(Pos.CENTER_RIGHT) | |
gridPane.add(classText2, col++, row, 1, 1) | |
def colorPicker = new ColorPicker() | |
gridPane.add(colorPicker, col, row++, 1, 1) | |
//ArrayList<Label> channelLabels | |
Button startButton = new Button() | |
startButton.setText("Alter Class") | |
gridPane.add(startButton, 0, row++, 1, 1) | |
//startButton.setTooltip(new Tooltip("If you need to change the number of classes, re-run the script")); | |
startButton.setOnAction { | |
changeList = getAllObjects().findAll{it.getPathClass() == getPathClass(classText.getValue().toString())} | |
changeList.each{ | |
it.setPathClass(getPathClass(classText2.getText())) | |
newClass = getPathClass(classText2.getText()) | |
newClass.setColor(ColorToolsFX.getRGBA(colorPicker.getValue())) | |
} | |
fireHierarchyUpdate() | |
} | |
//Some stuff that controls the dialog box showing up. I don't really understand it but it is needed. | |
Platform.runLater { | |
def stage = new Stage() | |
stage.initOwner(QuPathGUI.getInstance().getStage()) | |
stage.setScene(new Scene( gridPane)) | |
stage.setTitle("Class editor") | |
stage.setWidth(450); | |
stage.setHeight(200); | |
//stage.setResizable(false); | |
stage.show() | |
} |
//Objective: A quicker way to show only certain classes and hide all others | |
//ANY GROUP CLASS CHECKING or UNCHECKED OVERWRITE ANY SINGLE CLASS CHANGES | |
//Written for 0.2.0 | |
separatorsForBaseClass = "[.-_,:]+" //add an extra symbol between the brackets if you need to split on a different character | |
import javafx.application.Platform | |
import javafx.geometry.Insets | |
import javafx.scene.Scene | |
import javafx.geometry.Pos | |
import javafx.scene.control.TableView | |
import javafx.scene.control.CheckBox | |
import javafx.scene.layout.BorderPane | |
import javafx.scene.layout.GridPane | |
import javafx.scene.control.ScrollPane | |
import javafx.scene.layout.BorderPane | |
import javafx.stage.Stage | |
import javafx.scene.input.MouseEvent | |
import javafx.beans.value.ChangeListener | |
import qupath.lib.gui.QuPathGUI | |
//Find all classifications of detections | |
/***************************************** | |
If you have subcellular objects, you may want | |
to change this to getCellObjects() rather than | |
getDetectionObjects() | |
*****************************************/ | |
def classifications = new ArrayList<>( getDetectionObjects().collect {it?.getPathClass()} as Set) | |
///////////////////////////////////////////////////////////// | |
List<String> classNames = new ArrayList<String>() | |
classifications.each{ | |
classNames<< it.toString() | |
} | |
Set baseClasses = [] | |
classifications.each{ | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().add(it) | |
it?.getName()?.tokenize(separatorsForBaseClass).each{str-> | |
baseClasses << str.trim() | |
} | |
} | |
print baseClasses | |
baseList = baseClasses | |
//Find strings with duplicates in baseClasses | |
//baseList = baseClasses.countBy{it}.grep{it.value > 1}.collect{it.key} | |
//Set up GUI | |
int col = 0 | |
int row = 0 | |
int textFieldWidth = 120 | |
int labelWidth = 150 | |
def gridPane = new GridPane() | |
gridPane.setPadding(new Insets(10, 10, 10, 10)); | |
gridPane.setVgap(2); | |
gridPane.setHgap(10); | |
ScrollPane scrollPane = new ScrollPane(gridPane) | |
scrollPane.setFitToHeight(true); | |
BorderPane border = new BorderPane(scrollPane) | |
border.setPadding(new Insets(15)); | |
//Separately set up a checkbox for All classes | |
allOn = new CheckBox("All") | |
allOn.setId("All") | |
gridPane.add( allOn, 1, row++, 1,1) | |
row = 1 | |
ArrayList<CheckBox> boxes = new ArrayList(classifications.size()); | |
//Create the checkboxes for each class | |
for (i=0; i<classifications.size();i++){ | |
cb = new CheckBox(classNames[i]) | |
cb.setId(classNames[i].toString()) | |
boxes.add(cb) | |
gridPane.add( cb, col, row++, 1,1) | |
} | |
//Create checkboxes for base classes, defined as some string that showed up in more than one class entry | |
ArrayList<CheckBox> baseBoxes = new ArrayList(baseList.size()); | |
row = 2 | |
for (i=0; i<baseList.size();i++){ | |
cb = new CheckBox(baseList[i]) | |
cb.setId(baseList[i]) | |
baseBoxes.add(cb) | |
gridPane.add( cb, 1, row++, 1,1) | |
} | |
//behavior for all single class checkboxes | |
//I can't seem to check which checkbox is selected when they are created dynamically, so the results are updated for all classes | |
for (c in boxes){ | |
c.selectedProperty().addListener({o, oldV, newV -> | |
firstCol = gridPane.getChildren().findAll{gridPane.getColumnIndex(it) == 0} | |
for (n in firstCol){ | |
if (n.isSelected()){ | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().remove(getPathClass(n.getId())) | |
}else {getCurrentViewer().getOverlayOptions().hiddenClassesProperty().add(getPathClass(n.getId()))} | |
} | |
} as ChangeListener) | |
} | |
//behavior for base class checkboxes | |
//I can't easily figure out which checkbox was last checked, so this overwrites any single class checkboxes that were selected or unselected | |
for (c in baseBoxes){ | |
c.selectedProperty().addListener({o, oldV, newV -> | |
//verify that we are in the second column, and the nodes are selected | |
secondColSel = gridPane.getChildren().findAll{gridPane.getColumnIndex(it) == 1 && it.isSelected()} | |
secondColUnSel = gridPane.getChildren().findAll{gridPane.getColumnIndex(it) == 1 && !it.isSelected()} | |
for (n in secondColUnSel){ | |
batch = gridPane.getChildren().findAll{gridPane.getColumnIndex(it) == 0 && it.getId().contains(n.getId())} | |
batch.each{ | |
it.setSelected(false) | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().add(getPathClass(it.getId())) | |
} | |
} | |
for (n in secondColSel){ | |
batch = gridPane.getChildren().findAll{gridPane.getColumnIndex(it) == 0 && it.getId().contains(n.getId())} | |
batch.each{ | |
it.setSelected(true) | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().remove(getPathClass(it.getId())) | |
} | |
} | |
} as ChangeListener) | |
} | |
//Turn all on or off based on the All checkbox | |
allOn.selectedProperty().addListener({o, oldV, newV -> | |
if (!allOn.isSelected()){ | |
classifications.each{ | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().add(it) | |
} | |
gridPane.getChildren().each{ | |
it.setSelected(false) | |
} | |
}else { | |
classifications.each{ | |
getCurrentViewer().getOverlayOptions().hiddenClassesProperty().remove(it) | |
} | |
gridPane.getChildren().each{ | |
it.setSelected(true) | |
} | |
} | |
}as ChangeListener) | |
//Some stuff that controls the dialog box showing up. I don't really understand it but it is needed. | |
Platform.runLater { | |
def stage = new Stage() | |
stage.initOwner(QuPathGUI.getInstance().getStage()) | |
stage.setScene(new Scene( border)) | |
stage.setTitle("Select classes to display") | |
stage.setWidth(800); | |
stage.setHeight(500); | |
stage.setResizable(true); | |
stage.show() | |
} |
//The information in this script could be generalized to alter the color for any object list, or any individual object (see Selecting things Gist) | |
//Another way to use it might be to create a list of names ["blue","green","red"] along with a list/map of groups of three values | |
// [[0,0,200],[0,200,0],[200,0,0]] and pull from each, which would create a predetermined rainbow of named objects | |
//0.1.2 and 0.2.0 | |
def annotations = getAnnotationObjects() | |
for (i = 0; i<annotations.size(); i++){ | |
def j = i.mod(255) | |
//modulus used to keep the RGB values in the 0-255 range | |
annotations[i].setColorRGB(getColorRGB(255-j,j, j)) | |
} | |
print "done" |
//For earlier versions of QuPath, tested in 0.1.3 | |
//Create a detection object the same size and shape as the TMA core | |
//Give it summary measurements for the percentage of cells of each class within the core | |
//When one of the Class % measurements is selected while viewing Measure->Measurement Maps, all other detections will disappear | |
//and only the summary detection objects will be visible. | |
//It may be best to turn off annotation visibility. | |
import qupath.lib.objects.PathDetectionObject | |
import qupath.lib.objects.PathCellObject | |
hierarchy = getCurrentHierarchy() | |
cores = hierarchy.getTMAGrid().getTMACoreList() | |
Set list = [] | |
for (object in getAllObjects().findAll{it.isDetection() /*|| it.isAnnotation()*/}) { | |
list << object.getPathClass().toString() | |
} | |
print list | |
print "before cores" | |
cores.each { | |
print "initiating core" | |
//Find the cell count in this core | |
total = hierarchy.getDescendantObjects(it, null, PathCellObject).size() | |
//Prevent divide by zero errors in empty TMA cores | |
if (total != 0){ | |
for (className in list) { | |
cellType = hierarchy.getDescendantObjects(it,null, PathCellObject).findAll{it.getPathClass() == getPathClass(className)}.size() | |
it.getMeasurementList().putMeasurement(className+" cell %", cellType/(total)*100) | |
} | |
} | |
else { | |
for (className in list) { | |
it.getMeasurementList().putMeasurement(className+" cell %", 0) | |
} | |
} | |
fireHierarchyUpdate() | |
print "core complete" | |
} | |
cores.each { | |
print it | |
roi = it.getROI() | |
coreName = it.getName()+" - Tile" | |
def detection = new PathDetectionObject(roi, getPathClass("Tile")) | |
hierarchy.addPathObject(detection, false) | |
ml = it.getMeasurementList() | |
for (i=0;i<ml.size(); i++){ | |
detection.getMeasurementList().putMeasurement(ml.getMeasurementName(i), measurement(it, ml.getMeasurementName(i))) | |
} | |
fireHierarchyUpdate() | |
} | |
println("Are you done yet?") |
// Add percentages by cell class to each TMA core | |
//Confirmed for 0.2.0 | |
print "Wait for the comment indicating that it is done!" | |
print "This process is slow." | |
import qupath.lib.objects.PathCellObject | |
def metadata = getCurrentImageData().getServer().getOriginalMetadata() | |
def pixelSize = metadata.pixelCalibration.pixelWidth.value | |
hierarchy = getCurrentHierarchy() | |
cores = hierarchy.getTMAGrid().getTMACoreList() | |
Set list = [] | |
for (object in getAllObjects().findAll{it.isDetection() /*|| it.isAnnotation()*/}) { | |
list << object.getPathClass() | |
} | |
print list | |
def cellList = [] | |
cores.each { | |
//Find the cell count in this core | |
cellList = [] | |
cellList = qupath.lib.objects.PathObjectTools.getDescendantObjects(it, cellList, PathCellObject) | |
total = cellList.size() | |
//Prevent divide by zero errors in empty TMA cores | |
if (total != 0){ | |
annos=it.getChildObjects()[0] | |
if (annos.isAnnotation()){ | |
for (className in list) { | |
cellType = cellList.findAll{p->p.getPathClass() == className}.size() | |
annotationArea = annos.getROI().getArea()*pixelSize*pixelSize/1000000 | |
println(cellType) | |
println(annotationArea) | |
it.getMeasurementList().putMeasurement(className.toString()+" cells/mm^2", cellType/(annotationArea)) | |
} | |
} | |
for (className in list) { | |
cellType = cellList.findAll{p->p.getPathClass() == className}.size() | |
it.getMeasurementList().putMeasurement(className.toString()+" cell %", cellType/(total)*100) | |
} | |
} | |
else { | |
for (className in list) { | |
it.getMeasurementList().putMeasurement(className.toString()+" cell %", 0) | |
} | |
} | |
} | |
import qupath.lib.objects.PathDetectionObject | |
cores.each { | |
roi = it.getROI() | |
coreName = it.getName()+" - Tile" | |
def detection = new PathDetectionObject(roi, getPathClass("Tile")) | |
hierarchy.addPathObject(detection) | |
ml = it.getMeasurementList() | |
for (i=0;i<ml.size(); i++){ | |
//println(ml.getMeasurementValue(i)) | |
//println(detection) | |
detection.getMeasurementList().putMeasurement(ml.getMeasurementName(i), measurement(it, ml.getMeasurementName(i))) | |
} | |
fireHierarchyUpdate() | |
} | |
println("Now it is done.") |
//0.2.0 | |
// https://forum.image.sc/t/qupath-toggle-show-hide-detections-annotations-by-scripting/45916/4 | |
def overlayOptions = getCurrentViewer().getOverlayOptions() | |
overlayOptions.hiddenClassesProperty().addAll( | |
getPathClass('Tumor'), | |
getPathClass('Stroma') | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment