Skip to content

Commit 82e7d77

Browse files
authored
Merge pull request #81 from DIAGNijmegen/m-gc-wsi-bgseg
MHub / GC - WSI background/tissue segmentation model
2 parents f3c70d0 + 6ae707e commit 82e7d77

File tree

6 files changed

+343
-0
lines changed

6 files changed

+343
-0
lines changed
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
general:
2+
data_base_dir: /app/data
3+
version: 1.0
4+
description: WSI background tissue segmentation algorithm (dicom:sm to tiff:seg)
5+
6+
execute:
7+
- DicomImporter
8+
- TiffConverter
9+
- WSIBackgroundSegmentationRunner
10+
- DataOrganizer
11+
12+
modules:
13+
DicomImporter:
14+
source_dir: input_data
15+
import_dir: sorted_data
16+
sort_data: True
17+
meta:
18+
mod: "%Modality"
19+
20+
DataOrganizer:
21+
target_dir: output_data
22+
require_data_confirmation: true
23+
targets:
24+
- tiff:mod=seg-->[i:sid]/gc_wsi_bgseg.tiff

models/gc_wsi_bgseg/config/tiff.yml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
general:
2+
data_base_dir: /app/data
3+
version: 1.0
4+
description: WSI background tissue segmentation algorithm (tiff:sm to mha:seg)
5+
6+
execute:
7+
- FileStructureImporter
8+
- WSIBackgroundSegmentationRunner
9+
- DataOrganizer
10+
11+
modules:
12+
FileStructureImporter:
13+
input_dir: input_data
14+
structures:
15+
- $sid@instance/test.tiff@tiff:mod=sm
16+
import_id: sid
17+
18+
DataOrganizer:
19+
target_dir: output_data
20+
require_data_confirmation: true
21+
targets:
22+
- tiff:mod=seg-->[i:sid]/wsi_background_segmentation.tiff
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
FROM mhubai/base:latest
2+
3+
# Update authors label
4+
LABEL authors="[email protected]"
5+
6+
# Install pipenv (for a custom Python/Pip environment for ASAP-2.1 and the other algorithm requirements)
7+
RUN pip3 install --no-cache-dir pipenv
8+
9+
# Set environment variables for pipenv (installs into /app/.venv)
10+
ENV PIPENV_VENV_IN_PROJECT=1
11+
12+
# Install ASAP 2.1
13+
RUN apt-get update && \
14+
apt-get -y install curl libpython3.8-dev && \
15+
curl --remote-name --location "https://github.com/computationalpathologygroup/ASAP/releases/download/ASAP-2.1/ASAP-2.1-py38-Ubuntu2004.deb" && \
16+
dpkg --install ASAP-2.1-py38-Ubuntu2004.deb || true && \
17+
apt-get -f install --fix-missing --fix-broken --assume-yes && \
18+
ldconfig -v && \
19+
apt-get clean && \
20+
rm ASAP-2.1-py38-Ubuntu2004.deb
21+
22+
# Setup and install algorithm pipenv environment
23+
# 1. Ensure we configure a new empty pipenv for Python 3.8
24+
# 2. Link ASAP libraries into our environment
25+
# 3. Upgrade pip
26+
# 4. Upgrade version of numpy and numba to function correctly with ASAP
27+
# 5. Install required dependencies for algorithm
28+
RUN pipenv install --python 3.8 && \
29+
echo "/opt/ASAP/bin" > /app/.venv/lib/python3.8/site-packages/asap.pth && \
30+
pipenv run pip install --no-cache-dir --upgrade pip && \
31+
pipenv run pip install --no-cache-dir --upgrade numpy==1.24.4 numba==0.58.1 && \
32+
pipenv run pip install --no-cache-dir scipy==1.10.1 scikit-image==0.21.0 h5py==3.11.0
33+
34+
# build/install Tensorflow 2.11.0 with GPU support (without conda), with CUDA 11 toolkit and cudnn 8
35+
# tensorflow-2.11.0 Python 3.7-3.10 cuDNN >= 8.1 CUDA >= 11.2
36+
RUN pipenv run pip install --no-cache-dir \
37+
nvidia-cuda-runtime-cu11 \
38+
nvidia-cusolver-cu11 \
39+
nvidia-curand-cu11 \
40+
nvidia-cufft-cu11 \
41+
nvidia-cublas-cu11 \
42+
nvidia-cusparse-cu11 \
43+
nvidia-cudnn-cu11 \
44+
nvidia-tensorrt==7.2.3.4 \
45+
tensorflow==2.11.0 \
46+
--extra-index-url https://pypi.ngc.nvidia.com
47+
48+
# Configure required paths for tensorflow with GPU support
49+
ENV NVIDIA_DIR /app/.venv/lib/python3.8/site-packages/nvidia
50+
ENV LD_LIBRARY_PATH /app/.venv/lib/python3.8/site-packages/tensorrt:$NVIDIA_DIR/cublas/lib:$NVIDIA_DIR/cuda_runtime/lib:$NVIDIA_DIR/cudnn/lib:$NVIDIA_DIR/cufft/lib:$NVIDIA_DIR/curand/lib:$NVIDIA_DIR/cusolver/lib:$NVIDIA_DIR/cusparse/lib
51+
52+
# Import the MHub model definiton
53+
ARG MHUB_MODELS_REPO
54+
RUN buildutils/import_mhub_model.sh gc_wsi_bgseg ${MHUB_MODELS_REPO}
55+
56+
# Install pathology tissue background segmentation processor code and weights (version 1.0.0)
57+
RUN git clone --depth 1 --branch 1.0.0 https://github.com/DIAGNijmegen/pathology-tissue-background-segmentation-processor.git /app/src
58+
59+
# Add model and algorithm code bases to python path
60+
ENV PYTHONPATH="/app:/app/src"
61+
62+
# Default run script
63+
ENTRYPOINT ["python3", "-m", "mhubio.run"]
64+
CMD ["--config", "/app/models/gc_wsi_bgseg/config/default.yml"]

models/gc_wsi_bgseg/meta.json

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
{
2+
"id": "bb083d5e-b5ed-481a-8a24-00e95d301067",
3+
"name": "gc_wsi_bgseg",
4+
"title": "Tissue-Background segmentation in histopathological whole-slide images",
5+
"summary": {
6+
"description": "This algorithm segments the background and tissue in histopathological whole-slide images.",
7+
"inputs": [
8+
{
9+
"label": "Whole-slide image",
10+
"description": "Whole-slide histopathology image",
11+
"format": "DICOM",
12+
"modality": "SM",
13+
"bodypartexamined": "WHOLEBODY",
14+
"slicethickness": "",
15+
"non-contrast": false,
16+
"contrast": false
17+
}
18+
],
19+
"outputs": [
20+
{
21+
"type": "Prediction",
22+
"valueType": "Segmentation mask",
23+
"label": "WSI background and tissue segmentation mask",
24+
"description": "WSI background and tissue segmentation mask (MHA). The labels are: 0-background 1-tissue. The output will have a pixel spacing",
25+
"classes": []
26+
}
27+
],
28+
"model": {
29+
"architecture": "Fully convolutional network with 7 layers, ReLU activation functions in the first 6 convolutional layers and softmax in the last one. Max pooling was inserted after each of the first 3 convolutional layers.",
30+
"training": "supervised",
31+
"cmpapproach": "2D"
32+
},
33+
"data": {
34+
"training": {
35+
"vol_samples": 70
36+
},
37+
"evaluation": {
38+
"vol_samples": 38
39+
},
40+
"public": false,
41+
"external": false
42+
}
43+
},
44+
"details": {
45+
"name": "Tissue-Background Segmentation in Histopathological Whole-Slide Images",
46+
"version": "1.0.0",
47+
"devteam": "Peter Bándi",
48+
"type": "Segmentation",
49+
"date": {
50+
"weights": "2019-12-13",
51+
"code": "2024-05-16",
52+
"pub": "2019-12-17"
53+
},
54+
"cite": "Bándi P, Balkenhol M, van Ginneken B, van der Laak J, Litjens G. 2019. Resolution-agnostic tissue segmentation in whole-slide histopathology images with convolutional neural networks. PeerJ 7:e8242",
55+
"license": {
56+
"code": "AGPL v3.0",
57+
"weights": "AGPL v3.0"
58+
},
59+
"publications": [
60+
{
61+
"uri": "https://peerj.com/articles/8242/",
62+
"title": "Resolution-agnostic tissue segmentation in whole-slide histopathology images with convolutional neural networks"
63+
}
64+
],
65+
"github": "https://github.com/DIAGNijmegen/pathology-tissue-background-segmentation-processor",
66+
"zenodo": "",
67+
"colab": "",
68+
"slicer": false
69+
},
70+
"info": {
71+
"use": {
72+
"title": "Intended use",
73+
"text": "This algorithm is a segmentation method of the background on whole-slide histopathology images. The algorithm will segment WSI with various stains and resolutions. It takes pixel spacing as input parameter (default 2.0μm) and will create a segmentation of that resolution. The input WSI needs to contain at least one layer of that resolution, with a 25% tolerance. The algorithm can also be found on Grand Challenge [1] (access with verified account).",
74+
"references": [
75+
{
76+
"label": "Algorithm on Grand Challenge (access with verified account)",
77+
"uri": "https://grand-challenge.org/algorithms/tissue-background-segmenation"
78+
}
79+
],
80+
"tables": []
81+
},
82+
"analyses": {
83+
"title": "Evaluation",
84+
"text": "Evaluation was determined with DICE score, sensitivity, and false-positive count, and compared with three other non-deeplearning methods: Otsu's, FESI, and Thresholding. See the paper (Methods, pages 12-13, section on Measurements, and Results, pages 13-15) for additional details [1].",
85+
"references": [
86+
{
87+
"label": "Resolution-agnostic tissue segmentation in whole-slide histopathology images with convolutional neural networks",
88+
"uri": "https://peerj.com/articles/8242/"
89+
}
90+
],
91+
"tables": [
92+
{
93+
"label": "Dice scores at 2.0μm pixel spacing.",
94+
"entries": {
95+
"Thresholding": "0.8627 ±0.1361",
96+
"Otsu's": "0.7373 ±0.1596",
97+
"FESI": "0.8284 ±0.3288",
98+
"This model": "0.9822 ±0.0195"
99+
}
100+
},
101+
{
102+
"label": "Sensitivity scores at 2.0μm pixel spacing.",
103+
"entries": {
104+
"Thresholding": "0.5763 ±0.3631",
105+
"Otsu's": "0.2890 ±0.3665",
106+
"FESI": "0.6495 ±0.3690",
107+
"This model": "0.8953 ±0.1302"
108+
}
109+
},
110+
{
111+
"label": "False-positive count at 2.0μm pixel spacing.",
112+
"entries": {
113+
"Thresholding": "34.50 ±76.49",
114+
"Otsu's": "12.63 ±12.09",
115+
"FESI": "1.37 ±2.63",
116+
"This model": "5.37 ±8.25"
117+
}
118+
}
119+
]
120+
},
121+
"evaluation": {
122+
"title": "Evaluation data",
123+
"text": "The evaluation was performed on two private datasets. The first dataset consisted of 30 WSI with breast, lymph node, kidney, lung, rectum and tongue tissue, stained with hematoxylin and eosin (H&E), Sirius Red, Periodic Acid-Schiff (PAS), cytokeratin AE1/AE3 (AE1AE3), Ki-67, and a cocktail of cytokeratin 8 and cytokeratin 18 (CK8-18). The second dataset consisted of 8 WSI with mostly different tissue types and all different staining methods, to evaluate generalization of the model. It contained tissue types lung, cornea, aorta, brain, skin, uterus, and kidney. The tissues were stained with Grocott, Alcian Blue, Von Kossa, Perls, and Chromotrope Aniline Blue (CAB) stains. See the paper (Materials, pages 4-6, sections on the development and the dissimilar datasets) for additional details [1].",
124+
"references": [
125+
{
126+
"label": "Resolution-agnostic tissue segmentation in whole-slide histopathology images with convolutional neural networks",
127+
"uri": "https://peerj.com/articles/8242/"
128+
}
129+
],
130+
"tables": []
131+
},
132+
"training": {
133+
"title": "Training data",
134+
"text": "The training dataset consisted of 70 WSI from Breast, Lymph node, Kidney, Lung, Rectum and Tongue tissue, stained with hematoxylin and eosin (H&E), Sirius Red, Periodic Acid-Schiff (PAS), cytokeratin AE1/AE3 (AE1AE3), Ki-67, and a cocktail of cytokeratin 8 and cytokeratin 18 (CK8-18). See the paper (Materials, pages 4-5, development dataset section) for additional details [1].",
135+
"references": [
136+
{
137+
"label": "Resolution-agnostic tissue segmentation in whole-slide histopathology images with convolutional neural networks",
138+
"uri": "https://peerj.com/articles/8242/"
139+
}
140+
],
141+
"tables": []
142+
},
143+
"ethics": {
144+
"title": "",
145+
"text": "",
146+
"references": [],
147+
"tables": []
148+
},
149+
"limitations": {
150+
"title": "Limitations",
151+
"text": "This algorithm was developed for research purposes only. The provided input should contain a layer with the selected pixel spacing (default 2.0μm ± 25%).",
152+
"references": [],
153+
"tables": []
154+
}
155+
}
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""
2+
------------------------------------------------------------------
3+
Mhub / DIAG - Run Module for WSI Background Segmentation Algorithm
4+
------------------------------------------------------------------
5+
6+
------------------------------------------------------------------
7+
Author: Sil van de Leemput
8+
9+
------------------------------------------------------------------
10+
"""
11+
from typing import Optional
12+
13+
import tempfile
14+
15+
from mhubio.core import Instance, InstanceData, IO, Module
16+
17+
from pathlib import Path
18+
19+
@IO.Config(
20+
'input_spacing', float, 2.0,
21+
the="Desired input spacing to run the segmentation algorithm for. "
22+
"The closest level matching the spacing in the input Tiff image will be selected. "
23+
"Default is 2.0 micrometer."
24+
)
25+
@IO.Config(
26+
'output_spacing', Optional[float], None,
27+
the="Desired output spacing for the output segmentation. "
28+
"By default this matches the input_spacing."
29+
)
30+
@IO.Config(
31+
'spacing_tolerance', float, 0.25,
32+
the="Relative spacing tolerance with respect to the desired input_spacing. "
33+
"By default this is set to 25%."
34+
)
35+
class WSIBackgroundSegmentationRunner(Module):
36+
37+
input_spacing: float
38+
output_spacing: Optional[float]
39+
spacing_tolerance: float
40+
41+
CLI_SCRIPT_PATH = Path("/app") / "src" / "process.py"
42+
43+
@IO.Instance()
44+
@IO.Input('in_data', 'tif|tiff:mod=sm', the='input whole slide image Tiff')
45+
@IO.Output('out_data', 'gc_wsi_bg_segmentation.tif', 'tiff:mod=seg:model=WSIBackgroundSegmentation', 'in_data', the='Background segmentation of the input WSI.')
46+
def task(self, instance: Instance, in_data: InstanceData, out_data: InstanceData) -> None:
47+
output_spacing = self.output_spacing
48+
if self.output_spacing is None:
49+
output_spacing = self.input_spacing
50+
51+
with tempfile.TemporaryDirectory() as tmp_dir:
52+
# Execute the Tiger LB2 Algorithm through a Python subprocess and associated pipenv environment
53+
self.subprocess(
54+
[
55+
"pipenv",
56+
"run",
57+
"python",
58+
str(self.CLI_SCRIPT_PATH),
59+
in_data.abspath,
60+
out_data.abspath,
61+
"--work-dir",
62+
tmp_dir,
63+
"--input-spacing",
64+
str(self.input_spacing),
65+
"--output-spacing",
66+
str(output_spacing),
67+
"--spacing-tolerance",
68+
str(self.spacing_tolerance)
69+
]
70+
)
71+
72+
# Validate that the required output was generated by the subprocess
73+
if not Path(out_data.abspath).is_file():
74+
raise FileNotFoundError(
75+
f"Couldn't find expected output file: `{out_data.abspath}`. "
76+
f"The subprocess `{self.CLI_SCRIPT_PATH}` did not generate the required output file."
77+
)

models/gc_wsi_bgseg/utils/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)