Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add BioMedicalRandomGamma #2406

Merged
merged 38 commits into from
Jan 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f2b8d2f
doc
BLUE-coconut Nov 30, 2022
67b51b7
[Doc]Translate the 1_config.md and modify a wrong statement in 1_conf…
pofengdenihong Dec 2, 2022
4287fd2
Translate the 1_config.md and modify a wrong statement in 1_config.md
pofengdenihong Dec 2, 2022
5668182
modify part of content
BLUE-coconut Dec 3, 2022
ad470a3
Modify some expressions
pofengdenihong Dec 5, 2022
104a24d
changed parts of content
BLUE-coconut Dec 5, 2022
b0e57c6
Apply suggestions from code review
MeowZheng Dec 6, 2022
9750c97
Merge pull request #2371 from pofengdenihong/dev-1.x
MeowZheng Dec 6, 2022
3d1f8b7
modified
BLUE-coconut Dec 7, 2022
372a6ce
Update docs/zh_cn/user_guides/4_train_test.md
BLUE-coconut Dec 7, 2022
dc8aa35
CodeCamp #1562 [Doc] update `overview.md`
tianleiSHI Dec 10, 2022
dddf093
Update overview.md
tianleiSHI Dec 10, 2022
7edb141
Merge pull request #2355 from BLUE-coconut/master
MeowZheng Dec 12, 2022
d755707
Update docs/zh_cn/overview.md
tianleiSHI Dec 12, 2022
c2042f3
Update docs/zh_cn/overview.md
tianleiSHI Dec 12, 2022
7537987
Merge pull request #2397 from tianleiSHI/dev-1.x
MeowZheng Dec 12, 2022
58dcf57
Merge branch 'dev-1.x' of github.com:open-mmlab/mmsegmentation into d…
MeowZheng Jan 2, 2023
3b25d84
Merge branch 'dev-1.x' of github.com:open-mmlab/mmsegmentation into d…
MeowZheng Jan 2, 2023
bf6258a
Add torch1.13 in CI
xiexinch Dec 12, 2022
395d311
use mim install mm packages
xiexinch Dec 12, 2022
80ebe9a
install all requirements
xiexinch Dec 12, 2022
e592886
install wheel
xiexinch Dec 13, 2022
58dae2a
[Doc] Add ZN datasets.md in dev-1.x
MengzhangLI Dec 6, 2022
33dbf2c
add example project
xiexinch Dec 15, 2022
3eec9ea
add version limits
xiexinch Dec 20, 2022
571c78f
[Again] add BioMedicalRandomGamma
Fivethousand5k Dec 12, 2022
e98c482
[Again] add BioMedicalRandomGamma
Fivethousand5k Dec 12, 2022
fc0d5a8
fix by meow
MeowZheng Jan 2, 2023
86e53a4
remove change
MeowZheng Jan 2, 2023
e1fbc6d
fix typo
MeowZheng Jan 2, 2023
d39ed80
ut
MeowZheng Jan 2, 2023
f0848ef
refine impl
MeowZheng Jan 2, 2023
9baec65
add docstring
MeowZheng Jan 2, 2023
6e0c593
solve conflict
MeowZheng Jan 2, 2023
cd41c64
remove modify
MeowZheng Jan 2, 2023
9bba014
Update tests/test_datasets/test_transform.py
MeowZheng Jan 2, 2023
17555ac
Update tests/test_datasets/test_transform.py
MeowZheng Jan 2, 2023
a12e5a6
Update mmseg/datasets/transforms/transforms.py
MeowZheng Jan 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/zh_cn/advanced_guides/datasets.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 数据集
# 数据集

在 MMSegmentation 算法库中, 所有 Dataset 类的功能有两个: 加载[预处理](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/en/user_guides/2_dataset_prepare.md) 之后的数据集的信息, 和将数据送入[数据集变换流水线](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/mmseg/datasets/basesegdataset.py#L141) 中, 进行[数据变换操作](https://github.com/open-mmlab/mmsegmentation/blob/dev-1.x/docs/zh_cn/advanced_guides/transforms.md). 加载的数据集信息包括两类: 元信息 (meta information), 数据集本身的信息, 例如数据集总共的类别, 和它们对应调色盘信息: 数据信息 (data information) 是指每组数据中图片和对应标签的路径. 下文中介绍了 MMSegmentation 1.x 中数据集的常用接口, 和 mmseg 数据集基类中数据信息加载与修改数据集类别的逻辑, 以及数据集与数据变换流水线 (pipeline) 的关系.

Expand Down
7 changes: 4 additions & 3 deletions mmseg/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
from .pascal_context import PascalContextDataset, PascalContextDataset59
from .potsdam import PotsdamDataset
from .stare import STAREDataset
# yapf: disable
from .transforms import (CLAHE, AdjustGamma, BioMedical3DRandomCrop,
BioMedicalGaussianBlur, BioMedicalGaussianNoise,
GenerateEdge, LoadAnnotations,
BioMedicalRandomGamma, GenerateEdge, LoadAnnotations,
LoadBiomedicalAnnotation, LoadBiomedicalData,
LoadBiomedicalImageFromFile, LoadImageFromNDArray,
PackSegInputs, PhotoMetricDistortion, RandomCrop,
Expand All @@ -30,7 +31,6 @@
from .voc import PascalVOCDataset

# yapf: enable

__all__ = [
'BaseSegDataset', 'BioMedical3DRandomCrop', 'CityscapesDataset',
'PascalVOCDataset', 'ADE20KDataset', 'PascalContextDataset',
Expand All @@ -44,5 +44,6 @@
'LoadImageFromNDArray', 'LoadBiomedicalImageFromFile',
'LoadBiomedicalAnnotation', 'LoadBiomedicalData', 'GenerateEdge',
'DecathlonDataset', 'LIPDataset', 'ResizeShortestEdge',
'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur'
'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur',
'BioMedicalRandomGamma'
]
8 changes: 5 additions & 3 deletions mmseg/datasets/transforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
# yapf: disable
from .transforms import (CLAHE, AdjustGamma, BioMedical3DRandomCrop,
BioMedicalGaussianBlur, BioMedicalGaussianNoise,
GenerateEdge, PhotoMetricDistortion, RandomCrop,
RandomCutOut, RandomMosaic, RandomRotate, Rerange,
BioMedicalRandomGamma, GenerateEdge,
PhotoMetricDistortion, RandomCrop, RandomCutOut,
RandomMosaic, RandomRotate, Rerange,
ResizeShortestEdge, ResizeToMultiple, RGB2Gray,
SegRescale)

Expand All @@ -18,5 +19,6 @@
'RGB2Gray', 'RandomCutOut', 'RandomMosaic', 'PackSegInputs',
'ResizeToMultiple', 'LoadImageFromNDArray', 'LoadBiomedicalImageFromFile',
'LoadBiomedicalAnnotation', 'LoadBiomedicalData', 'GenerateEdge',
'ResizeShortestEdge', 'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur'
'ResizeShortestEdge', 'BioMedicalGaussianNoise', 'BioMedicalGaussianBlur',
'BioMedicalRandomGamma'
]
119 changes: 119 additions & 0 deletions mmseg/datasets/transforms/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1686,3 +1686,122 @@ def __repr__(self):
repr_str += 'different_sigma_per_axis='\
f'{self.different_sigma_per_axis})'
return repr_str


@TRANSFORMS.register_module()
class BioMedicalRandomGamma(BaseTransform):
MeowZheng marked this conversation as resolved.
Show resolved Hide resolved
"""Using random gamma correction to process the biomedical image.

Modified from
https://github.com/MIC-DKFZ/batchgenerators/blob/master/batchgenerators/transforms/color_transforms.py#L132 # noqa:E501
With licence: Apache 2.0

Required Keys:

- img (np.ndarray): Biomedical image with shape (N, Z, Y, X),
N is the number of modalities, and data type is float32.

Modified Keys:
- img

Args:
prob (float): The probability to perform this transform. Default: 0.5.
gamma_range (Tuple[float]): Range of gamma values. Default: (0.5, 2).
invert_image (bool): Whether invert the image before applying gamma
augmentation. Default: False.
per_channel (bool): Whether perform the transform each channel
individually. Default: False
retain_stats (bool): Gamma transformation will alter the mean and std
of the data in the patch. If retain_stats=True, the data will be
transformed to match the mean and standard deviation before gamma
augmentation. Default: False.
"""

def __init__(self,
prob: float = 0.5,
gamma_range: Tuple[float] = (0.5, 2),
invert_image: bool = False,
per_channel: bool = False,
retain_stats: bool = False):
assert 0 <= prob and prob <= 1
assert isinstance(gamma_range, tuple) and len(gamma_range) == 2
assert isinstance(invert_image, bool)
assert isinstance(per_channel, bool)
assert isinstance(retain_stats, bool)
self.prob = prob
self.gamma_range = gamma_range
self.invert_image = invert_image
self.per_channel = per_channel
self.retain_stats = retain_stats

@cache_randomness
def _do_gamma(self):
"""Whether do adjust gamma for image."""
return np.random.rand() < self.prob

def _adjust_gamma(self, img: np.array):
"""Gamma adjustment for image.

Args:
img (np.array): Input image before gamma adjust.

Returns:
np.arrays: Image after gamma adjust.
"""

if self.invert_image:
img = -img

def _do_adjust(img):
if retain_stats_here:
img_mean = img.mean()
img_std = img.std()
if np.random.random() < 0.5 and self.gamma_range[0] < 1:
gamma = np.random.uniform(self.gamma_range[0], 1)
else:
gamma = np.random.uniform(
max(self.gamma_range[0], 1), self.gamma_range[1])
img_min = img.min()
img_range = img.max() - img_min # range
img = np.power(((img - img_min) / float(img_range + 1e-7)),
gamma) * img_range + img_min
if retain_stats_here:
img = img - img.mean()
img = img / (img.std() + 1e-8) * img_std
img = img + img_mean
return img

if not self.per_channel:
retain_stats_here = self.retain_stats
img = _do_adjust(img)
else:
for c in range(img.shape[0]):
img[c] = _do_adjust(img[c])
if self.invert_image:
img = -img
return img

def transform(self, results: dict) -> dict:
"""Call function to perform random gamma correction
Args:
results (dict): Result dict from loading pipeline.

Returns:
dict: Result dict with random gamma correction performed.
"""
do_gamma = self._do_gamma()

if do_gamma:
results['img'] = self._adjust_gamma(results['img'])
else:
pass
return results

def __repr__(self):
repr_str = self.__class__.__name__
repr_str += f'(prob={self.prob}, '
repr_str += f'gamma_range={self.gamma_range},'
repr_str += f'invert_image={self.invert_image},'
repr_str += f'per_channel={self.per_channel},'
repr_str += f'retain_stats={self.retain_stats}'
return repr_str
67 changes: 66 additions & 1 deletion tests/test_datasets/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from PIL import Image

from mmseg.datasets.transforms import * # noqa
from mmseg.datasets.transforms import PhotoMetricDistortion, RandomCrop
from mmseg.datasets.transforms import (LoadBiomedicalImageFromFile,
PhotoMetricDistortion, RandomCrop)
from mmseg.registry import TRANSFORMS
from mmseg.utils import register_all_modules

Expand Down Expand Up @@ -886,3 +887,67 @@ def test_biomedical_gaussian_blur():
# the max value in the smoothed image should be less than the original one
assert original_img.max() >= results['img'].max()
assert original_img.min() <= results['img'].min()


def test_BioMedicalRandomGamma():
MeowZheng marked this conversation as resolved.
Show resolved Hide resolved

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma', prob=-1, gamma_range=(0.7, 1.2))
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma', prob=1.2, gamma_range=(0.7, 1.2))
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma', prob=1.0, gamma_range=(0.7))
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma',
prob=1.0,
gamma_range=(0.7, 0.2, 0.3))
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma',
prob=1.0,
gamma_range=(0.7, 2),
invert_image=1)
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma',
prob=1.0,
gamma_range=(0.7, 2),
per_channel=1)
TRANSFORMS.build(transform)

with pytest.raises(AssertionError):
transform = dict(
type='BioMedicalRandomGamma',
prob=1.0,
gamma_range=(0.7, 2),
retain_stats=1)
TRANSFORMS.build(transform)

test_img = 'tests/data/biomedical.nii.gz'
results = dict(img_path=test_img)
transform = LoadBiomedicalImageFromFile()
results = transform(copy.deepcopy(results))
origin_img = results['img']
transform2 = dict(
type='BioMedicalRandomGamma',
prob=1.0,
gamma_range=(0.7, 2),
)
transform2 = TRANSFORMS.build(transform2)
results = transform2(results)
transformed_img = results['img']
assert origin_img.shape == transformed_img.shape