Skip to content
Snippets Groups Projects
Commit 6dd4de74 authored by Daniel CARRON's avatar Daniel CARRON :b: Committed by André Anjos
Browse files

[experiment] Add iostar database

parent 8a71f010
No related branches found
Tags v1.1.2
1 merge request!46Create common library
Showing
with 622 additions and 0 deletions
......@@ -430,6 +430,13 @@ chasedb1-2nd = "mednet.libs.segmentation.config.data.chasedb1.second_annotator"
# drive dataset - retinography
drive = "mednet.libs.segmentation.config.data.drive.default"
# iostar - retinography
iostar-vessel = "mednet.libs.segmentation.config.data.iostar.vessel"
iostar-disc = "mednet.libs.segmentation.config.data.iostar.optic_disc"
# montgomery county - cxr
# montgomery = "mednet.libs.segmentation.config.data.montgomery.default"
# stare dataset - retinography
stare = "mednet.libs.segmentation.config.data.stare.ah"
stare-2nd = "mednet.libs.segmentation.config.data.stare.vk"
......
# SPDX-FileCopyrightText: Copyright © 2024 Idiap Research Institute <contact@idiap.ch>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""IOSTAR (training set) for Vessel and Optic-Disc Segmentation."""
import importlib.resources
import os
from pathlib import Path
import PIL.Image
from mednet.libs.common.data.datamodule import CachingDataModule
from mednet.libs.common.data.split import JSONDatabaseSplit
from mednet.libs.common.data.typing import DatabaseSplit, Sample
from mednet.libs.segmentation.data.typing import (
SegmentationRawDataLoader as _SegmentationRawDataLoader,
)
from torchvision import tv_tensors
from torchvision.transforms.functional import to_tensor
from ....utils.rc import load_rc
CONFIGURATION_KEY_DATADIR = "datadir." + (__name__.rsplit(".", 2)[-2])
"""Key to search for in the configuration file for the root directory of this
database."""
class SegmentationRawDataLoader(_SegmentationRawDataLoader):
"""A specialized raw-data-loader for the iostar dataset."""
datadir: str
"""This variable contains the base directory where the database raw data is
stored."""
def __init__(self):
self.datadir = load_rc().get(
CONFIGURATION_KEY_DATADIR, os.path.realpath(os.curdir)
)
def sample(self, sample: tuple[str, str, str]) -> Sample:
"""Load a single image sample from the disk.
Parameters
----------
sample
A tuple containing the path suffix, within the dataset root folder,
where to find the image to be loaded, and an integer, representing the
sample label.
Returns
-------
The sample representation.
"""
image = PIL.Image.open(Path(self.datadir) / str(sample[0])).convert(
mode="RGB"
)
tensor = tv_tensors.Image(to_tensor(image))
target = tv_tensors.Image(
to_tensor(
PIL.Image.open(Path(self.datadir) / str(sample[1])).convert(
mode="1", dither=None
)
)
)
mask = tv_tensors.Mask(
to_tensor(
PIL.Image.open(Path(self.datadir) / str(sample[2])).convert(
mode="1", dither=None
)
)
)
return tensor, dict(target=target, mask=mask, name=sample[0]) # type: ignore[arg-type]
def make_split(basename: str) -> DatabaseSplit:
"""Return a database split for the iostar database.
Parameters
----------
basename
Name of the .json file containing the split to load.
Returns
-------
An instance of DatabaseSplit.
"""
return JSONDatabaseSplit(
importlib.resources.files(__name__.rsplit(".", 1)[0]).joinpath(basename)
)
class DataModule(CachingDataModule):
"""IOSTAR (training set) for Vessel and Optic-Disc Segmentation.
The IOSTAR vessel segmentation dataset includes 30 images with a resolution of
1024 × 1024 pixels. All the vessels in this dataset are annotated by a group of
experts working in the field of retinal image analysis. Additionally the
dataset includes annotations for the optic disc and the artery/vein ratio.
* Reference: [IOSTAR-2016]_
* Original resolution (height x width): 1024 x 1024
* Split reference: [MEYER-2017]_
* Protocol ``vessel``:
* Training samples: 20 (including labels and masks)
* Test samples: 10 (including labels and masks)
* Protocol ``optic-disc``:
* Training samples: 20 (including labels and masks)
* Test samples: 10 (including labels and masks)
Parameters
----------
split_filename
Name of the .json file containing the split to load.
"""
def __init__(self, split_filename: str):
super().__init__(
database_split=make_split(split_filename),
raw_data_loader=SegmentationRawDataLoader(),
)
{
"train": [
[
"image/STAR 01_OSC.jpg",
"mask_OD/STAR 01_OSC_ODMask.tif",
"mask/STAR 01_OSC_Mask.tif"
],
[
"image/STAR 02_ODC.jpg",
"mask_OD/STAR 02_ODC_ODMask.tif",
"mask/STAR 02_ODC_Mask.tif"
],
[
"image/STAR 03_OSN.jpg",
"mask_OD/STAR 03_OSN_ODMask.tif",
"mask/STAR 03_OSN_Mask.tif"
],
[
"image/STAR 05_ODC.jpg",
"mask_OD/STAR 05_ODC_ODMask.tif",
"mask/STAR 05_ODC_Mask.tif"
],
[
"image/STAR 06_ODN.jpg",
"mask_OD/STAR 06_ODN_ODMask.tif",
"mask/STAR 06_ODN_Mask.tif"
],
[
"image/STAR 08_OSN.jpg",
"mask_OD/STAR 08_OSN_ODMask.tif",
"mask/STAR 08_OSN_Mask.tif"
],
[
"image/STAR 09_OSN.jpg",
"mask_OD/STAR 09_OSN_ODMask.tif",
"mask/STAR 09_OSN_Mask.tif"
],
[
"image/STAR 10_OSN.jpg",
"mask_OD/STAR 10_OSN_ODMask.tif",
"mask/STAR 10_OSN_Mask.tif"
],
[
"image/STAR 13_OSN.jpg",
"mask_OD/STAR 13_OSN_ODMask.tif",
"mask/STAR 13_OSN_Mask.tif"
],
[
"image/STAR 15_OSN.jpg",
"mask_OD/STAR 15_OSN_ODMask.tif",
"mask/STAR 15_OSN_Mask.tif"
],
[
"image/STAR 16_OSN.jpg",
"mask_OD/STAR 16_OSN_ODMask.tif",
"mask/STAR 16_OSN_Mask.tif"
],
[
"image/STAR 17_ODN.jpg",
"mask_OD/STAR 17_ODN_ODMask.tif",
"mask/STAR 17_ODN_Mask.tif"
],
[
"image/STAR 20_ODC.jpg",
"mask_OD/STAR 20_ODC_ODMask.tif",
"mask/STAR 20_ODC_Mask.tif"
],
[
"image/STAR 21_OSC.jpg",
"mask_OD/STAR 21_OSC_ODMask.tif",
"mask/STAR 21_OSC_Mask.tif"
],
[
"image/STAR 24_OSC.jpg",
"mask_OD/STAR 24_OSC_ODMask.tif",
"mask/STAR 24_OSC_Mask.tif"
],
[
"image/STAR 26_ODC.jpg",
"mask_OD/STAR 26_ODC_ODMask.tif",
"mask/STAR 26_ODC_Mask.tif"
],
[
"image/STAR 28_ODN.jpg",
"mask_OD/STAR 28_ODN_ODMask.tif",
"mask/STAR 28_ODN_Mask.tif"
],
[
"image/STAR 30_ODC.jpg",
"mask_OD/STAR 30_ODC_ODMask.tif",
"mask/STAR 30_ODC_Mask.tif"
],
[
"image/STAR 31_ODN.jpg",
"mask_OD/STAR 31_ODN_ODMask.tif",
"mask/STAR 31_ODN_Mask.tif"
],
[
"image/STAR 32_ODC.jpg",
"mask_OD/STAR 32_ODC_ODMask.tif",
"mask/STAR 32_ODC_Mask.tif"
]
],
"test": [
[
"image/STAR 34_ODC.jpg",
"mask_OD/STAR 34_ODC_ODMask.tif",
"mask/STAR 34_ODC_Mask.tif"
],
[
"image/STAR 36_OSC.jpg",
"mask_OD/STAR 36_OSC_ODMask.tif",
"mask/STAR 36_OSC_Mask.tif"
],
[
"image/STAR 37_ODN.jpg",
"mask_OD/STAR 37_ODN_ODMask.tif",
"mask/STAR 37_ODN_Mask.tif"
],
[
"image/STAR 38_ODC.jpg",
"mask_OD/STAR 38_ODC_ODMask.tif",
"mask/STAR 38_ODC_Mask.tif"
],
[
"image/STAR 39_ODC.jpg",
"mask_OD/STAR 39_ODC_ODMask.tif",
"mask/STAR 39_ODC_Mask.tif"
],
[
"image/STAR 40_OSC.jpg",
"mask_OD/STAR 40_OSC_ODMask.tif",
"mask/STAR 40_OSC_Mask.tif"
],
[
"image/STAR 43_OSC.jpg",
"mask_OD/STAR 43_OSC_ODMask.tif",
"mask/STAR 43_OSC_Mask.tif"
],
[
"image/STAR 44_OSN.jpg",
"mask_OD/STAR 44_OSN_ODMask.tif",
"mask/STAR 44_OSN_Mask.tif"
],
[
"image/STAR 45_ODC.jpg",
"mask_OD/STAR 45_ODC_ODMask.tif",
"mask/STAR 45_ODC_Mask.tif"
],
[
"image/STAR 48_OSN.jpg",
"mask_OD/STAR 48_OSN_ODMask.tif",
"mask/STAR 48_OSN_Mask.tif"
]
]
}
# SPDX-FileCopyrightText: Copyright © 2024 Idiap Research Institute <contact@idiap.ch>
#
# SPDX-License-Identifier: GPL-3.0-or-later
from mednet.libs.segmentation.config.data.iostar.datamodule import DataModule
datamodule = DataModule("optic-disc.json")
{
"train": [
[
"image/STAR 01_OSC.jpg",
"GT/STAR 01_OSC_GT.tif",
"mask/STAR 01_OSC_Mask.tif"
],
[
"image/STAR 02_ODC.jpg",
"GT/STAR 02_ODC_GT.tif",
"mask/STAR 02_ODC_Mask.tif"
],
[
"image/STAR 03_OSN.jpg",
"GT/STAR 03_OSN_GT.tif",
"mask/STAR 03_OSN_Mask.tif"
],
[
"image/STAR 05_ODC.jpg",
"GT/STAR 05_ODC_GT.tif",
"mask/STAR 05_ODC_Mask.tif"
],
[
"image/STAR 06_ODN.jpg",
"GT/STAR 06_ODN_GT.tif",
"mask/STAR 06_ODN_Mask.tif"
],
[
"image/STAR 08_OSN.jpg",
"GT/STAR 08_OSN_GT.tif",
"mask/STAR 08_OSN_Mask.tif"
],
[
"image/STAR 09_OSN.jpg",
"GT/STAR 09_OSN_GT.tif",
"mask/STAR 09_OSN_Mask.tif"
],
[
"image/STAR 10_OSN.jpg",
"GT/STAR 10_OSN_GT.tif",
"mask/STAR 10_OSN_Mask.tif"
],
[
"image/STAR 13_OSN.jpg",
"GT/STAR 13_OSN_GT.tif",
"mask/STAR 13_OSN_Mask.tif"
],
[
"image/STAR 15_OSN.jpg",
"GT/STAR 15_OSN_GT.tif",
"mask/STAR 15_OSN_Mask.tif"
],
[
"image/STAR 16_OSN.jpg",
"GT/STAR 16_OSN_GT.tif",
"mask/STAR 16_OSN_Mask.tif"
],
[
"image/STAR 17_ODN.jpg",
"GT/STAR 17_ODN_GT.tif",
"mask/STAR 17_ODN_Mask.tif"
],
[
"image/STAR 20_ODC.jpg",
"GT/STAR 20_ODC_GT.tif",
"mask/STAR 20_ODC_Mask.tif"
],
[
"image/STAR 21_OSC.jpg",
"GT/STAR 21_OSC_GT.tif",
"mask/STAR 21_OSC_Mask.tif"
],
[
"image/STAR 24_OSC.jpg",
"GT/STAR 24_OSC_GT.tif",
"mask/STAR 24_OSC_Mask.tif"
],
[
"image/STAR 26_ODC.jpg",
"GT/STAR 26_ODC_GT.tif",
"mask/STAR 26_ODC_Mask.tif"
],
[
"image/STAR 28_ODN.jpg",
"GT/STAR 28_ODN_GT.tif",
"mask/STAR 28_ODN_Mask.tif"
],
[
"image/STAR 30_ODC.jpg",
"GT/STAR 30_ODC_GT.tif",
"mask/STAR 30_ODC_Mask.tif"
],
[
"image/STAR 31_ODN.jpg",
"GT/STAR 31_ODN_GT.tif",
"mask/STAR 31_ODN_Mask.tif"
],
[
"image/STAR 32_ODC.jpg",
"GT/STAR 32_ODC_GT.tif",
"mask/STAR 32_ODC_Mask.tif"
]
],
"test": [
[
"image/STAR 34_ODC.jpg",
"GT/STAR 34_ODC_GT.tif",
"mask/STAR 34_ODC_Mask.tif"
],
[
"image/STAR 36_OSC.jpg",
"GT/STAR 36_OSC_GT.tif",
"mask/STAR 36_OSC_Mask.tif"
],
[
"image/STAR 37_ODN.jpg",
"GT/STAR 37_ODN_GT.tif",
"mask/STAR 37_ODN_Mask.tif"
],
[
"image/STAR 38_ODC.jpg",
"GT/STAR 38_ODC_GT.tif",
"mask/STAR 38_ODC_Mask.tif"
],
[
"image/STAR 39_ODC.jpg",
"GT/STAR 39_ODC_GT.tif",
"mask/STAR 39_ODC_Mask.tif"
],
[
"image/STAR 40_OSC.jpg",
"GT/STAR 40_OSC_GT.tif",
"mask/STAR 40_OSC_Mask.tif"
],
[
"image/STAR 43_OSC.jpg",
"GT/STAR 43_OSC_GT.tif",
"mask/STAR 43_OSC_Mask.tif"
],
[
"image/STAR 44_OSN.jpg",
"GT/STAR 44_OSN_GT.tif",
"mask/STAR 44_OSN_Mask.tif"
],
[
"image/STAR 45_ODC.jpg",
"GT/STAR 45_ODC_GT.tif",
"mask/STAR 45_ODC_Mask.tif"
],
[
"image/STAR 48_OSN.jpg",
"GT/STAR 48_OSN_GT.tif",
"mask/STAR 48_OSN_Mask.tif"
]
]
}
# SPDX-FileCopyrightText: Copyright © 2024 Idiap Research Institute <contact@idiap.ch>
#
# SPDX-License-Identifier: GPL-3.0-or-later
from mednet.libs.segmentation.config.data.iostar.datamodule import DataModule
datamodule = DataModule("vessel.json")
# SPDX-FileCopyrightText: Copyright © 2024 Idiap Research Institute <contact@idiap.ch>
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""Tests for iostar dataset."""
import importlib
import pytest
from click.testing import CliRunner
def id_function(val):
if isinstance(val, dict):
return str(val)
return repr(val)
@pytest.mark.parametrize(
"split,lengths",
[
("vessel", dict(train=20, test=10)),
("optic-disc", dict(train=20, test=10)),
],
ids=id_function, # just changes how pytest prints it
)
def test_protocol_consistency(
database_checkers,
split: str,
lengths: dict[str, int],
):
from mednet.libs.segmentation.config.data.iostar.datamodule import (
make_split,
)
database_checkers.check_split(
make_split(f"{split}.json"),
lengths=lengths,
)
@pytest.mark.skip_if_rc_var_not_set("datadir.iostar")
def test_database_check():
from mednet.libs.segmentation.scripts.database import check
runner = CliRunner()
result = runner.invoke(check, ["iostar-vessel"])
assert (
result.exit_code == 0
), f"Exit code {result.exit_code} != 0 -- Output:\n{result.output}"
@pytest.mark.skip_if_rc_var_not_set("datadir.iostar")
@pytest.mark.parametrize(
"dataset",
[
"train",
"test",
],
)
@pytest.mark.parametrize(
"name",
["vessel", "optic_disc"],
)
def test_loading(database_checkers, name: str, dataset: str):
datamodule = importlib.import_module(
f".{name}",
"mednet.libs.segmentation.config.data.iostar",
).datamodule
datamodule.model_transforms = [] # should be done before setup()
datamodule.setup("predict") # sets up all datasets
loader = datamodule.predict_dataloader()[dataset]
limit = 3 # limit load checking
for batch in loader:
if limit == 0:
break
database_checkers.check_loaded_batch(
batch,
batch_size=1,
color_planes=3,
expected_num_targets=1,
)
limit -= 1
@pytest.mark.skip_if_rc_var_not_set("datadir.iostar")
def test_raw_transforms_image_quality(database_checkers, datadir):
reference_histogram_file = str(
datadir / "histograms/raw_data/histograms_iostar_vessel.json",
)
datamodule = importlib.import_module(
".vessel",
"mednet.libs.segmentation.config.data.iostar",
).datamodule
datamodule.model_transforms = []
datamodule.setup("predict")
database_checkers.check_image_quality(datamodule, reference_histogram_file)
@pytest.mark.skip_if_rc_var_not_set("datadir.iostar")
@pytest.mark.parametrize(
"model_name",
["lwnet"],
)
def test_model_transforms_image_quality(database_checkers, datadir, model_name):
reference_histogram_file = str(
datadir
/ f"histograms/models/histograms_{model_name}_iostar_vessel.json",
)
datamodule = importlib.import_module(
".vessel",
"mednet.libs.segmentation.config.data.iostar",
).datamodule
model = importlib.import_module(
f".{model_name}",
"mednet.libs.segmentation.config.models",
).model
datamodule.model_transforms = model.model_transforms
datamodule.setup("predict")
database_checkers.check_image_quality(
datamodule,
reference_histogram_file,
compare_type="statistical",
pearson_coeff_threshold=0.005,
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment