Passed
Push — master ( c3d045...3525ae )
by Konstantinos
01:55 queued 43s
created

test_adding_noise_to_content_image   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 306
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 192
dl 0
loc 306
rs 10
c 0
b 0
f 0
wmc 14

7 Functions

Rating   Name   Duplication   Size   Complexity  
A test_prod_noise() 0 44 1
B test_numpy_random_generator_stochastic_process_is_reproducable() 0 48 1
A test_adding_noise_results_in_random_image() 0 34 2
A test_changing_seeds_prod_noise() 0 53 1
A test_verify_if_production_uses_the_same_seed_on_restart() 0 4 1
A prod_read_image_from_disk() 0 26 3
B test_adding_noise_with_the_same_seed_results_in_same_image() 0 75 5
1
import pytest
2
3
# TEST that when adding random noise to the same image, twice in a row, the
4
# result is different
5
def test_adding_noise_results_in_random_image(
6
    test_suite,
7
):
8
    import typing as t
9
    from numpy.typing import NDArray
10
    from pathlib import Path
11
    
12
    # CONSTANTS #
13
    expected_content_image_shape = (
14
        225,  # Height
15
        300,  # Width
16
        3,
17
    )
18
    # GIVEN an "original" Content Image
19
    import imageio
20
    canoe_content_image: Path = Path(test_suite) / 'data' / 'canoe_water_w300-h225.jpg'
21
    
22
    content_image: NDArray = imageio.imread(canoe_content_image)
23
    assert content_image.shape == expected_content_image_shape
24
25
    # GIVEN an "Add Random Noise Operation"
26
    from artificial_artwork.image import noisy
27
    NOISY_RATIO: float = 0.6
28
    apply_noise: t.Callable[[NDArray], NDArray] = lambda matrix_array: noisy(matrix_array, NOISY_RATIO)
29
30
    # WHEN we add random noise to the "original" Content Image, twice in a row
31
    # noisy_content_image_matrix = self.apply_noise(self.nst_algorithm.parameters.content_image.matrix)
32
    first_noisy_content_image_matrix = apply_noise(content_image)
33
    second_noisy_content_image_matrix = apply_noise(content_image)
34
35
    # THEN 2 new Images are produced, and they are different
36
    assert first_noisy_content_image_matrix.shape == expected_content_image_shape
37
    assert second_noisy_content_image_matrix.shape == expected_content_image_shape
38
    assert not (first_noisy_content_image_matrix == second_noisy_content_image_matrix).all()
39
40
41
def test_numpy_random_generator_stochastic_process_is_reproducable():
42
    import numpy as np
43
    # Expected 1st Sample from RNG with seed 1234
44
    expected_array_1 = np.array([
45
        [[19.067991, -4.7921705, 16.92985],
46
            [-9.532303, -7.236118, -15.276351],
47
            [-10.329349, -7.2586427, 18.56317]],
48
        [[-9.454008, -2.359755, 4.3948326],
49
            [14.544852, 14.550307, 6.9952526],
50
            [6.3949738, 9.430308, -11.089853]]
51
    ], dtype='float32')
52
    # Expected 2nd Sample from RNG with seed 1234
53
    expected_array_2 = np.array([
54
        [[-13.1173525, 14.816599, -17.594454],
55
            [7.3475566, 6.8495207, 4.440719],
56
            [-17.594507, 19.110771, -2.4419348]],
57
        [[  1.3038008, -19.874708 ,  -9.949316 ],
58
            [ 14.339618 ,  -2.988066 ,   9.432759 ],
59
            [ 16.88173  , -13.861033 ,  19.690369 ]]
60
    ], dtype='float32')
61
62
    expected_image_shape = (
63
        2,  # Height
64
        3,  # Width
65
        3,  # color channels
66
    )
67
    seed: int = 1234
68
    rng1 = np.random.default_rng(seed=seed)
69
    # rng = np.random.default_rng()
70
    random_noise_image_11 = rng1.uniform(-20, 20, expected_image_shape).astype('float32')
71
72
    assert expected_array_1.shape == expected_image_shape
73
    assert random_noise_image_11.shape == expected_image_shape
74
    assert (random_noise_image_11 == expected_array_1).all()
75
76
    # Verify second RNG 1st sample is DIFFERENT than first RNG 1st sample
77
    rng2 = np.random.default_rng(seed=seed + 1)
78
    random_noise_image_21 = rng2.uniform(-20, 20, expected_image_shape).astype('float32')
79
    assert random_noise_image_21.shape == expected_image_shape
80
    assert not (random_noise_image_21 == expected_array_1).all()
81
82
    assert not (random_noise_image_21 == random_noise_image_11).all()
83
84
    # Take second sample and verify it is the expected 2nd Sample from RNG 1234
85
    random_noise_image_12 = rng1.uniform(-20, 20, expected_image_shape).astype('float32')
86
    assert random_noise_image_12.shape == expected_image_shape
87
    assert not (random_noise_image_12 == expected_array_1).all()
88
    assert (random_noise_image_12 == expected_array_2).all()
89
90
91
def test_verify_if_production_uses_the_same_seed_on_restart():
92
93
    # GIVEN a "seed" value
94
    seed: int = 1234
95
96
    # WHEN we add random noise to the "original" Content Image, twice in a row
97
    # noisy_content_image_matrix = self.apply_noise(self.nst_algorithm.parameters.content_image.matrix)
98
99
@pytest.fixture
100
def prod_read_image_from_disk():
101
    import typing as t
102
    import numpy as np
103
    from numpy.typing import NDArray
104
    from artificial_artwork.image.image_operations import (
105
        reshape_image,
106
        subtract,
107
    )
108
    from artificial_artwork.image.image_factory import ImageFactory
109
    from artificial_artwork.disk_operations import Disk
110
111
    def _prod_read_image_from_disk(image_path: str) -> NDArray:
112
        means = np.array([123.68, 116.779, 103.939]).reshape((1,1,1,3))  # means
113
        image_fct = ImageFactory(
114
            Disk.load_image,
115
        )
116
        prod_preprocessing_pipeline = [
117
            lambda x: reshape_image(x, ((1,) + x.shape)),
118
            lambda x: subtract(x, means),
119
        ]
120
        img_wrapper = image_fct.from_disk(image_path, prod_preprocessing_pipeline)
121
        # file_path: str
122
        # matrix: NDArray
123
        return img_wrapper.matrix
124
    return _prod_read_image_from_disk
125
126
127
# TEST that the first operation to add random noise to an image results to the
128
# same prerecorded generated-with-noise image produced with the same seed
129
def test_adding_noise_with_the_same_seed_results_in_same_image(
130
    test_suite,
131
    prod_read_image_from_disk,
132
):
133
    import typing as t
134
    from numpy.typing import NDArray
135
    from pathlib import Path
136
    import numpy as np
137
    rng = np.random.default_rng(seed=42)
138
139
    # CONSTANTS #
140
    expected_content_image_shape = (
141
        225,  # Height
142
        300,  # Width
143
        3,
144
    )
145
    # GIVEN the Noisy Content Image of Running the Production Demo on process A
146
    noisy_canoe_content_image_v1: Path = Path(test_suite) / 'data' / 'demo-image-noisy-iter-1-1234_v1.png'
147
    # noisy_content_image_v1: NDArray = imageio.imread(noisy_canoe_content_image_v1)
148
    noisy_content_image_v1: NDArray = prod_read_image_from_disk(noisy_canoe_content_image_v1)
149
    # GIVEN the Noisy Content Image of Running the Production Demo on process B
150
    noisy_canoe_content_image_v2: Path = Path(test_suite) / 'data' / 'demo-image-noisy-iter-1-1234_v2.png'
151
    # noisy_content_image_v2: NDArray = imageio.imread(noisy_canoe_content_image_v2)
152
    noisy_content_image_v2: NDArray = prod_read_image_from_disk(noisy_canoe_content_image_v2)
153
154
    # THEN since the Production RNG uses initializes a Stochastic Process with default Seed 1234
155
    # THEN the Noisy Content Image of Running the Production Demo on process A
156
    # is the same as the Noisy Content Image of Running the Production Demo on process B
157
    assert (noisy_content_image_v1 == noisy_content_image_v2).all()
158
159
    # GIVEN a "seed" value
160
    PROD_DEFAULT_SEED = 1234
161
162
    # GIVEN an "Add Random Noise Operation"
163
    from artificial_artwork.image.image_operations import ImageNoiseAdder
164
    noise_adder = ImageNoiseAdder(seed=PROD_DEFAULT_SEED)
165
    PROD_DEFAULT_NOISY_RATIO: float = 0.6
166
    apply_noise = lambda x: noise_adder(x, PROD_DEFAULT_NOISY_RATIO)
167
168
    # GIVEN an "original" Content Image
169
    canoe_content_image: Path = Path(test_suite) / 'data' / 'canoe_water_w300-h225.jpg'
170
    content_image: NDArray = prod_read_image_from_disk(canoe_content_image)
171
172
    assert content_image.shape == (1,) + expected_content_image_shape
173
174
    # WHEN we add random noise to the "original" Content Image, twice in a row
175
    # noisy_content_image_matrix = self.apply_noise(self.nst_algorithm.parameters.content_image.matrix)
176
    first_noisy_content_image_matrix = apply_noise(content_image)
177
    second_noisy_content_image_matrix = apply_noise(content_image)
178
179
    # assert first_noisy_content_image_matrix.shape == expected_content_image_shape
180
    # assert second_noisy_content_image_matrix.shape == expected_content_image_shape
181
182
    # THEN 2 new Images are produced, and they are different
183
    assert not (first_noisy_content_image_matrix == second_noisy_content_image_matrix).all()
184
185
    # THEN the first noisy image is the same as the prerecorded generated-with-noise image
186
    # produced with the same seed
187
    from artificial_artwork.image.image_operations import convert_to_uint8
188
    # if we have shape of form (1, Width, Height, Number_of_Color_Channels)
189
    if first_noisy_content_image_matrix.ndim == 4 and first_noisy_content_image_matrix.shape[0] == 1:
190
        import numpy as np
191
        # reshape to (Width, Height, Number_of_Color_Channels)
192
        first_noisy_content_image_matrix = np.reshape(first_noisy_content_image_matrix, tuple(first_noisy_content_image_matrix.shape[1:]))
193
    if str(first_noisy_content_image_matrix.dtype) != 'uint8':
194
        first_noisy_content_image_matrix = convert_to_uint8(first_noisy_content_image_matrix)
195
196
    from artificial_artwork.disk_operations import Disk
197
    ppath = '/tmp/nst-unit-test-image.png'
198
    Disk.save_image(first_noisy_content_image_matrix,
199
        ppath, save_format='png')
200
    first_noisy_content_image_matrix: NDArray = prod_read_image_from_disk(ppath)
201
202
    assert first_noisy_content_image_matrix.shape == noisy_content_image_v1.shape
203
    assert (first_noisy_content_image_matrix == noisy_content_image_v1).all()
204
205
206
def test_prod_noise():
207
    import numpy as np
208
    from artificial_artwork.image.image_operations import ImageNoiseAdder
209
210
    # Expected 1st Sample from RNG with seed 1234
211
    expected_array_1 = np.array([
212
        [[19.067991, -4.7921705, 16.92985],
213
            [-9.532303, -7.236118, -15.276351],
214
            [-10.329349, -7.2586427, 18.56317]],
215
        [[-9.454008, -2.359755, 4.3948326],
216
            [14.544852, 14.550307, 6.9952526],
217
            [6.3949738, 9.430308, -11.089853]]
218
    ], dtype='float32')
219
    # Expected 2nd Sample from RNG with seed 1234
220
    expected_array_2 = np.array([
221
        [[-13.1173525, 14.816599, -17.594454],
222
            [7.3475566, 6.8495207, 4.440719],
223
            [-17.594507, 19.110771, -2.4419348]],
224
        [[  1.3038008, -19.874708 ,  -9.949316 ],
225
            [ 14.339618 ,  -2.988066 ,   9.432759 ],
226
            [ 16.88173  , -13.861033 ,  19.690369 ]]
227
    ], dtype='float32')
228
229
    expected_image_shape = (
230
        2,  # Height
231
        3,  # Width
232
        3,  # color channels
233
    )
234
    seed: int = 1234
235
236
    rng = ImageNoiseAdder(seed=seed)._default_rng
237
238
    random_noise_image_11 = rng(-20, 20, expected_image_shape)
239
240
    assert expected_array_1.shape == expected_image_shape
241
    assert random_noise_image_11.shape == expected_image_shape
242
    assert (random_noise_image_11 == expected_array_1).all()
243
244
    # Take second sample and verify it is the expected 2nd Sample from RNG 1234
245
    random_noise_image_12 = rng(-20, 20, expected_image_shape)
246
247
    assert random_noise_image_12.shape == expected_image_shape
248
    assert not (random_noise_image_12 == expected_array_1).all()
249
    assert (random_noise_image_12 == expected_array_2).all()
250
251
252
253
def test_changing_seeds_prod_noise():
254
    import numpy as np
255
    from artificial_artwork.image.image_operations import ImageNoiseAdder
256
257
    # Expected 1st Sample from RNG with seed 1234
258
    expected_array_1 = np.array([
259
        [[19.067991, -4.7921705, 16.92985],
260
            [-9.532303, -7.236118, -15.276351],
261
            [-10.329349, -7.2586427, 18.56317]],
262
        [[-9.454008, -2.359755, 4.3948326],
263
            [14.544852, 14.550307, 6.9952526],
264
            [6.3949738, 9.430308, -11.089853]]
265
    ], dtype='float32')
266
    # Expected 2nd Sample from RNG with seed 1234
267
    expected_array_2 = np.array([
268
        [[-13.1173525, 14.816599, -17.594454],
269
            [7.3475566, 6.8495207, 4.440719],
270
            [-17.594507, 19.110771, -2.4419348]],
271
        [[  1.3038008, -19.874708 ,  -9.949316 ],
272
            [ 14.339618 ,  -2.988066 ,   9.432759 ],
273
            [ 16.88173  , -13.861033 ,  19.690369 ]]
274
    ], dtype='float32')
275
276
    expected_image_shape = (
277
        2,  # Height
278
        3,  # Width
279
        3,  # color channels
280
    )
281
    seed: int = 1234
282
283
    rng = ImageNoiseAdder(seed=seed)._default_rng
284
285
    random_noise_image_11 = rng(-20, 20, expected_image_shape)
286
287
    assert expected_array_1.shape == expected_image_shape
288
    assert random_noise_image_11.shape == expected_image_shape
289
    assert (random_noise_image_11 == expected_array_1).all()
290
291
    # use infra to configure RNG with the seed
292
    # rng2 = ImageNoiseAdder._create_rng(seed=seed+1)
293
294
    # use infra to configure RNG with Previous Seed
295
    rng1 = ImageNoiseAdder._create_rng(seed=seed)
296
297
    # Take second sample from RNG 1
298
    random_noise_image_12 = rng1(-20, 20, expected_image_shape)
299
300
    assert random_noise_image_12.shape == expected_image_shape
301
    assert not (random_noise_image_12 == expected_array_2).all()    
302
303
    random_noise_image_13 = rng(-20, 20, expected_image_shape)
304
    assert random_noise_image_13.shape == expected_image_shape
305
    assert (random_noise_image_13 == expected_array_2).all()    
306