From 6333dc14f3c85a6567597034379e43b290865051 Mon Sep 17 00:00:00 2001 From: tianbin li <46390195+tianbinli@users.noreply.github.com> Date: Wed, 21 Jun 2023 14:41:58 +0800 Subject: [PATCH] [Project] Medical semantic seg dataset: dr_hagis (#2729) --- .../fundus_photography/dr_hagis/README.md | 155 ++++++++++++++++++ .../dr_hagis/configs/dr-hagis_512x512.py | 42 +++++ ..._unet_1xb16-0.0001-20k_dr-hagis-512x512.py | 17 ++ ...6_unet_1xb16-0.001-20k_dr-hagis-512x512.py | 17 ++ ...16_unet_1xb16-0.01-20k_dr-hagis-512x512.py | 17 ++ .../dr_hagis/datasets/dr-hagis_dataset.py | 27 +++ .../dr_hagis/tools/prepare_dataset.py | 41 +++++ 7 files changed, 316 insertions(+) create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/README.md create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/configs/dr-hagis_512x512.py create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.0001-20k_dr-hagis-512x512.py create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.001-20k_dr-hagis-512x512.py create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.01-20k_dr-hagis-512x512.py create mode 100644 projects/medical/2d_image/fundus_photography/dr_hagis/datasets/dr-hagis_dataset.py create mode 100755 projects/medical/2d_image/fundus_photography/dr_hagis/tools/prepare_dataset.py diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/README.md b/projects/medical/2d_image/fundus_photography/dr_hagis/README.md new file mode 100644 index 0000000000..85d8a3e271 --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/README.md @@ -0,0 +1,155 @@ +# DR HAGIS: Diabetic Retinopathy, Hypertension, Age-related macular degeneration and Glacuoma ImageS + +## Description + +This project supports **`DR HAGIS: Diabetic Retinopathy, Hypertension, Age-related macular degeneration and Glacuoma ImageS`**, which can be downloaded from [here](https://paperswithcode.com/dataset/dr-hagis). + +### Dataset Overview + +The DR HAGIS database has been created to aid the development of vessel extraction algorithms suitable for retinal screening programmes. Researchers are encouraged to test their segmentation algorithms using this database. All thirty-nine fundus images were obtained from a diabetic retinopathy screening programme in the UK. Hence, all images were taken from diabetic patients. + +Besides the fundus images, the manual segmentation of the retinal surface vessels is provided by an expert grader. These manually segmented images can be used as the ground truth to compare and assess the automatic vessel extraction algorithms. Masks of the FOV are provided as well to quantify the accuracy of vessel extraction within the FOV only. The images were acquired in different screening centers, therefore reflecting the range of image resolutions, digital cameras and fundus cameras used in the clinic. The fundus images were captured using a Topcon TRC-NW6s, Topcon TRC-NW8 or a Canon CR DGi fundus camera with a horizontal 45 degree field-of-view (FOV). The images are 4752x3168 pixels, 3456x2304 pixels, 3126x2136 pixels, 2896x1944 pixels or 2816x1880 pixels in size. + +### Original Statistic Information + +| Dataset name | Anatomical region | Task type | Modality | Num. Classes | Train/Val/Test Images | Train/Val/Test Labeled | Release Date | License | +| ------------------------------------------------------- | ----------------- | ------------ | ------------------ | ------------ | --------------------- | ---------------------- | ------------ | ------- | +| [DR HAGIS](https://paperswithcode.com/dataset/dr-hagis) | head and neck | segmentation | fundus photography | 2 | 40/-/- | yes/-/- | 2017 | - | + +| Class Name | Num. Train | Pct. Train | Num. Val | Pct. Val | Num. Test | Pct. Test | +| :--------: | :--------: | :--------: | :------: | :------: | :-------: | :-------: | +| background | 40 | 96.38 | - | - | - | - | +| vessel | 40 | 3.62 | - | - | - | - | + +Note: + +- `Pct` means percentage of pixels in this category in all pixels. + +### Visualization + +![bac](https://raw.githubusercontent.com/uni-medical/medical-datasets-visualization/main/2d/semantic_seg/fundus_photography/dr_hagis/dr_hagis_dataset.png) + +## Usage + +### Prerequisites + +- Python v3.8 +- PyTorch v1.10.0 +- [MIM](https://github.com/open-mmlab/mim) v0.3.4 +- [MMCV](https://github.com/open-mmlab/mmcv) v2.0.0rc4 +- [MMEngine](https://github.com/open-mmlab/mmengine) v0.2.0 or higher +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation) v1.0.0rc5 + +All the commands below rely on the correct configuration of `PYTHONPATH`, which should point to the project's directory so that Python can locate the module files. In `dr_hagis/` root directory, run the following line to add the current directory to `PYTHONPATH`: + +```shell +export PYTHONPATH=`pwd`:$PYTHONPATH +``` + +### Dataset preparing + +- download dataset from [here](https://paperswithcode.com/dataset/dr-hagis) and decompress data to path `'data/'`. +- run script `"python tools/prepare_dataset.py"` to format data and change folder structure as below. +- run script `"python ../../tools/split_seg_dataset.py"` to split dataset and generate `train.txt`, `val.txt` and `test.txt`. If the label of official validation set and test set can't be obtained, we generate `train.txt` and `val.txt` from the training set randomly. + +```none + mmsegmentation + ├── mmseg + ├── projects + │ ├── medical + │ │ ├── 2d_image + │ │ │ ├── fundus_photography + │ │ │ │ ├── dr_hagis + │ │ │ │ │ ├── configs + │ │ │ │ │ ├── datasets + │ │ │ │ │ ├── tools + │ │ │ │ │ ├── data + │ │ │ │ │ │ ├── train.txt + │ │ │ │ │ │ ├── val.txt + │ │ │ │ │ │ ├── images + │ │ │ │ │ │ │ ├── train + │ │ │ │ | │ │ │ ├── xxx.png + │ │ │ │ | │ │ │ ├── ... + │ │ │ │ | │ │ │ └── xxx.png + │ │ │ │ │ │ ├── masks + │ │ │ │ │ │ │ ├── train + │ │ │ │ | │ │ │ ├── xxx.png + │ │ │ │ | │ │ │ ├── ... + │ │ │ │ | │ │ │ └── xxx.png +``` + +### Divided Dataset Information + +***Note: The table information below is divided by ourselves.*** + +| Class Name | Num. Train | Pct. Train | Num. Val | Pct. Val | Num. Test | Pct. Test | +| :--------: | :--------: | :--------: | :------: | :------: | :-------: | :-------: | +| background | 32 | 96.21 | 8 | 97.12 | - | - | +| vessel | 32 | 3.79 | 8 | 2.88 | - | - | + +### Training commands + +Train models on a single server with one GPU. + +```shell +mim train mmseg ./configs/${CONFIG_FILE} +``` + +### Testing commands + +Test models on a single server with one GPU. + +```shell +mim test mmseg ./configs/${CONFIG_FILE} --checkpoint ${CHECKPOINT_PATH} +``` + + + +## Dataset Citation + +If this work is helpful for your research, please consider citing the below paper. + +``` +@article{holm2017dr, + title={DR HAGIS—a fundus image database for the automatic extraction of retinal surface vessels from diabetic patients}, + author={Holm, Sven and Russell, Greg and Nourrit, Vincent and McLoughlin, Niall}, + journal={Journal of Medical Imaging}, + volume={4}, + number={1}, + pages={014503--014503}, + year={2017}, + publisher={Society of Photo-Optical Instrumentation Engineers} +} +``` + +## Checklist + +- [x] Milestone 1: PR-ready, and acceptable to be one of the `projects/`. + + - [x] Finish the code + + - [x] Basic docstrings & proper citation + + - [ ] Test-time correctness + + - [x] A full README + +- [ ] Milestone 2: Indicates a successful model implementation. + + - [ ] Training-time correctness + +- [ ] Milestone 3: Good to be a part of our core package! + + - [ ] Type hints and docstrings + + - [ ] Unit tests + + - [ ] Code polishing + + - [ ] Metafile.yml + +- [ ] Move your modules into the core package following the codebase's file hierarchy structure. + +- [ ] Refactor your modules into the core package following the codebase's file hierarchy structure. diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/configs/dr-hagis_512x512.py b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/dr-hagis_512x512.py new file mode 100644 index 0000000000..93b9638410 --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/dr-hagis_512x512.py @@ -0,0 +1,42 @@ +dataset_type = 'DRHAGISDataset' +data_root = 'data/' +img_scale = (512, 512) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations'), + dict(type='Resize', scale=img_scale, keep_ratio=False), + dict(type='RandomFlip', prob=0.5), + dict(type='PhotoMetricDistortion'), + dict(type='PackSegInputs') +] +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', scale=img_scale, keep_ratio=False), + dict(type='LoadAnnotations'), + dict(type='PackSegInputs') +] +train_dataloader = dict( + batch_size=16, + num_workers=4, + persistent_workers=True, + sampler=dict(type='InfiniteSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + ann_file='train.txt', + data_prefix=dict(img_path='images/', seg_map_path='masks/'), + pipeline=train_pipeline)) +val_dataloader = dict( + batch_size=1, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + ann_file='val.txt', + data_prefix=dict(img_path='images/', seg_map_path='masks/'), + pipeline=test_pipeline)) +test_dataloader = val_dataloader +val_evaluator = dict(type='IoUMetric', iou_metrics=['mIoU', 'mDice']) +test_evaluator = dict(type='IoUMetric', iou_metrics=['mIoU', 'mDice']) diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.0001-20k_dr-hagis-512x512.py b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.0001-20k_dr-hagis-512x512.py new file mode 100644 index 0000000000..9d14427c45 --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.0001-20k_dr-hagis-512x512.py @@ -0,0 +1,17 @@ +_base_ = [ + './dr-hagis_512x512.py', 'mmseg::_base_/models/fcn_unet_s5-d16.py', + 'mmseg::_base_/default_runtime.py', + 'mmseg::_base_/schedules/schedule_20k.py' +] +custom_imports = dict(imports='datasets.dr-hagis_dataset') +img_scale = (512, 512) +data_preprocessor = dict(size=img_scale) +optimizer = dict(lr=0.0001) +optim_wrapper = dict(optimizer=optimizer) +model = dict( + data_preprocessor=data_preprocessor, + decode_head=dict(num_classes=2), + auxiliary_head=None, + test_cfg=dict(mode='whole', _delete_=True)) +vis_backends = None +visualizer = dict(vis_backends=vis_backends) diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.001-20k_dr-hagis-512x512.py b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.001-20k_dr-hagis-512x512.py new file mode 100644 index 0000000000..507ec748bf --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.001-20k_dr-hagis-512x512.py @@ -0,0 +1,17 @@ +_base_ = [ + './dr-hagis_512x512.py', 'mmseg::_base_/models/fcn_unet_s5-d16.py', + 'mmseg::_base_/default_runtime.py', + 'mmseg::_base_/schedules/schedule_20k.py' +] +custom_imports = dict(imports='datasets.dr-hagis_dataset') +img_scale = (512, 512) +data_preprocessor = dict(size=img_scale) +optimizer = dict(lr=0.001) +optim_wrapper = dict(optimizer=optimizer) +model = dict( + data_preprocessor=data_preprocessor, + decode_head=dict(num_classes=2), + auxiliary_head=None, + test_cfg=dict(mode='whole', _delete_=True)) +vis_backends = None +visualizer = dict(vis_backends=vis_backends) diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.01-20k_dr-hagis-512x512.py b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.01-20k_dr-hagis-512x512.py new file mode 100644 index 0000000000..092ae00a7d --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/configs/fcn-unet-s5-d16_unet_1xb16-0.01-20k_dr-hagis-512x512.py @@ -0,0 +1,17 @@ +_base_ = [ + './dr-hagis_512x512.py', 'mmseg::_base_/models/fcn_unet_s5-d16.py', + 'mmseg::_base_/default_runtime.py', + 'mmseg::_base_/schedules/schedule_20k.py' +] +custom_imports = dict(imports='datasets.dr-hagis_dataset') +img_scale = (512, 512) +data_preprocessor = dict(size=img_scale) +optimizer = dict(lr=0.01) +optim_wrapper = dict(optimizer=optimizer) +model = dict( + data_preprocessor=data_preprocessor, + decode_head=dict(num_classes=2), + auxiliary_head=None, + test_cfg=dict(mode='whole', _delete_=True)) +vis_backends = None +visualizer = dict(vis_backends=vis_backends) diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/datasets/dr-hagis_dataset.py b/projects/medical/2d_image/fundus_photography/dr_hagis/datasets/dr-hagis_dataset.py new file mode 100644 index 0000000000..9659f0b8d7 --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/datasets/dr-hagis_dataset.py @@ -0,0 +1,27 @@ +from mmseg.datasets import BaseSegDataset +from mmseg.registry import DATASETS + + +@DATASETS.register_module() +class DRHAGISDataset(BaseSegDataset): + """DRHAGISDataset dataset. + + In segmentation map annotation for DRHAGISDataset, + ``reduce_zero_label`` is fixed to False. The ``img_suffix`` + is fixed to '.png' and ``seg_map_suffix`` is fixed to '.png'. + + Args: + img_suffix (str): Suffix of images. Default: '.png' + seg_map_suffix (str): Suffix of segmentation maps. Default: '.png' + """ + METAINFO = dict(classes=('background', 'vessel')) + + def __init__(self, + img_suffix='.png', + seg_map_suffix='.png', + **kwargs) -> None: + super().__init__( + img_suffix=img_suffix, + seg_map_suffix=seg_map_suffix, + reduce_zero_label=False, + **kwargs) diff --git a/projects/medical/2d_image/fundus_photography/dr_hagis/tools/prepare_dataset.py b/projects/medical/2d_image/fundus_photography/dr_hagis/tools/prepare_dataset.py new file mode 100755 index 0000000000..51f4df7dac --- /dev/null +++ b/projects/medical/2d_image/fundus_photography/dr_hagis/tools/prepare_dataset.py @@ -0,0 +1,41 @@ +import glob +import os +import shutil + +import mmengine +import numpy as np +from PIL import Image + +root_path = 'data/' +img_suffix = '.jpg' +seg_map_suffix = '_manual_orig.png' +save_img_suffix = '.png' +save_seg_map_suffix = '.png' + +x_train = glob.glob(os.path.join('data/DRHAGIS/**/*' + img_suffix)) + +mmengine.mkdir_or_exist(root_path + 'images/train/') +mmengine.mkdir_or_exist(root_path + 'masks/train/') + +D3_palette = {0: (0, 0, 0), 1: (1, 1, 1)} +D3_invert_palette = {v: k for k, v in D3_palette.items()} +D2_255_convert_dict = {0: 0, 255: 1} + +part_dir_dict = {0: 'train/', 1: 'val/'} +for ith, part in enumerate([x_train]): + part_dir = part_dir_dict[ith] + for img in part: + basename = os.path.basename(img) + shutil.copy( + img, root_path + 'images/' + part_dir + basename.split('.')[0] + + save_img_suffix) + mask_path = root_path + 'DRHAGIS/Manual_Segmentations/' + basename.split( # noqa + '.')[0] + seg_map_suffix + label = np.array(Image.open(mask_path)) + + save_mask_path = root_path + 'masks/' + part_dir + basename.split( + '.')[0] + save_seg_map_suffix # noqa + mask = np.array(Image.open(mask_path)).astype(np.uint8) + mask[mask == 255] = 1 + mask = Image.fromarray(mask) + mask.save(save_mask_path)