This module contains functions for slide-level quality control, including Otsu’s thresholding and Gaussian blur filtering. Quality control methods are used by passing a list of callables to the
qc argument of
.extract_tiles(). They can also be directly applied to a slide with
import slideflow as sf from slideflow.slide import qc # Define custom QC options qc = [ qc.Otsu(), qc.Gaussian(sigma=2) ] # Use this QC during tile extraction P.extract_tiles(qc=qc) # Alternatively, you can use the same QC directly on a WSI object wsi = sf.WSI(...) wsi.qc(qc).show()
- class Otsu(slide_level: int | None = None)¶
Prepare Otsu’s thresholding algorithm for filtering a slide.
This method is used to detect areas of tissue and remove background.
This QC method works by obtaining a thumbnail of a slide, and converting the image into the HSV color space. The HSV image undergoes a median blur using OpenCV with a kernel size of 7, and the image is thresholded using
cv2.THRESH_OTSU. This results in a binary mask, which is then applied to the slide for filtering.
Original paper: https://ieeexplore.ieee.org/document/4310076
Otsu’s thresholding may give unexpected results with slides that have many large pen marks, erroneously identifying pen marks as tissue and removing the actual tissue as background. This behavior can be circumvented by applying a Gaussian filter before Otsu’s thresholding.
import slideflow as sf from slideflow.slide import qc wsi = sf.WSI(...) gaussian = qc.GaussianV2() otsu = qc.Otsu() wsi.qc([gaussian, otsu])
Apply Otsu’s thresholding to a slide.
import slideflow as sf from slideflow.slide import qc wsi = sf.WSI(...) otsu = qc.Otsu() wsi.qc(otsu)
level (int) – Slide pyramid level at which to perform filtering. Defaults to second-lowest available level.
- class Gaussian(mpp: float | None = None, sigma: int = 3, threshold: float = 0.02)¶
Prepare Gaussian filtering algorithm for filtering a slide.
This method is used to remove out-of-focus areas and pen marks.
This QC method works by obtaining a thumbnail of a slide, and converting the image into grayspace. A gaussian filter with a given sigma (default=3) is calculated using scikit-image. Areas with blur below the given threshold (default=0.02) are filtered out.
Apply Gaussian filtering to a slide.
import slideflow as sf from slideflow.slide import qc wsi = sf.WSI(...) gaussian = qc.Gaussian() wsi.qc(gaussian)
mpp (float) – Microns-per-pixel at which to perform filtering. Defaults to 4 times the tile extraction MPP (e.g. for a tile_px/tile_um combination at 10X effective magnification, where tile_px=tile_um, the default blur_mpp would be 4, or effective magnification 2.5x).
sigma (int) – Sigma (radius) for Gaussian filter. Defaults to 3.
threshold (float) – Gaussian threshold. Defaults to 0.02.
- class Save(dest: str | None = None)¶
QC function which saves the mask to a numpy file.
When this QC method is applied to a slide, the current QC masks (e.g., as applied by the Otsu or Gaussian filtering methods) are saved to a numpy file. These saved masks can be loaded in the future using
slideflow.slide.qc.Load. Saving/loading masks saves time by allowing to avoid regenerating masks repeatedly.
By default, masks are saved in the same folder as whole-slide images.
from slideflow.slide import qc # Define a QC approach that auto-saves masks qc = [ qc.Otsu(), qc.Save() ] P.extract_tiles(qc=qc) ... # Auto-load previously saved masks qc = [ qc.Load() ] P.extract_tiles(qc=qc)
dest (str, optional) – Path in which to save the qc mask. If None, will save in the same directory as the slide. Defaults to None.
- class Load(source: str | None = None)¶
QC function which loads a saved numpy mask.
Loads and applies a QC mask which was saved by
source (str, optional) – Path to search for qc mask. If None, will search in the same directory as the slide. Defaults to None.
- class StridedDL(model: Callable, pred_idx: int, tile_px: int, tile_um: str | int, *, buffer: int = 8, verbose: bool = False, pred_threshold: float = 0.5, **wsi_kwargs)¶
QC function which uses a deep learning model to generate a QC mask.
When this QC method is applied to a slide, the given deep learning model generates predictions across the whole-slide image (using the class index specified by
pred_idx). Areas with a prediction above
pred_thresholdare masked, to be discarded.
Create a DeepFocus module that filters out-of-focus tiles.
import slideflow as sf from slideflow.slide.qc import strided_dl from deepfocus import deepfocus_v3 deepfocus = strided_dl.StridedDL( model=deepfocus_v3(), pred_idx=1, tile_px=64, tile_um='40x' ) wsi = sf.WSI(...) wsi.qc(deepfocus)
Do the same, but using class inheritance.
import slideflow as sf from slideflow.slide.qc import strided_dl from deepfocus import deepfocus_v3 class DeepFocus(strided_dl.StridedDL): def __init__(self): model = deepfocus_v3() checkpoint = '/path/to/checkpoint-ver5' load_checkpoint(model, checkpoint) super().__init__( model=model, pred_idx=1, tile_px=64, tile_um='40x' ) wsi = sf.WSI(...) deepfocus = DeepFocus() wsi.qc(deepfocus)
- Keyword Arguments:
verbose (bool) – Show a progress bar during calculation.
buffer (int) – Number of tiles (width and height) to extract and process simultaneously. Extracted tile size (width/height) will be
tile_px * buffer. Defaults to 8.
grayspace_fraction (float) – Grayspace fraction when extracting tiles from slides. Defaults to 1 (disables).
pred_threshold (float) – Predictions below this value are masked.
kwargs (Any) – All remaining keyword arguments are passed to