-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathnoises.py
157 lines (122 loc) · 4.09 KB
/
noises.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""
Features for introducing noise to images.
This module provides classes to add various types of noise to images,
including constant offsets, Gaussian noise, and Poisson-distributed noise.
Module Structure
----------------
Classes:
- `Noise`: Abstract base class for noise models.
- `Background` / `Offset`: Adds a constant value to an image.
- `Gaussian`: Adds IID Gaussian noise.
- `ComplexGaussian`: Adds complex-valued Gaussian noise.
- `Poisson`: Adds Poisson-distributed noise based on signal-to-noise ratio.
Example
-------
Add Gaussian noise to an image:
>>> import numpy as np
>>> image = np.ones((100, 100))
>>> gaussian_noise = noises.Gaussian(mu=0, sigma=0.1)
>>> noisy_image = gaussian_noise.resolve(image)
Add Poisson noise with a specified signal-to-noise ratio:
>>> poisson_noise = noises.Poisson(snr=0.5)
>>> noisy_image = poisson_noise.resolve(image)
"""
import numpy as np
from .features import Feature
from .image import Image
from .types import PropertyLike
class Noise(Feature):
"""Base abstract noise class."""
class Background(Noise):
"""Adds a constant value to an image
Parameters
----------
offset : float
The value to add to the image
"""
def __init__(self, offset: PropertyLike[float], **kwargs):
super().__init__(offset=offset, **kwargs)
def get(self, image, offset, **kwargs):
return image + offset
# ALIASES
Offset = Background
class Gaussian(Noise):
"""Adds IID Gaussian noise to an image.
Parameters
----------
mu : float
The mean of the Gaussian distribution.
sigma : float
The standard deviation of the Gaussian distribution.
"""
def __init__(
self,
mu: PropertyLike[float] = 0,
sigma: PropertyLike[float] = 1,
**kwargs
):
super().__init__(mu=mu, sigma=sigma, **kwargs)
def get(self, image, mu, sigma, **kwargs):
noisy_image = mu + image + np.random.randn(*image.shape) * sigma
return noisy_image
class ComplexGaussian(Noise):
"""Adds complex-valued IID Gaussian noise to an image.
Parameters
----------
mu : float
The mean of the Gaussian distribution.
sigma : float
The standard deviation of the Gaussian distribution.
"""
def __init__(
self,
mu: PropertyLike[float] = 0,
sigma: PropertyLike[float] = 1,
**kwargs
):
super().__init__(mu=mu, sigma=sigma, **kwargs)
def get(self, image, mu, sigma, **kwargs):
real_noise = np.random.randn(*image.shape)
imag_noise = np.random.randn(*image.shape) * 1j
noisy_image = mu + image + (real_noise + imag_noise) * sigma
return noisy_image
class Poisson(Noise):
"""Adds Poisson-distributed noise to an image.
Parameters
----------
snr : float
Signal-to-noise ratio of the final image. The signal is determined
by the peak value of the image.
background : float
Value to be be used as the background. This is used to calculate the
signal of the image.
max_val : float, optional
Maximum allowable value to prevent overflow in noise computation.
Default is 1e8.
"""
def __init__(
self,
*args,
snr: PropertyLike[float] = 100,
background: PropertyLike[float] = 0,
max_val=1e8,
**kwargs
):
super().__init__(
*args, snr=snr, background=background, max_val=max_val, **kwargs
)
def get(self, image, snr, background, max_val, **kwargs):
image[image < 0] = 0
immax = np.max(image)
peak = np.abs(immax - background)
rescale = snr ** 2 / peak ** 2
rescale = np.clip(rescale, 1e-10, max_val / np.abs(immax))
try:
noisy_image = Image(np.random.poisson(image * rescale) / rescale)
noisy_image.merge_properties_from(image)
return noisy_image
except ValueError:
raise ValueError(
"Numpy poisson function errored due to too large value. "
"Set max_val in dt.Poisson to a lower value to fix."
)