mirror of
https://github.com/open-mmlab/mmsegmentation.git
synced 2025-06-03 22:03:48 +08:00
## Motivation Add Synapse dataset in MMSegmentation. Old PR: https://github.com/open-mmlab/mmsegmentation/pull/2372.
This commit is contained in:
parent
bd29c20778
commit
2d67e51db3
41
configs/_base_/datasets/synapse.py
Normal file
41
configs/_base_/datasets/synapse.py
Normal file
@ -0,0 +1,41 @@
|
||||
dataset_type = 'SynapseDataset'
|
||||
data_root = 'data/synapse/'
|
||||
img_scale = (224, 224)
|
||||
train_pipeline = [
|
||||
dict(type='LoadImageFromFile'),
|
||||
dict(type='LoadAnnotations'),
|
||||
dict(type='Resize', scale=img_scale, keep_ratio=True),
|
||||
dict(type='RandomRotFlip', rotate_prob=0.5, flip_prob=0.5, degree=20),
|
||||
dict(type='PackSegInputs')
|
||||
]
|
||||
test_pipeline = [
|
||||
dict(type='LoadImageFromFile'),
|
||||
dict(type='Resize', scale=img_scale, keep_ratio=True),
|
||||
dict(type='LoadAnnotations'),
|
||||
dict(type='PackSegInputs')
|
||||
]
|
||||
train_dataloader = dict(
|
||||
batch_size=6,
|
||||
num_workers=2,
|
||||
persistent_workers=True,
|
||||
sampler=dict(type='InfiniteSampler', shuffle=True),
|
||||
dataset=dict(
|
||||
type=dataset_type,
|
||||
data_root=data_root,
|
||||
data_prefix=dict(
|
||||
img_path='img_dir/train', seg_map_path='ann_dir/train'),
|
||||
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,
|
||||
data_prefix=dict(img_path='img_dir/val', seg_map_path='ann_dir/val'),
|
||||
pipeline=test_pipeline))
|
||||
test_dataloader = val_dataloader
|
||||
|
||||
val_evaluator = dict(type='IoUMetric', iou_metrics=['mDice'])
|
||||
test_evaluator = val_evaluator
|
@ -414,3 +414,84 @@ The contents of LIP datasets include:
|
||||
│ │ │ ├── 100034_483681.png
|
||||
│ │ │ ├── ...
|
||||
```
|
||||
|
||||
## Synapse dataset
|
||||
|
||||
This dataset could be download from [this page](https://www.synapse.org/#!Synapse:syn3193805/wiki/)
|
||||
|
||||
To follow the data preparation setting of [TransUNet](https://arxiv.org/abs/2102.04306), which splits original training set (30 scans)
|
||||
into new training (18 scans) and validation set (12 scans). Please run the following command to prepare the dataset.
|
||||
|
||||
```shell
|
||||
unzip RawData.zip
|
||||
cd ./RawData/Training
|
||||
```
|
||||
|
||||
Then create `train.txt` and `val.txt` to split dataset.
|
||||
|
||||
According to TransUnet, the following is the data set division.
|
||||
|
||||
train.txt
|
||||
|
||||
```none
|
||||
img0005.nii.gz
|
||||
img0006.nii.gz
|
||||
img0007.nii.gz
|
||||
img0009.nii.gz
|
||||
img0010.nii.gz
|
||||
img0021.nii.gz
|
||||
img0023.nii.gz
|
||||
img0024.nii.gz
|
||||
img0026.nii.gz
|
||||
img0027.nii.gz
|
||||
img0028.nii.gz
|
||||
img0030.nii.gz
|
||||
img0031.nii.gz
|
||||
img0033.nii.gz
|
||||
img0034.nii.gz
|
||||
img0037.nii.gz
|
||||
img0039.nii.gz
|
||||
img0040.nii.gz
|
||||
```
|
||||
|
||||
val.txt
|
||||
|
||||
```none
|
||||
img0008.nii.gz
|
||||
img0022.nii.gz
|
||||
img0038.nii.gz
|
||||
img0036.nii.gz
|
||||
img0032.nii.gz
|
||||
img0002.nii.gz
|
||||
img0029.nii.gz
|
||||
img0003.nii.gz
|
||||
img0001.nii.gz
|
||||
img0004.nii.gz
|
||||
img0025.nii.gz
|
||||
img0035.nii.gz
|
||||
```
|
||||
|
||||
The contents of synapse datasets include:
|
||||
|
||||
```none
|
||||
├── Training
|
||||
│ ├── img
|
||||
│ │ ├── img0001.nii.gz
|
||||
│ │ ├── img0002.nii.gz
|
||||
│ │ ├── ...
|
||||
│ ├── label
|
||||
│ │ ├── label0001.nii.gz
|
||||
│ │ ├── label0002.nii.gz
|
||||
│ │ ├── ...
|
||||
│ ├── train.txt
|
||||
│ ├── val.txt
|
||||
```
|
||||
|
||||
Then, use this command to convert synapse dataset.
|
||||
|
||||
```shell
|
||||
python tools/dataset_converters/synapse.py --dataset-path /path/to/synapse
|
||||
```
|
||||
|
||||
Noted that MMSegmentation default evaluation metric (such as mean dice value) is calculated on 2D slice image,
|
||||
which is not comparable to results of 3D scan in some paper such as [TransUNet](https://arxiv.org/abs/2102.04306).
|
||||
|
@ -18,6 +18,7 @@ from .night_driving import NightDrivingDataset
|
||||
from .pascal_context import PascalContextDataset, PascalContextDataset59
|
||||
from .potsdam import PotsdamDataset
|
||||
from .stare import STAREDataset
|
||||
from .synapse import SynapseDataset
|
||||
# yapf: disable
|
||||
from .transforms import (CLAHE, AdjustGamma, BioMedical3DPad,
|
||||
BioMedical3DRandomCrop, BioMedicalGaussianBlur,
|
||||
@ -26,9 +27,9 @@ from .transforms import (CLAHE, AdjustGamma, BioMedical3DPad,
|
||||
LoadBiomedicalAnnotation, LoadBiomedicalData,
|
||||
LoadBiomedicalImageFromFile, LoadImageFromNDArray,
|
||||
PackSegInputs, PhotoMetricDistortion, RandomCrop,
|
||||
RandomCutOut, RandomMosaic, RandomRotate, Rerange,
|
||||
ResizeShortestEdge, ResizeToMultiple, RGB2Gray,
|
||||
SegRescale)
|
||||
RandomCutOut, RandomMosaic, RandomRotate,
|
||||
RandomRotFlip, Rerange, ResizeShortestEdge,
|
||||
ResizeToMultiple, RGB2Gray, SegRescale)
|
||||
from .voc import PascalVOCDataset
|
||||
|
||||
# yapf: enable
|
||||
@ -46,5 +47,6 @@ __all__ = [
|
||||
'LoadBiomedicalAnnotation', 'LoadBiomedicalData', 'GenerateEdge',
|
||||
'DecathlonDataset', 'LIPDataset', 'ResizeShortestEdge',
|
||||
'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur',
|
||||
'BioMedicalRandomGamma', 'BioMedical3DPad'
|
||||
'BioMedicalRandomGamma', 'BioMedical3DPad', 'RandomRotFlip',
|
||||
'SynapseDataset'
|
||||
]
|
||||
|
28
mmseg/datasets/synapse.py
Normal file
28
mmseg/datasets/synapse.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
from mmseg.registry import DATASETS
|
||||
from .basesegdataset import BaseSegDataset
|
||||
|
||||
|
||||
@DATASETS.register_module()
|
||||
class SynapseDataset(BaseSegDataset):
|
||||
"""Synapse dataset.
|
||||
|
||||
Before dataset preprocess of Synapse, there are total 13 categories of
|
||||
foreground which does not include background. After preprocessing, 8
|
||||
foreground categories are kept while the other 5 foreground categories are
|
||||
handled as background. The ``img_suffix`` is fixed to '.jpg' and
|
||||
``seg_map_suffix`` is fixed to '.png'.
|
||||
"""
|
||||
METAINFO = dict(
|
||||
classes=('background', 'aorta', 'gallbladder', 'left_kidney',
|
||||
'right_kidney', 'liver', 'pancreas', 'spleen', 'stomach'),
|
||||
palette=[[0, 0, 0], [0, 0, 255], [0, 255, 0], [255, 0, 0],
|
||||
[0, 255, 255], [255, 0, 255], [255, 255, 0], [60, 255, 255],
|
||||
[240, 240, 240]])
|
||||
|
||||
def __init__(self,
|
||||
img_suffix='.jpg',
|
||||
seg_map_suffix='.png',
|
||||
**kwargs) -> None:
|
||||
super().__init__(
|
||||
img_suffix=img_suffix, seg_map_suffix=seg_map_suffix, **kwargs)
|
@ -8,9 +8,9 @@ from .transforms import (CLAHE, AdjustGamma, BioMedical3DPad,
|
||||
BioMedical3DRandomCrop, BioMedicalGaussianBlur,
|
||||
BioMedicalGaussianNoise, BioMedicalRandomGamma,
|
||||
GenerateEdge, PhotoMetricDistortion, RandomCrop,
|
||||
RandomCutOut, RandomMosaic, RandomRotate, Rerange,
|
||||
ResizeShortestEdge, ResizeToMultiple, RGB2Gray,
|
||||
SegRescale)
|
||||
RandomCutOut, RandomMosaic, RandomRotate,
|
||||
RandomRotFlip, Rerange, ResizeShortestEdge,
|
||||
ResizeToMultiple, RGB2Gray, SegRescale)
|
||||
|
||||
# yapf: enable
|
||||
__all__ = [
|
||||
@ -20,5 +20,5 @@ __all__ = [
|
||||
'ResizeToMultiple', 'LoadImageFromNDArray', 'LoadBiomedicalImageFromFile',
|
||||
'LoadBiomedicalAnnotation', 'LoadBiomedicalData', 'GenerateEdge',
|
||||
'ResizeShortestEdge', 'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur',
|
||||
'BioMedicalRandomGamma', 'BioMedical3DPad'
|
||||
'BioMedicalRandomGamma', 'BioMedical3DPad', 'RandomRotFlip'
|
||||
]
|
||||
|
@ -861,6 +861,84 @@ class RandomCutOut(BaseTransform):
|
||||
return repr_str
|
||||
|
||||
|
||||
@TRANSFORMS.register_module()
|
||||
class RandomRotFlip(BaseTransform):
|
||||
"""Rotate and flip the image & seg or just rotate the image & seg.
|
||||
|
||||
Required Keys:
|
||||
|
||||
- img
|
||||
- gt_seg_map
|
||||
|
||||
Modified Keys:
|
||||
|
||||
- img
|
||||
- gt_seg_map
|
||||
|
||||
Args:
|
||||
rotate_prob (float): The probability of rotate image.
|
||||
flip_prob (float): The probability of rotate&flip image.
|
||||
degree (float, tuple[float]): Range of degrees to select from. If
|
||||
degree is a number instead of tuple like (min, max),
|
||||
the range of degree will be (``-degree``, ``+degree``)
|
||||
"""
|
||||
|
||||
def __init__(self, rotate_prob=0.5, flip_prob=0.5, degree=(-20, 20)):
|
||||
self.rotate_prob = rotate_prob
|
||||
self.flip_prob = flip_prob
|
||||
assert 0 <= rotate_prob <= 1 and 0 <= flip_prob <= 1
|
||||
if isinstance(degree, (float, int)):
|
||||
assert degree > 0, f'degree {degree} should be positive'
|
||||
self.degree = (-degree, degree)
|
||||
else:
|
||||
self.degree = degree
|
||||
assert len(self.degree) == 2, f'degree {self.degree} should be a ' \
|
||||
f'tuple of (min, max)'
|
||||
|
||||
def random_rot_flip(self, results: dict) -> dict:
|
||||
k = np.random.randint(0, 4)
|
||||
results['img'] = np.rot90(results['img'], k)
|
||||
for key in results.get('seg_fields', []):
|
||||
results[key] = np.rot90(results[key], k)
|
||||
axis = np.random.randint(0, 2)
|
||||
results['img'] = np.flip(results['img'], axis=axis).copy()
|
||||
for key in results.get('seg_fields', []):
|
||||
results[key] = np.flip(results[key], axis=axis).copy()
|
||||
return results
|
||||
|
||||
def random_rotate(self, results: dict) -> dict:
|
||||
angle = np.random.uniform(min(*self.degree), max(*self.degree))
|
||||
results['img'] = mmcv.imrotate(results['img'], angle=angle)
|
||||
for key in results.get('seg_fields', []):
|
||||
results[key] = mmcv.imrotate(results[key], angle=angle)
|
||||
return results
|
||||
|
||||
def transform(self, results: dict) -> dict:
|
||||
"""Call function to rotate or rotate & flip image, semantic
|
||||
segmentation maps.
|
||||
|
||||
Args:
|
||||
results (dict): Result dict from loading pipeline.
|
||||
|
||||
Returns:
|
||||
dict: Rotated or rotated & flipped results.
|
||||
"""
|
||||
rotate_flag = 0
|
||||
if random.random() < self.rotate_prob:
|
||||
results = self.random_rotate(results)
|
||||
rotate_flag = 1
|
||||
if random.random() < self.flip_prob and rotate_flag == 0:
|
||||
results = self.random_rot_flip(results)
|
||||
return results
|
||||
|
||||
def __repr__(self):
|
||||
repr_str = self.__class__.__name__
|
||||
repr_str += f'(rotate_prob={self.rotate_prob}, ' \
|
||||
f'flip_prob={self.flip_prob}, ' \
|
||||
f'degree={self.degree})'
|
||||
return repr_str
|
||||
|
||||
|
||||
@TRANSFORMS.register_module()
|
||||
class RandomMosaic(BaseTransform):
|
||||
"""Mosaic augmentation. Given 4 images, mosaic transform combines them into
|
||||
|
@ -6,8 +6,8 @@ from .class_names import (ade_classes, ade_palette, cityscapes_classes,
|
||||
get_palette, isaid_classes, isaid_palette,
|
||||
loveda_classes, loveda_palette, potsdam_classes,
|
||||
potsdam_palette, stare_classes, stare_palette,
|
||||
vaihingen_classes, vaihingen_palette, voc_classes,
|
||||
voc_palette)
|
||||
synapse_classes, synapse_palette, vaihingen_classes,
|
||||
vaihingen_palette, voc_classes, voc_palette)
|
||||
# yapf: enable
|
||||
from .collect_env import collect_env
|
||||
from .io import datafrombytes
|
||||
@ -27,5 +27,5 @@ __all__ = [
|
||||
'cityscapes_palette', 'ade_palette', 'voc_palette', 'cocostuff_palette',
|
||||
'loveda_palette', 'potsdam_palette', 'vaihingen_palette', 'isaid_palette',
|
||||
'stare_palette', 'dataset_aliases', 'get_classes', 'get_palette',
|
||||
'datafrombytes'
|
||||
'datafrombytes', 'synapse_palette', 'synapse_classes'
|
||||
]
|
||||
|
@ -265,6 +265,20 @@ def stare_palette():
|
||||
return [[120, 120, 120], [6, 230, 230]]
|
||||
|
||||
|
||||
def synapse_palette():
|
||||
"""Synapse palette for external use."""
|
||||
return [[0, 0, 0], [0, 0, 255], [0, 255, 0], [255, 0, 0], [0, 255, 255],
|
||||
[255, 0, 255], [255, 255, 0], [60, 255, 255], [240, 240, 240]]
|
||||
|
||||
|
||||
def synapse_classes():
|
||||
"""Synapse class names for external use."""
|
||||
return [
|
||||
'background', 'aorta', 'gallbladder', 'left_kidney', 'right_kidney',
|
||||
'liver', 'pancreas', 'spleen', 'stomach'
|
||||
]
|
||||
|
||||
|
||||
def lip_classes():
|
||||
"""LIP class names for external use."""
|
||||
return [
|
||||
|
BIN
tests/data/pseudo_synapse_dataset/ann_dir/case0005_slice000.png
Normal file
BIN
tests/data/pseudo_synapse_dataset/ann_dir/case0005_slice000.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 334 B |
BIN
tests/data/pseudo_synapse_dataset/ann_dir/case0005_slice001.png
Normal file
BIN
tests/data/pseudo_synapse_dataset/ann_dir/case0005_slice001.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 334 B |
BIN
tests/data/pseudo_synapse_dataset/img_dir/case0005_slice000.jpg
Normal file
BIN
tests/data/pseudo_synapse_dataset/img_dir/case0005_slice000.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
tests/data/pseudo_synapse_dataset/img_dir/case0005_slice001.jpg
Normal file
BIN
tests/data/pseudo_synapse_dataset/img_dir/case0005_slice001.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -9,7 +9,7 @@ import pytest
|
||||
from mmseg.datasets import (ADE20KDataset, BaseSegDataset, CityscapesDataset,
|
||||
COCOStuffDataset, DecathlonDataset, ISPRSDataset,
|
||||
LIPDataset, LoveDADataset, PascalVOCDataset,
|
||||
PotsdamDataset, iSAIDDataset)
|
||||
PotsdamDataset, SynapseDataset, iSAIDDataset)
|
||||
from mmseg.registry import DATASETS
|
||||
from mmseg.utils import get_classes, get_palette
|
||||
|
||||
@ -220,6 +220,19 @@ def test_vaihingen():
|
||||
assert len(test_dataset) == 1
|
||||
|
||||
|
||||
def test_synapse():
|
||||
test_dataset = SynapseDataset(
|
||||
pipeline=[],
|
||||
data_prefix=dict(
|
||||
img_path=osp.join(
|
||||
osp.dirname(__file__),
|
||||
'../data/pseudo_synapse_dataset/img_dir'),
|
||||
seg_map_path=osp.join(
|
||||
osp.dirname(__file__),
|
||||
'../data/pseudo_synapse_dataset/ann_dir')))
|
||||
assert len(test_dataset) == 2
|
||||
|
||||
|
||||
def test_isaid():
|
||||
test_dataset = iSAIDDataset(
|
||||
pipeline=[],
|
||||
|
@ -184,6 +184,68 @@ def test_flip():
|
||||
assert np.equal(original_seg, results['gt_semantic_seg']).all()
|
||||
|
||||
|
||||
def test_random_rotate_flip():
|
||||
with pytest.raises(AssertionError):
|
||||
transform = dict(type='RandomRotFlip', flip_prob=1.5)
|
||||
TRANSFORMS.build(transform)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
transform = dict(type='RandomRotFlip', rotate_prob=1.5)
|
||||
TRANSFORMS.build(transform)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
transform = dict(type='RandomRotFlip', degree=[20, 20, 20])
|
||||
TRANSFORMS.build(transform)
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
transform = dict(type='RandomRotFlip', degree=-20)
|
||||
TRANSFORMS.build(transform)
|
||||
|
||||
transform = dict(
|
||||
type='RandomRotFlip', flip_prob=1.0, rotate_prob=0, degree=20)
|
||||
rot_flip_module = TRANSFORMS.build(transform)
|
||||
|
||||
results = dict()
|
||||
img = mmcv.imread(
|
||||
osp.join(
|
||||
osp.dirname(__file__),
|
||||
'../data/pseudo_synapse_dataset/img_dir/case0005_slice000.jpg'),
|
||||
'color')
|
||||
original_img = copy.deepcopy(img)
|
||||
seg = np.array(
|
||||
Image.open(
|
||||
osp.join(
|
||||
osp.dirname(__file__),
|
||||
'../data/pseudo_synapse_dataset/ann_dir/case0005_slice000.png')
|
||||
))
|
||||
original_seg = copy.deepcopy(seg)
|
||||
results['img'] = img
|
||||
results['gt_semantic_seg'] = seg
|
||||
results['seg_fields'] = ['gt_semantic_seg']
|
||||
results['img_shape'] = img.shape
|
||||
results['ori_shape'] = img.shape
|
||||
# Set initial values for default meta_keys
|
||||
results['pad_shape'] = img.shape
|
||||
results['scale_factor'] = 1.0
|
||||
|
||||
result_flip = rot_flip_module(results)
|
||||
assert original_img.shape == result_flip['img'].shape
|
||||
assert original_seg.shape == result_flip['gt_semantic_seg'].shape
|
||||
|
||||
transform = dict(
|
||||
type='RandomRotFlip', flip_prob=0, rotate_prob=1.0, degree=20)
|
||||
rot_flip_module = TRANSFORMS.build(transform)
|
||||
|
||||
result_rotate = rot_flip_module(results)
|
||||
assert original_img.shape == result_rotate['img'].shape
|
||||
assert original_seg.shape == result_rotate['gt_semantic_seg'].shape
|
||||
|
||||
assert str(transform) == "{'type': 'RandomRotFlip'," \
|
||||
" 'flip_prob': 0," \
|
||||
" 'rotate_prob': 1.0," \
|
||||
" 'degree': 20}"
|
||||
|
||||
|
||||
def test_pad():
|
||||
# test assertion if both size_divisor and size is None
|
||||
with pytest.raises(AssertionError):
|
||||
|
155
tools/dataset_converters/synapse.py
Normal file
155
tools/dataset_converters/synapse.py
Normal file
@ -0,0 +1,155 @@
|
||||
# Copyright (c) OpenMMLab. All rights reserved.
|
||||
import argparse
|
||||
import os.path as osp
|
||||
|
||||
import nibabel as nib
|
||||
import numpy as np
|
||||
from mmengine.utils import mkdir_or_exist
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def read_files_from_txt(txt_path):
|
||||
with open(txt_path) as f:
|
||||
files = f.readlines()
|
||||
files = [file.strip() for file in files]
|
||||
return files
|
||||
|
||||
|
||||
def read_nii_file(nii_path):
|
||||
img = nib.load(nii_path).get_fdata()
|
||||
return img
|
||||
|
||||
|
||||
def split_3d_image(img):
|
||||
c, _, _ = img.shape
|
||||
res = []
|
||||
for i in range(c):
|
||||
res.append(img[i, :, :])
|
||||
return res
|
||||
|
||||
|
||||
def label_mapping(label):
|
||||
"""Label mapping from TransUNet paper setting. It only has 9 classes, which
|
||||
are 'background', 'aorta', 'gallbladder', 'left_kidney', 'right_kidney',
|
||||
'liver', 'pancreas', 'spleen', 'stomach', respectively. Other foreground
|
||||
classes in original dataset are all set to background.
|
||||
|
||||
More details could be found here: https://arxiv.org/abs/2102.04306
|
||||
"""
|
||||
maped_label = np.zeros_like(label)
|
||||
maped_label[label == 8] = 1
|
||||
maped_label[label == 4] = 2
|
||||
maped_label[label == 3] = 3
|
||||
maped_label[label == 2] = 4
|
||||
maped_label[label == 6] = 5
|
||||
maped_label[label == 11] = 6
|
||||
maped_label[label == 1] = 7
|
||||
maped_label[label == 7] = 8
|
||||
return maped_label
|
||||
|
||||
|
||||
def pares_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert synapse dataset to mmsegmentation format')
|
||||
parser.add_argument(
|
||||
'--dataset-path', type=str, help='synapse dataset path.')
|
||||
parser.add_argument(
|
||||
'--save-path',
|
||||
default='data/synapse',
|
||||
type=str,
|
||||
help='save path of the dataset.')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = pares_args()
|
||||
dataset_path = args.dataset_path
|
||||
save_path = args.save_path
|
||||
|
||||
if not osp.exists(dataset_path):
|
||||
raise ValueError('The dataset path does not exist. '
|
||||
'Please enter a correct dataset path.')
|
||||
if not osp.exists(osp.join(dataset_path, 'img')) \
|
||||
or not osp.exists(osp.join(dataset_path, 'label')):
|
||||
raise FileNotFoundError('The dataset structure is incorrect. '
|
||||
'Please check your dataset.')
|
||||
|
||||
train_id = read_files_from_txt(osp.join(dataset_path, 'train.txt'))
|
||||
train_id = [idx[3:7] for idx in train_id]
|
||||
|
||||
test_id = read_files_from_txt(osp.join(dataset_path, 'val.txt'))
|
||||
test_id = [idx[3:7] for idx in test_id]
|
||||
|
||||
mkdir_or_exist(osp.join(save_path, 'img_dir/train'))
|
||||
mkdir_or_exist(osp.join(save_path, 'img_dir/val'))
|
||||
mkdir_or_exist(osp.join(save_path, 'ann_dir/train'))
|
||||
mkdir_or_exist(osp.join(save_path, 'ann_dir/val'))
|
||||
|
||||
# It follows data preparation pipeline from here:
|
||||
# https://github.com/Beckschen/TransUNet/tree/main/datasets
|
||||
for i, idx in enumerate(train_id):
|
||||
img_3d = read_nii_file(
|
||||
osp.join(dataset_path, 'img', 'img' + idx + '.nii.gz'))
|
||||
label_3d = read_nii_file(
|
||||
osp.join(dataset_path, 'label', 'label' + idx + '.nii.gz'))
|
||||
|
||||
img_3d = np.clip(img_3d, -125, 275)
|
||||
img_3d = (img_3d + 125) / 400
|
||||
img_3d *= 255
|
||||
img_3d = np.transpose(img_3d, [2, 0, 1])
|
||||
img_3d = np.flip(img_3d, 2)
|
||||
|
||||
label_3d = np.transpose(label_3d, [2, 0, 1])
|
||||
label_3d = np.flip(label_3d, 2)
|
||||
label_3d = label_mapping(label_3d)
|
||||
|
||||
for c in range(img_3d.shape[0]):
|
||||
img = img_3d[c]
|
||||
label = label_3d[c]
|
||||
|
||||
img = Image.fromarray(img).convert('RGB')
|
||||
label = Image.fromarray(label).convert('L')
|
||||
img.save(
|
||||
osp.join(
|
||||
save_path, 'img_dir/train', 'case' + idx.zfill(4) +
|
||||
'_slice' + str(c).zfill(3) + '.jpg'))
|
||||
label.save(
|
||||
osp.join(
|
||||
save_path, 'ann_dir/train', 'case' + idx.zfill(4) +
|
||||
'_slice' + str(c).zfill(3) + '.png'))
|
||||
|
||||
for i, idx in enumerate(test_id):
|
||||
img_3d = read_nii_file(
|
||||
osp.join(dataset_path, 'img', 'img' + idx + '.nii.gz'))
|
||||
label_3d = read_nii_file(
|
||||
osp.join(dataset_path, 'label', 'label' + idx + '.nii.gz'))
|
||||
|
||||
img_3d = np.clip(img_3d, -125, 275)
|
||||
img_3d = (img_3d + 125) / 400
|
||||
img_3d *= 255
|
||||
img_3d = np.transpose(img_3d, [2, 0, 1])
|
||||
img_3d = np.flip(img_3d, 2)
|
||||
|
||||
label_3d = np.transpose(label_3d, [2, 0, 1])
|
||||
label_3d = np.flip(label_3d, 2)
|
||||
label_3d = label_mapping(label_3d)
|
||||
|
||||
for c in range(img_3d.shape[0]):
|
||||
img = img_3d[c]
|
||||
label = label_3d[c]
|
||||
|
||||
img = Image.fromarray(img).convert('RGB')
|
||||
label = Image.fromarray(label).convert('L')
|
||||
img.save(
|
||||
osp.join(
|
||||
save_path, 'img_dir/val', 'case' + idx.zfill(4) +
|
||||
'_slice' + str(c).zfill(3) + '.jpg'))
|
||||
label.save(
|
||||
osp.join(
|
||||
save_path, 'ann_dir/val', 'case' + idx.zfill(4) +
|
||||
'_slice' + str(c).zfill(3) + '.png'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user