Skip to content

Commit b97efda

Browse files
author
Olivier Burri
authored
Refactor 092024 (#52)
* fixes confusion between per tile and global preprocessing methods * fixes formatting * fixes rounding of downsampling fixes typos, formatting and comment contents * updates logic of handling tiles * updates demo scripts * fixes IntelliJ warnings * bumps version number
1 parent 9d75c28 commit b97efda

9 files changed

+165
-185
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ext.qupathVersion = gradle.ext.qupathVersion
2525

2626
description = 'QuPath extension to use Cellpose'
2727

28-
version = "0.9.6-SNAPSHOT"
28+
version = "0.9.6"
2929

3030
dependencies {
3131
implementation "io.github.qupath:qupath-gui-fx:${qupathVersion}"

src/main/java/qupath/ext/biop/cellpose/Cellpose2D.java

Lines changed: 125 additions & 143 deletions
Large diffs are not rendered by default.

src/main/java/qupath/ext/biop/cellpose/CellposeBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public CellposeBuilder preprocess(ImageOp... ops) {
226226
* @param global preprocessing operation
227227
* @return this builder
228228
*/
229-
public CellposeBuilder preprocess(TileOpCreator global) {
229+
public CellposeBuilder preprocessGlobal(TileOpCreator global) {
230230
this.globalPreprocessing = global;
231231
return this;
232232
}
@@ -761,7 +761,7 @@ public CellposeBuilder normalizePercentilesGlobal(double percentileMin, double p
761761
this.noCellposeNormalization();
762762

763763
// Add this operation to the preprocessing
764-
return this.preprocess(normOp);
764+
return this.preprocessGlobal(normOp);
765765
}
766766

767767
/**
@@ -834,7 +834,7 @@ public Cellpose2D build() {
834834

835835
cellpose.extendChannelOp = extendChannelOp;
836836

837-
837+
// TODO make compatible with --all_channels
838838
if (this.channels.length > 2) {
839839
logger.warn("You supplied {} channels, but Cellpose needs two channels at most. Keeping the first two", channels.length);
840840
this.channels = Arrays.copyOf(this.channels, 2);

src/main/java/qupath/ext/biop/cellpose/CellposeExtension.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ public void installExtension(QuPathGUI qupath) {
6969
StringProperty omniposePath = PathPrefs.createPersistentPreference("omniposePythonPath", "");
7070
StringProperty condaPath = PathPrefs.createPersistentPreference("condaPath", "");
7171

72-
7372
//Set options to current values
7473
options.setCellposePythonPath(cellposePath.get());
7574
options.setOmniposePythonPath(omniposePath.get());

src/main/java/qupath/ext/biop/cellpose/CellposeSetup.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public class CellposeSetup {
88
private static final CellposeSetup instance = new CellposeSetup();
99
private String cellposePythonPath = null;
1010
private String omniposePythonPath = null;
11-
1211
private String condaPath = null;
1312

1413
public static CellposeSetup getInstance() {
@@ -41,7 +40,7 @@ public void setCondaPath(String condaPath) {
4140

4241
private void checkPath(String path) {
4342
// It should be a file and it should exist
44-
if( !path.equals("")) {
43+
if(!path.trim().isEmpty()) {
4544
File toCheck = new File(path);
4645
if (!toCheck.exists())
4746
Dialogs.showWarningNotification("Cellpose/Omnipose extension: Path not found", "The path to \"" + path + "\" does not exist or does not point to a valid file.");

src/main/resources/scripts/Cellpose_detection_template.groovy

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,41 +20,41 @@
2020
// Specify the model name (cyto, nuclei, cyto2, ... or a path to your custom model as a string)
2121
// Other models for Cellpose https://cellpose.readthedocs.io/en/latest/models.html
2222
// And for Omnipose: https://omnipose.readthedocs.io/models.html
23-
def pathModel = 'cyto2'
23+
def pathModel = 'cyto3'
2424
def cellpose = Cellpose2D.builder( pathModel )
2525
.pixelSize( 0.5 ) // Resolution for detection in um
2626
.channels( 'DAPI' ) // Select detection channel(s)
2727
// .tempDirectory( new File( '/tmp' ) ) // Temporary directory to export images to. defaults to 'cellpose-temp' inside the QuPath Project
28-
// .preprocess( ImageOps.Filters.median(1) ) // List of preprocessing ImageOps to run on the images before exporting them
29-
// .normalizePercentilesGlobal(0.1, 99.8, 10) // Convenience global percentile normalization. arguments are percentileMin, percentileMax, dowsample.
30-
// .tileSize(1024) // If your GPU can take it, make larger tiles to process fewer of them. Useful for Omnipose
31-
// .cellposeChannels(1,2) // Overwrites the logic of this plugin with these two values. These will be sent directly to --chan and --chan2
32-
// .cellprobThreshold(0.0) // Threshold for the mask detection, defaults to 0.0
33-
// .flowThreshold(0.4) // Threshold for the flows, defaults to 0.4
34-
// .diameter(15) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
28+
// .preprocess( ImageOps.Filters.median( 1 ) ) // List of preprocessing ImageOps to run on the images before exporting them
29+
// .normalizePercentilesGlobal( 0.1, 99.8, 10 ) // Convenience global percentile normalization. arguments are percentileMin, percentileMax, dowsample.
30+
// .tileSize( 1024 ) // If your GPU can take it, make larger tiles to process fewer of them. Useful for Omnipose
31+
// .cellposeChannels( 1,2 ) // Overwrites the logic of this plugin with these two values. These will be sent directly to --chan and --chan2
32+
// .cellprobThreshold( 0.0 ) // Threshold for the mask detection, defaults to 0.0
33+
// .flowThreshold( 0.4 ) // Threshold for the flows, defaults to 0.4
34+
// .diameter( 15 ) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
3535
// .useOmnipose() // Use omnipose instead
36-
// .addParameter("cluster") // Any parameter from cellpose or omnipose not available in the builder.
37-
// .addParameter("save_flows") // Any parameter from cellpose or omnipose not available in the builder.
38-
// .addParameter("anisotropy", "3") // Any parameter from cellpose or omnipose not available in the builder.
39-
// .cellExpansion(5.0) // Approximate cells based upon nucleus expansion
40-
// .cellConstrainScale(1.5) // Constrain cell expansion using nucleus size
41-
// .classify("My Detections") // PathClass to give newly created objects
36+
// .addParameter( "cluster" ) // Any parameter from cellpose or omnipose not available in the builder.
37+
// .addParameter( "save_flows" ) // Any parameter from cellpose or omnipose not available in the builder.
38+
// .addParameter( "anisotropy", "3" ) // Any parameter from cellpose or omnipose not available in the builder.
39+
// .cellExpansion( 5.0 ) // Approximate cells based upon nucleus expansion
40+
// .cellConstrainScale( 1.5 ) // Constrain cell expansion using nucleus size
41+
// .classify( "My Detections" ) // PathClass to give newly created objects
4242
// .measureShape() // Add shape measurements
4343
// .measureIntensity() // Add cell measurements (in all compartments)
4444
// .createAnnotations() // Make annotations instead of detections. This ignores cellExpansion
45-
// .simplify(0) // Simplification 1.6 by default, set to 0 to get the cellpose masks as precisely as possible
45+
// .simplify( 0 ) // Simplification 1.6 by default, set to 0 to get the cellpose masks as precisely as possible
4646
.build()
4747

4848
// Run detection for the selected objects
4949
def imageData = getCurrentImageData()
5050
def pathObjects = getSelectedObjects() // To process only selected annotations, useful while testing
5151
// def pathObjects = getAnnotationObjects() // To process all annotations. For working in batch mode
5252
if (pathObjects.isEmpty()) {
53-
Dialogs.showErrorMessage("Cellpose", "Please select a parent object!")
53+
Dialogs.showErrorMessage( "Cellpose", "Please select a parent object!" )
5454
return
5555
}
5656

57-
cellpose.detectObjects(imageData, pathObjects)
57+
cellpose.detectObjects( imageData, pathObjects )
5858

5959
// You could do some post-processing here, e.g. to remove objects that are too small, but it is usually better to
6060
// do this in a separate script so you can see the results before deleting anything.

src/main/resources/scripts/Cellpose_training_template.groovy

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@
1717
*/
1818

1919
// First we need to create a Cellpose2D builder and add all parameters that we want to use for training
20-
def cellpose = Cellpose2D.builder("cyto") // Can choose "None" if you want to train from scratch
21-
.channels("DAPI", "CY3") // or work with .cellposeChannels( channel1, channel2 ) and follow the cellpose way
22-
// .preprocess(ImageOps.Filters.gaussianBlur(1)) // Optional preprocessing QuPath Ops
23-
// .epochs(500) // Optional: will default to 500
24-
// .groundTruthDirectory( new File("/my/ground/truth/folder")) // Optional: If you wish to save your GT elsewhere than the QuPath Project
25-
// .learningRate(0.2) // Optional: Will default to 0.2
26-
// .batchSize(8) // Optional: Will default to 8
27-
// .minTrainMasks(5) // Optional: Will default to 5
28-
// .addParameter("save_flows") // Any parameter from cellpose not available in the builder. See https://cellpose.readthedocs.io/en/latest/command.html
29-
// .addParameter("anisotropy", "3") // Any parameter from cellpose not available in the builder. See https://cellpose.readthedocs.io/en/latest/command.html
30-
// .modelDirectory( new File("My/folder/for/models")) // Optional place to store resulting model. Will default to QuPath project root, and make a 'models' folder
31-
// .saveBuilder("My Builder") // Optional: Will save a builder json file that can be reloaded with Cellpose2D.builder(File builderFile)
20+
def cellpose = Cellpose2D.builder( "cyto3" ) // Can choose "None" if you want to train from scratch
21+
.channels( "DAPI", "CY3" ) // or work with .cellposeChannels( channel1, channel2 ) and follow the cellpose way
22+
// .preprocess( ImageOps.Filters.gaussianBlur( 1 ) ) // Optional preprocessing QuPath Ops
23+
// .epochs(500) // Optional: will default to 500
24+
// .groundTruthDirectory( new File( "/my/ground/truth/folder" ) ) // Optional: If you wish to save your GT elsewhere than the QuPath Project
25+
// .learningRate(0.2) // Optional: Will default to 0.2
26+
// .batchSize(8) // Optional: Will default to 8
27+
// .minTrainMasks(5) // Optional: Will default to 5
28+
// .addParameter("save_flows") // Any parameter from cellpose not available in the builder. See https://cellpose.readthedocs.io/en/latest/command.html
29+
// .addParameter("anisotropy", "3") // Any parameter from cellpose not available in the builder. See https://cellpose.readthedocs.io/en/latest/command.html
30+
// .modelDirectory( new File("D:/models/" ) ) // Optional place to store resulting model. Will default to QuPath project root, and make a 'models' folder
31+
// .saveBuilder("My Builder") // Optional: Will save a builder json file that can be reloaded with Cellpose2D.builder(File builderFile)
3232
.build()
3333

3434
// Now we can train a new model

src/main/resources/scripts/Create_Cellpose_training_and_validation_images.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import qupath.ext.biop.cellpose.Cellpose2D
2121

2222
// Build a Cellpose instance for saving the image pairs
2323
def cellpose = Cellpose2D.builder( "None" ) // No effect, as this script only exports the images
24-
// .channels( "DAPI", "CY3" ) // Optional: Image channels to export
24+
// .channels( "DAPI", "CY3" ) // Optional: Image channels to export
2525
// .preprocess( ImageOps.Filters.gaussianBlur( 1 ) ) // Optional: preprocessing QuPath Ops
2626
.build()
2727

src/main/resources/scripts/Detect_nuclei_and_cells_using_Cellpose.groovy

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ if (pathObjects.isEmpty()) {
1919
clearDetections()
2020

2121
// Create a Cellpose detectors for cyto and nuclei
22-
def pathModel_cyto = 'cyto2'
22+
def pathModel_cyto = 'cyto3'
2323
def cellpose_cyto = Cellpose2D.builder( pathModel_cyto )
24-
.channels("HCS","DAPI")
24+
.channels( "HCS","DAPI" )
2525
.pixelSize( 0.3 ) // Resolution for detection
26-
.diameter(30) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
26+
.diameter(30 ) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
2727
.measureShape() // Add shape measurements
2828
.measureIntensity() // Add cell measurements (in all compartments)
2929
.build()
3030

31-
def pathModel_nuc = 'cyto2'
31+
def pathModel_nuc = 'cyto3'
3232
def cellpose_nuc = Cellpose2D.builder( pathModel_nuc )
33-
.channels("DAPI")
33+
.channels("DAPI" )
3434
.pixelSize( 0.3 ) // Resolution for detection
3535
.diameter(10) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
3636
.build()

0 commit comments

Comments
 (0)