Skip to content

Commit

Permalink
Merge pull request #1080 from drieslab/suite_dev
Browse files Browse the repository at this point in the history
v4.1.6
  • Loading branch information
jiajic authored Dec 9, 2024
2 parents 3b309ac + 8ad8609 commit f3a78f6
Show file tree
Hide file tree
Showing 17 changed files with 808 additions and 72 deletions.
8 changes: 4 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: Giotto
Title: Spatial Single-Cell Transcriptomics Toolbox
Version: 4.1.5
Version: 4.1.6
Authors@R: c(
person("Ruben", "Dries", email = "[email protected]",
role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7650-7754")),
Expand Down Expand Up @@ -28,7 +28,7 @@ RoxygenNote: 7.3.2
Depends:
R (>= 4.4.1),
methods,
GiottoClass (>= 0.4.1)
GiottoClass (>= 0.4.5)
Imports:
BiocParallel,
BiocSingular,
Expand All @@ -37,8 +37,8 @@ Imports:
dbscan (>= 1.1-3),
ggraph,
ggplot2 (>= 3.1.1),
GiottoUtils (>= 0.2.0),
GiottoVisuals (>= 0.2.6),
GiottoUtils (>= 0.2.2),
GiottoVisuals (>= 0.2.10),
igraph (>= 1.2.4.1),
Matrix (>= 1.6-2),
MatrixGenerics,
Expand Down
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,12 @@ export(doLeidenClusterIgraph)
export(doLeidenSubCluster)
export(doLouvainCluster)
export(doLouvainSubCluster)
export(doMesmerSegmentation)
export(doRandomWalkCluster)
export(doSNNCluster)
export(doScrubletDetect)
export(doStardistSegmentation)
export(dotPlot)
export(estimateAutomatedImageRegistrationWithSIFT)
export(estimateImageBg)
export(exportGiottoViewer)
Expand Down Expand Up @@ -751,6 +754,7 @@ importFrom(GiottoVisuals,dimGenePlot3D)
importFrom(GiottoVisuals,dimPlot)
importFrom(GiottoVisuals,dimPlot2D)
importFrom(GiottoVisuals,dimPlot3D)
importFrom(GiottoVisuals,dotPlot)
importFrom(GiottoVisuals,getColors)
importFrom(GiottoVisuals,giottoSankeyPlan)
importFrom(GiottoVisuals,plotHeatmap)
Expand Down
21 changes: 21 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@

# Giotto 4.1.6 (2024/12/09)

## Bug fixes
* `doScrubletDetect()` seed setting

## Enhancements
* `labelTransfer()` now has `integration_method = "harmony"` for label transferring with an integration pipeline. See ?labelTransfer and the `integration_method` section.
* `importXenium()` `load_transcripts()` can now return a `data.table` rather than the `giottoPoints` representation

## New
* `doMesmerSegmentation()` and `doStardistSegmentation()` segmentation wrappers
* `.varexp()` internal for calculating SVD variance determined with support for partial SVDs
* `.cumvar()` internal for calculating cumulative variance explained
* re-export of `dotPlot()` from GiottoVisuals

## Changes
* GiottoClass req raised to 0.4.5
* GiottoUtils req raised to 0.2.2
* GiottoVisuals req raised to 0.2.10


# Giotto 4.1.5 (2024/11/08)

## Enhancements
Expand Down
185 changes: 185 additions & 0 deletions R/cell_segmentation.R
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,188 @@ doCellposeSegmentation <- function(
rast <- terra::rast(masks)
terra::writeRaster(rast, mask_output, overwrite = TRUE)
}




#'
#' @title perform Mesmer(Deepcell) segmentation
#' @description
#'
#' perform the Giotto Wrapper of mesmer segmentation. This is for a model
#' inference to generate segmentation mask file from input image.
#' main parameters needed
#' @name doMesmerSegmentation
#' @param Image_dir character, required. Provide a path to a IF image.
#' @param python_env python environment with deepcell installed.
#' default = "giotto_segmentation". See deepcell official website for more details.
#' @param mask_output required. Provide a path to the output mask file.
#' @param Nucleus_channel channel number for Nuclei, default to 1
#' @param Memberane_channel channel number for cell boundary, default to 2
#' @param pixel_per_micron physical micron size per pixel, default to 0.25
#' @returns No return variable, as this will write directly to output path
#' provided.
#' @examples
#' # example code
#' doMesmerSegmentation(
#' Image_dir = input_image,
#' mask_output = output,
#' Nucleus_channel = 1,
#' Memberane_channel = 2,
#' pixel_per_micron = 0.5
#' )
#' @export
doMesmerSegmentation <- function(Image_dir,
python_env = 'giotto_segmentation',
Nucleus_channel = 1,
Memberane_channel = 2,
pixel_per_micron = 0.25,
mask_output,
verbose = F, ...){
## Load required python libraries
GiottoClass::set_giotto_python_path(python_env)
GiottoUtils::package_check("deepcell", repository = "pip")
tiff <- reticulate::import("tifffile")
np <- reticulate::import("numpy")
deepcell <- reticulate::import("deepcell.applications")
message("successfully loaded giotto environment with deepcell.")

# Initialize the Mesmer application from DeepCell
mesmer <- deepcell$Mesmer()

GiottoUtils::vmsg(
.v = verbose, .is_debug = FALSE, "Loading Image... ",
)
GiottoUtils::package_check("terra")
rast = terra::rast(Image_dir)
# Convert the R matrix to a NumPy array explicitly
Nucleus_channel_np <- np$array(drop(terra::as.array(rast[[as.numeric(Nucleus_channel)]])))
Membrane_channel_np <- np$array(drop(terra::as.array(rast[[as.numeric(Memberane_channel)]])))
stacked_array <- np$stack(list(Nucleus_channel_np, Membrane_channel_np), axis = as.integer(-1))
# Add a new axis to the stacked array to fit Mesmer input
stacked_array <- np$expand_dims(stacked_array, axis = as.integer(0))

GiottoUtils::vmsg(.v = verbose, .is_debug = FALSE, "Segmenting Image...")

segmentation_predictions = mesmer$predict(stacked_array, image_mpp=pixel_per_micron)
mask <- segmentation_predictions[1,,,1]
mask_r <- reticulate::py_to_r(mask)

GiottoUtils::vmsg(
.v = verbose, .is_debug = FALSE,
"Segmentation finished... Saving mask file..."
)

rast <- terra::rast(mask_r)
terra::writeRaster(rast, mask_output, overwrite = TRUE)
}



#'
#' @title perform Stardist segmentation
#' @description
#'
#' perform the Giotto Wrapper of Stardist 2D segmentation. This is for a model
#' inference to generate segmentation mask file from input image.
#' main parameters needed
#' @name doStardistSegmentation
#' @param Image_dir character, required. Provide a path to an image.
#' @param python_env python environment with Stardist installed.
#' default = "giotto_segmentation". See Stardist official website for more details.
#' @param mask_output required. Provide a path to the output mask file.
#' @param model_name Name of the model to run inference. Default to '2D_versatile_fluo'.
#' If using HE model, input image must be RGB, else the nuclei_channel must be given
#' @param nuclei_channel Required using IF based nuclei segmentation, channel number of the nuclei staining.
#' @param prob_thresh prob_thresh for model (if not given use model default)
#' @param nms_thresh nms_thresh for model (if not given use model default)
#' @returns No return variable, as this will write directly to output path provided.
#' @examples
#' # example code
#' doStardistSegmentation(
#' Image_dir = input_image,
#' mask_output = output,
#' model_name = '2D_versatile_fluo',
#' nuclei_channel = 3
#' )
#'
#' @export
doStardistSegmentation <- function(Image_dir,
python_env = 'giotto_segmentation',
mask_output,
model_name = '2D_versatile_fluo',
nuclei_channel = NULL,
prob_thresh = NULL,
nms_thresh = NULL,
verbose = F,
...){
# Import the necessary Python modules
## Load required python libraries
GiottoClass::set_giotto_python_path(python_env)
GiottoUtils::package_check("stardist", repository = "pip")
stardist <- reticulate::import("stardist.models")
csbdeep <- reticulate::import("csbdeep.utils")
np <- reticulate::import("numpy")

# Load the StarDist2D model
model_name <- match.arg(
model_name, unique(c("2D_versatile_fluo", "2D_versatile_he", "2D_paper_dsb2018", "2D_demo", model_name))
)
GiottoUtils::vmsg(
.v = verbose, .is_debug = FALSE, "Loading model ",
model_name
)

model <- stardist$StarDist2D$from_pretrained(model_name)

# Load the image
GiottoUtils::vmsg(
.v = verbose, .is_debug = FALSE, "Loading Image from ",
Image_dir
)
GiottoUtils::package_check("terra")
rast = terra::rast(Image_dir)
if (model_name != '2D_versatile_he' & is.null(nuclei_channel)){
stop('using IF based nuclei segmentation, please specify nuclei channel')
}
else if( model_name == '2D_versatile_he'){
img <- np$array(terra::as.array(rast))
}
else {
img <- np$array(drop(terra::as.array(rast[[as.numeric(nuclei_channel)]])))
}

# Normalize the image
normalized_img <- csbdeep$normalize(img)

# Perform prediction with StarDist2D model
results <- model$predict_instances(normalized_img,
prob_thresh = prob_thresh,
nms_thresh = nms_thresh)

# Extract the labels (first output from predict_instances)
mask <- results[[1]]
GiottoUtils::vmsg(
.v = verbose, .is_debug = FALSE,
"Segmentation finished... Saving mask file..."
)
rast_m <- terra::rast(mask)
terra::writeRaster(rast_m, mask_output, overwrite = TRUE)
}

















Loading

0 comments on commit f3a78f6

Please sign in to comment.