Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor 092024 #52

Merged
merged 7 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ ext.qupathVersion = gradle.ext.qupathVersion

description = 'QuPath extension to use Cellpose'

version = "0.9.6-SNAPSHOT"
version = "0.9.6"

dependencies {
implementation "io.github.qupath:qupath-gui-fx:${qupathVersion}"
Expand Down
268 changes: 125 additions & 143 deletions src/main/java/qupath/ext/biop/cellpose/Cellpose2D.java

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/main/java/qupath/ext/biop/cellpose/CellposeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public CellposeBuilder preprocess(ImageOp... ops) {
* @param global preprocessing operation
* @return this builder
*/
public CellposeBuilder preprocess(TileOpCreator global) {
public CellposeBuilder preprocessGlobal(TileOpCreator global) {
this.globalPreprocessing = global;
return this;
}
Expand Down Expand Up @@ -761,7 +761,7 @@ public CellposeBuilder normalizePercentilesGlobal(double percentileMin, double p
this.noCellposeNormalization();

// Add this operation to the preprocessing
return this.preprocess(normOp);
return this.preprocessGlobal(normOp);
}

/**
Expand Down Expand Up @@ -834,7 +834,7 @@ public Cellpose2D build() {

cellpose.extendChannelOp = extendChannelOp;


// TODO make compatible with --all_channels
if (this.channels.length > 2) {
logger.warn("You supplied {} channels, but Cellpose needs two channels at most. Keeping the first two", channels.length);
this.channels = Arrays.copyOf(this.channels, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public void installExtension(QuPathGUI qupath) {
StringProperty omniposePath = PathPrefs.createPersistentPreference("omniposePythonPath", "");
StringProperty condaPath = PathPrefs.createPersistentPreference("condaPath", "");


//Set options to current values
options.setCellposePythonPath(cellposePath.get());
options.setOmniposePythonPath(omniposePath.get());
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/qupath/ext/biop/cellpose/CellposeSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public class CellposeSetup {
private static final CellposeSetup instance = new CellposeSetup();
private String cellposePythonPath = null;
private String omniposePythonPath = null;

private String condaPath = null;

public static CellposeSetup getInstance() {
Expand Down Expand Up @@ -41,7 +40,7 @@ public void setCondaPath(String condaPath) {

private void checkPath(String path) {
// It should be a file and it should exist
if( !path.equals("")) {
if(!path.trim().isEmpty()) {
File toCheck = new File(path);
if (!toCheck.exists())
Dialogs.showWarningNotification("Cellpose/Omnipose extension: Path not found", "The path to \"" + path + "\" does not exist or does not point to a valid file.");
Expand Down
34 changes: 17 additions & 17 deletions src/main/resources/scripts/Cellpose_detection_template.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,41 @@
// Specify the model name (cyto, nuclei, cyto2, ... or a path to your custom model as a string)
// Other models for Cellpose https://cellpose.readthedocs.io/en/latest/models.html
// And for Omnipose: https://omnipose.readthedocs.io/models.html
def pathModel = 'cyto2'
def pathModel = 'cyto3'
def cellpose = Cellpose2D.builder( pathModel )
.pixelSize( 0.5 ) // Resolution for detection in um
.channels( 'DAPI' ) // Select detection channel(s)
// .tempDirectory( new File( '/tmp' ) ) // Temporary directory to export images to. defaults to 'cellpose-temp' inside the QuPath Project
// .preprocess( ImageOps.Filters.median(1) ) // List of preprocessing ImageOps to run on the images before exporting them
// .normalizePercentilesGlobal(0.1, 99.8, 10) // Convenience global percentile normalization. arguments are percentileMin, percentileMax, dowsample.
// .tileSize(1024) // If your GPU can take it, make larger tiles to process fewer of them. Useful for Omnipose
// .cellposeChannels(1,2) // Overwrites the logic of this plugin with these two values. These will be sent directly to --chan and --chan2
// .cellprobThreshold(0.0) // Threshold for the mask detection, defaults to 0.0
// .flowThreshold(0.4) // Threshold for the flows, defaults to 0.4
// .diameter(15) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
// .preprocess( ImageOps.Filters.median( 1 ) ) // List of preprocessing ImageOps to run on the images before exporting them
// .normalizePercentilesGlobal( 0.1, 99.8, 10 ) // Convenience global percentile normalization. arguments are percentileMin, percentileMax, dowsample.
// .tileSize( 1024 ) // If your GPU can take it, make larger tiles to process fewer of them. Useful for Omnipose
// .cellposeChannels( 1,2 ) // Overwrites the logic of this plugin with these two values. These will be sent directly to --chan and --chan2
// .cellprobThreshold( 0.0 ) // Threshold for the mask detection, defaults to 0.0
// .flowThreshold( 0.4 ) // Threshold for the flows, defaults to 0.4
// .diameter( 15 ) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
// .useOmnipose() // Use omnipose instead
// .addParameter("cluster") // Any parameter from cellpose or omnipose not available in the builder.
// .addParameter("save_flows") // Any parameter from cellpose or omnipose not available in the builder.
// .addParameter("anisotropy", "3") // Any parameter from cellpose or omnipose not available in the builder.
// .cellExpansion(5.0) // Approximate cells based upon nucleus expansion
// .cellConstrainScale(1.5) // Constrain cell expansion using nucleus size
// .classify("My Detections") // PathClass to give newly created objects
// .addParameter( "cluster" ) // Any parameter from cellpose or omnipose not available in the builder.
// .addParameter( "save_flows" ) // Any parameter from cellpose or omnipose not available in the builder.
// .addParameter( "anisotropy", "3" ) // Any parameter from cellpose or omnipose not available in the builder.
// .cellExpansion( 5.0 ) // Approximate cells based upon nucleus expansion
// .cellConstrainScale( 1.5 ) // Constrain cell expansion using nucleus size
// .classify( "My Detections" ) // PathClass to give newly created objects
// .measureShape() // Add shape measurements
// .measureIntensity() // Add cell measurements (in all compartments)
// .createAnnotations() // Make annotations instead of detections. This ignores cellExpansion
// .simplify(0) // Simplification 1.6 by default, set to 0 to get the cellpose masks as precisely as possible
// .simplify( 0 ) // Simplification 1.6 by default, set to 0 to get the cellpose masks as precisely as possible
.build()

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

cellpose.detectObjects(imageData, pathObjects)
cellpose.detectObjects( imageData, pathObjects )

// You could do some post-processing here, e.g. to remove objects that are too small, but it is usually better to
// do this in a separate script so you can see the results before deleting anything.
Expand Down
24 changes: 12 additions & 12 deletions src/main/resources/scripts/Cellpose_training_template.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@
*/

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

// Now we can train a new model
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import qupath.ext.biop.cellpose.Cellpose2D

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ if (pathObjects.isEmpty()) {
clearDetections()

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

def pathModel_nuc = 'cyto2'
def pathModel_nuc = 'cyto3'
def cellpose_nuc = Cellpose2D.builder( pathModel_nuc )
.channels("DAPI")
.channels("DAPI" )
.pixelSize( 0.3 ) // Resolution for detection
.diameter(10) // Median object diameter. Set to 0.0 for the `bact_omni` model or for automatic computation
.build()
Expand Down
Loading