= Description =
This extension, with source located at rQPEBIOP is the current 'fourre-tout' for all the new features we are currently implementing for QuPath to make our users' lives simpler.
== Requirements ==
Because some features (Like saving display settigns) were not programmer-accessible (`private`), we had to modify QuPath's code. Which is why most features are only available if you are running *QuPath v0.1.4**.
== Installation ==
Once you have QuPath installed, you can copy the `BIOPTools` jar file from
`\\svfas6.epfl.ch\biop\public\0 - BIOP Data\0-Install\QuPath\QuPath\Extensions`
`smb://svfas6.epfl.ch/biop/public/0 - BIOP Data/0-Install/QuPath/QuPath/Extensions`
= Contents ==
== Commands ==
The Extension includes the following commands
=== {nav BIOP > Display Settings... > Save current display settings to file... } ===
Asks the user for a location and a file name to save the current display settings (Brightness & Contast, active channels, channel colors) of the currently opened image) as a JSON file, which can be reused by the command below
=== {nav BIOP > Display Settings... > Load display settings from file... } ===
Asks the user a JSON file created with the command above. This sets the display settings of the current image ot those defined in the file.
=== {nav BIOP > Display Settings... >Apply display settings to similar images in projects} ===
Will apply the currently active Brightness & Contast, active channels and channel colors to all images to of the project as long as
# they share the same number of channels
# they have the same image type (Fluorescence, probably)
== Utils ==
Utils class contains utilities that are not linked to the user interface
=== sendResultsToFile(ArrayList<String> resultColumns, ArrayList<PathObject> objects, File resultsFile) ===
Sends the selected results from the selected objects to the selected file. The cool thing is that as long as you list all the results with the same column names as the ones in the GUI's Measurements, it will be available for export.
```lang=java
import ch.epfl.biop.qupath.utils.Utils
// Settings to establish, the name of the folder and the name of the results file
def results_folder_name = 'results'
def results_file_name = 'results.txt'
// Get the micrometers name
def um = Utils.um
// Choose the measurements you want to export
// sendResultsToFile will automatically append the image and subimage names as the first columns
def measurements = [ "Name", "Class", "Parent", "Area "+um+"^2"]
// Choose the objects for whom you want to have measurements
def objects = getAnnotationObjects()
// --------------------- Magic happens below --------------------- //
// Build the results directory
def res_directory = buildFilePath( PROJECT_BASE_DIR, results_folder_name )
// Build the results file
def res_file = new File( res_directory, results_file_name )
// Make sure the folder exists
mkdirs( res_directory )
// The method below creates a results table
// THE TABLE IS CREATED ONCE and THEN APPENDED
Utils.sendResultsToFile( measurements, objects, res_file )
```
=== getAllMeasurements() ===
Returns all the measurements available in QuPath for the all pathObjects Then we can use things like getStringValue() and getDoubleValue() and get ANY measurement as it is written in the Measurements GUI
```lang=java
import ch.epfl.biop.qupath.utils.Utils
def um = Utils.um;
def m = Utils.getAllMeasurements()
def object = getSelectedObject()
println( m.getNumericValue( object, 'Perimeter '+um ) )
```
=== getAllMeasurements(java.util.List<qupath.lib.objects.PathObject> pathObjects) ===
Creates an ObservableMeasurementTableData for the requested PathObjects, which might be a bit faster as it does not need to compute the measurements for all the objects, but just for the ones we need.
== GUI Utilities ===
These utilities deal with how we can interact with QuPath's GUI, mostly dealing with Image Display
=== applyDisplaySettingsToProject() ===
Will apply the current display settings (Visible Channels, Histogram Min-Max, Channel Colors) to all images in the project with **the same image type and number of channels**
lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
GUIUtils.applyDisplaySettingsToProject()
=== getChannelMinMax(int channel) ===
Returns a list of Integers with the min and max display values for the current channel (one-based)
lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def channel = 3
def min_max = GUIUtils.getChannelMinMax( channel )
println( sprintf( "Max is %d for channel %d", min_max[1], channel ) )
=== getChannelMinMax(java.lang.String channel) ===
Returns a list with the minimum and maximum display values for the given channel defined by its name
lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
// Image is RGB H&E
def channel = "Optical density sum"
def min_max = GUIUtils.getChannelMinMax( channel )
println( sprintf( "Max is %d for channel %s", min_max[1], channel ) )
=== getImagePlus(qupath.lib.objects.PathObject pathObject, int downsample, boolean sendPathObjectAsRoi, boolean sendChildObjectsInOverlay) ===
Returns an ImagePlus object with or without a ROI and with or without an overlay (if there are child objects)
lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def object = getSelectedObject()
def downsample = 4
def sendObject = false
def sendChildObjects = false
def imp = GUIUtils.getImagePlus( object, downsample, sendObject, sendChildObjects )
imp.show()
=== loadDisplaySettings(java.io.File fileToLoad) ===
Loads the display settings (Brightness, contrast, LUT, Min-Max) from a json serialized file created with **saveDisplaySettings()**
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def settingsDir = buildFilePath( PROJECT_BASE_DIR, "settings" )
mkdirs(settingsDir)
def loadFile = new File( settingsDir, 'CustomSettings.json')
GUIUtils.loadDisplaySettings( loadFile )
```
=== saveDisplaySettings(java.io.File fileToSave) ===
Saves the current display settings (Brightness, contrast, LUT, Min-Max) to a json serialized file that can be used with with **loadDisplaySettings()**
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def settingsDir = buildFilePath( PROJECT_BASE_DIR, "settings" )
mkdirs(settingsDir)
def saveFile = new File( settingsDir, 'CustomSettings.json')
GUIUtils.loadDisplaySettings( saveFile )
```
=== setActiveChannels(java.util.ArrayList<java.lang.Integer> theChannels) ===
Sets the channels in the list to active and deactivates the ones not in it
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def activeChannels = [1,3]
GUIUtils.setActiveChannels( activeChannels )
```
IMPORTANT: This command does not update the "Brightness and Contrast" window, which no longer reflects the current state until you change something
=== setActiveChannelsByName(java.util.ArrayList<java.lang.String> channelNames) ===
Sets the channels in the list to active and deactivated the ones not in it
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
def activeChannels = ["Channel 1","Channel 3"]
GUIUtils.setActiveChannelsByName( activeChannels )
```
NOTE: The name of the method is different because Java does not know how to differentiate `ArrayList<String>` from `ArrayList<Integer>`
=== setChannelColor(int channel, javafx.scene.paint.Color color) ===
Sets the color of the selected channel. See [[https://docs.oracle.com/javafx/2/api/javafx/scene/paint/Color.html | JavaFX's Color Class]]
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
import javafx.scene.paint.Color;
def c1Color = Color.YELLOW
def c2Color = Color.rgb(255,128,128)
def c3Color = Color.web("0055FF")
GUIUtils.setChannelColor( 1, c1Color )
GUIUtils.setChannelColor( 2, c2Color )
GUIUtils.setChannelColor( 3, c3Color )
```
IMPORTANT: This command does not update the "Brightness and Contrast" window, which no longer reflects the current state until you change something
=== setChannelColor(java.lang.String channelName, javafx.scene.paint.Color color) ===
Same as above, but the channel can be selected with a String
=== setChannelMinMax(int channelID, int min, int max) ===
Sets the minimum and maximum display range for a channel, defined by its index (1 based)
```lang=java
import ch.epfl.biop.qupath.utils.GUIUtils
GUIUtils.setChannelMinMax(1, 0, 5000)
```
=== setChannelMinMax(java.lang.String channelName, int min, int max) ===
Sets the minimum and maximum display range for a channel, defined by its name
== PathObject Utilities ==
These methods are for helping us manipulate pathObjects as needed
=== LineToArea(qupath.lib.roi.interfaces.ROI line, double thickness) ===
Converts a line to a very thin 4 sided polygon, so it has an area. returns a ROI which can be placed into a PathObject
```lang=java
import ch.epfl.biop.qupath.utils.PathUtils
import qupath.lib.objects.PathAnnotationObject;
object = getSelectedObject()
def area = PathUtils.LineToArea( object.getROI(), 100.0 )
def areaObject = new PathAnnotationObject( area )
getCurrentHierarchy().addPathObject( areaObject, true, true )
```
=== splitObject(qupath.lib.objects.PathObject pathObject, qupath.lib.objects.PathObject splitter) ===
Splits the defined pathobject using the provided splitter. The return value is a List of PathObjects, as the split might have generated more than one separate object
This is useful when trying to split an object with a line to cut it in half, for example.
```lang=java
import ch.epfl.biop.qupath.utils.PathUtils
import qupath.lib.objects.PathAnnotationObject;
// First create a polygon object, then make a line that goes through it
def objects = getAnnotationObjects()
def resultingObjects = PathUtils.splitObject( objects[0], objects[1] )
resultingObjects.each{ it.setPathClass( getPathClass( "Split" ) ) }
getCurrentHierarchy().addPathObjects( resultingObjects, true )
```
== ScriptableMacroRunner ==
This class wraps the ImageJ Macro runner into a more user friendly class to use with scripts
```lang=java
import ch.epfl.biop.qupath.utils.ScriptableMacroRunner
// Call the scriptable macro runner
def mr = new ScriptableMacroRunner()
// Most important MacroRunner Command
// You can set the macro text directly here
mr.setMacroText("makeOval(200,200,100,100);");
// Easiest way is to send it text from an .ijm file
def macroFile = new File("SomePath/someMacro.ijm")
mr.setMacroText(macroFile.text)
// Optional, define the region to send
def region = getSelectedObject()
// All settings below are OPTIONAL
mr.setDownsample(10) // Otherwise will set downsample to 1
mr.setPathObject(region) // Sets the region that will be sent to ImageJ, if unset, will work on whole region
mr.setSendROI(false) // Sends the pathObject to ImageJ as a ROI
mr.setSendOverlay(false) // Sends the childern of the pathObject to ImageJ as Overlay
mr.setClearObjects(false) // Clears the current child objects of the pathobject being sent
mr.setGetROI(false) // Get ImageJ Current ROI As annotation
mr.setGetOverlay(false) // Get ImageJ Overlay back to QuPath
mr.setGetOverlayAs("Annotations") // or "Detections
// Runs the whole thing and returns what we want
mr.run()
// After this, the results should be in QuPath= Shortcuts and easier ways to access common QuPath functions in scripts =
Using rQPEBIOP
== Utils Class ==
This class contains general things useful in QuPath
=== Get Pixel Size ===
```lang=java
import ch.epfl.biop.qupath.utils.*
def px_size = Utils.getPixelSize()
```
=== Send Results to a File ===
```lang=java
import ch.epfl.biop.qupath.utils.*
// Define the measurements you want to send over
def results = [ "Nucleus: Area", "Nucleus: DAB OD mean", "Parent", "Class", "Name" ]
// Define the object you want to send
def cells = getCellObjects()
// Define the file and directory where you want to save the results
def resDir = buildFilePath(PROJECT_BASE_DIR, 'results')
mkdirs( resDir )
def resFile = new File( resDir, 'average_distances.csv' )
// Finally send the results. This method will append the image name as the first column
Utils.sendResultsToFile( measurements, cells, resFile )
// If you just want the results to end in `PROJECT_BASE_DIR/results/results.txt` you can use
Utils.sendResultsToFile( measurements, cells )
// If you want to send all results to `PROJECT_BASE_DIR/results/results.txt` you can use
Utils.sendResultsToFile( cells )
```
== Get the full measurements table ==
```lang=java
// Choose the objects for which you want the measurements
def path_objects = getAllObjects()
// Get the Measurements
def measurements = Utils.getAllMeasurements( path_objects )
// Access any measurement that appears in the 'Show annotation measurements' or 'Show detection measurements'
def area = measurements.getNumericValue( one_object, "Area µm2")
// This works with Area, Num Detections, etc
```
== PathUtils Class ==
This class has to do with operations on PathObjects
=== Get Area of a ROI ===
```lang=java
import ch.epfl.biop.qupath.utils.*
def object = getSelectedObject()
PathUtils.getAreaMicrons( object )
PathUtils.getArea( object )
```
== GUIUtils Class ==
=== Get an ImagePlus ===
```lang=java
import ch.epfl.biop.qupath.utils.*
def object = getSelectedObject()
// Get full ImagePlus
def imp = GUIUtils.getImagePlus( object, downsample, sendPathObjectAsRoi, sendChildObjectsInOverlay )
// Get a specific channel or series of channels
def channels = ["Channel 1, "Channel 3"] // Same names as in the 'Adjust Brightness And Contrast' menu
def imp = GUIUtils.getImagePlus( object, downsample, sendPathObjectAsRoi, sendChildObjectsInOverlay, channels )
// For Brightfield, you can only get one channel at a time
def imp_dab = GUIUtils.getImagePlus( object, downsample, sendPathObjectAsRoi, sendChildObjectsInOverlay, ["DAB"] ) // note the [ ], if you give it more channels it only returns the first one
```
=== Get/ Set Min And Max for Channels ===
```lang=java
import ch.epfl.biop.qupath.utils.*
// Channel number is 1-based
def channel = 1
def minmax = GUIUtils.getChannelMinMax( channel ) // min is in minmax[0] and max in minmax[1]
// By channel name
def channel_name = "DAB"
def minmax = GUIUtils.getChannelMinMax( channel_name )
GUIUtils.setChannelMinMax(1, 10.0, 3000.0 )
// or
GUIUtils.setChannelMinMax("DAB", 0.0, 1.0 )
```
=== Set Channel Visibility ==
```lang=java
import ch.epfl.biop.qupath.utils.*
GUIUtils.setActiveChannels( [1,3,4] )
// or
GUIUtils.setActiveChannelsbyName( ["Channel 1, "Channel 3, "Channel 4"] )
```
=== Set Channel Color ===
Use the JavaFX `Color` Class, see https://docs.oracle.com/javase/8/javafx/api/javafx/scene/paint/Color.html
```lang=java
import ch.epfl.biop.qupath.utils.*
import javafx.scene.paint.Color
def color = new Color.rgb(0,0,255,1.0) // red green blue and alpha (opacity, 1.0 means not transparent)
GUIUtils.setChannelColor( 1, color )
// or
GUIUtils.setChannelColor( "DAB", color )
```
=== Save and Load Display Settings ===
```lang=java
import ch.epfl.biop.qupath.utils.*
def save_here = new File( "D:/Display/my_display.txt" )
GUIUTils.saveDisplaySettings( save_here )
// Load
GUIUTils.loadDisplaySettings( save_here )
// Apply current settings to project
GUIUtils.applyDisplaySettingsToProject()
```