-
Notifications
You must be signed in to change notification settings - Fork 35
/
color.py
137 lines (102 loc) · 3.55 KB
/
color.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from typing import Any, Dict, Tuple, Union
import numpy as np
import torch
from fuse.data.ops.op_base import OpBase
from fuse.utils.ndict import NDict
from fuseimg.data.ops.ops_common_imaging import OpApplyTypesImaging
from fuseimg.utils.typing.key_types_imaging import DataTypeImaging
class OpClip(OpBase):
"""
Clip values - support both torch tensor and numpy array
"""
def __init__(self, **kwargs: Dict[str, Any]):
super().__init__(**kwargs)
def __call__(
self,
sample_dict: NDict,
key: str,
clip: Tuple[float, float] = (0.0, 1.0),
) -> NDict:
"""
Clip values
:param key: key to an image in sample_dict: either torch tensor or numpy array and any dimension
:param clip: values for clipping from both sides
"""
img = sample_dict[key]
processed_img = self.clip(img, clip)
sample_dict[key] = processed_img
return sample_dict
@staticmethod
def clip(
img: Union[np.ndarray, torch.Tensor], clip: Tuple[float, float] = (0.0, 1.0)
) -> Union[np.ndarray, torch.Tensor]:
if isinstance(img, np.ndarray):
processed_img = np.clip(img, clip[0], clip[1])
elif isinstance(img, torch.Tensor):
processed_img = torch.clamp(img, clip[0], clip[1], out=img)
else:
raise Exception(f"Error: unexpected type {type(img)}")
return processed_img
op_clip_img = OpApplyTypesImaging({DataTypeImaging.IMAGE: (OpClip(), {})})
class OpNormalizeAgainstSelf(OpBase):
"""
normalizes a tensor into [0.0, 1.0] using its own statistics (NOT against a dataset)
"""
def __init__(self, **kwargs: dict):
super().__init__(**kwargs)
def __call__(self, sample_dict: NDict, key: str) -> NDict:
img = sample_dict[key].astype(np.float32)
img -= img.min()
img = img / img.max()
sample_dict[key] = img
return sample_dict
op_normalize_against_self_img = OpApplyTypesImaging(
{DataTypeImaging.IMAGE: (OpNormalizeAgainstSelf(), {})}
)
class OpToIntImageSpace(OpBase):
"""
normalizes a tensor into [0, 255] int gray-scale using its own statistics (NOT against a dataset)
"""
def __init__(self, **kwargs: dict):
super().__init__(**kwargs)
def __call__(
self,
sample_dict: NDict,
key: str,
) -> NDict:
img = sample_dict[key]
img -= img.min()
img /= img.max()
img *= 255.0
img = img.astype(np.uint8).copy()
# img = img.transpose((1, 2, 0))
sample_dict[key] = img
return sample_dict
op_to_int_image_space_img = OpApplyTypesImaging(
{DataTypeImaging.IMAGE: (OpToIntImageSpace(), {})}
)
class OpToRange(OpBase):
"""
linearly project from a range to a different range
"""
def __call__(
self,
sample_dict: NDict,
key: str,
from_range: Tuple[float, float],
to_range: Tuple[float, float],
) -> NDict:
from_range_start = from_range[0]
from_range_end = from_range[1]
to_range_start = to_range[0]
to_range_end = to_range[1]
img = sample_dict[key]
# shift to start at 0
img -= from_range_start
# scale to be in desired range
img *= (to_range_end - to_range_start) / (from_range_end - from_range_start)
# shift to start in desired start val
img += to_range_start
sample_dict[key] = img
return sample_dict
op_to_range_img = OpApplyTypesImaging({DataTypeImaging.IMAGE: (OpToRange(), {})})