-
Notifications
You must be signed in to change notification settings - Fork 1
/
settings.py
314 lines (249 loc) · 11.2 KB
/
settings.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
"""
This module provides <class Settings> only contains parameters that video processing requires.
Their description is
loud_speed - speed of loud parts of video/audio.
quiet_speed - speed of quiet parts of video/audio.
global_speed - multiplies loud_speed and quiet_speed.
min_quiet_time - the program doesn't accelerate the first min_quiet_time seconds in every boring piece.
max_quiet_time - in every boring video piece, the program skips part starting from max_quiet_time seconds.
sound_threshold - a threshold between loud sound and quiet sound.
Example of usage of Settings class
settings = Settings(min_quiet_time=1, quiet_speed=1)
And it contains apply_settings_to_interestingpartsarray method that takes interesting_parts_array
and returns modified according to all parameters interesting_parts_array and boring_parts_array
(Example of usage of this method:
new_interesting_parts_array, new_boring_parts_array = setting.apply_settings_to_interestingpartsarray(old_interesting_parts_array)
)
"""
# setting.py
import numbers
import numpy as np
from some_functions import str2error_message
SETTING_EXTENTION = "SVA_settings"
TRIVIAL_DICT = {
"global_speed": 1,
"loud_speed": 1,
"quiet_speed": 6,
"min_quiet_time": 0.25,
"max_quiet_time": 2,
"volume_coefficient": 1,
"quiet_volume_coefficient": 0.35,
"loud_volume_coefficient": 1,
"max_volume": 1,
"decrease": 1,
"brightness": 1,
"contras_ratio": 1,
"rotate_image": 0,
"inverted": False,
}
class Settings:
"""
Settings class provide ability to store settings data, to change it, to read and save from/to file,
convert that data to dict and from dict
argumets
you can specify either filepath either kwargs otherwise (if you specify both of them) excecption will be raised
----filepath - Settings will be read from file
----kwargs in format global_speed=value
loud_speed=value
...
inverted=value
some of them can be skipped
fields: self.
(float)
loud_speed - speed of loud parts of video/audio.
quiet_speed - speed of quiet parts of video/audio.
global_speed - multiplies loud_speed and quiet_speed.
min_quiet_time - the program doesn't accelerate the first min_quiet_time seconds in every boring piece.
max_quiet_time - in every boring video piece, the program skips part starting from max_quiet_time seconds.
sound_threshold - a threshold between loud sound and quiet sound.
# todo All parameter starting from here are not supported by video processing
quiet_volume_coefficient - multiply sound in quiet video parts # not supported yet
loud_volume_coefficient - multipld by sound in loud video parts # not supported yet
volume_coefficient - multiply quiet_volume_coefficient and loud_volume_coefficient # not supported yet
max_volume - maximal able volume of sound: all frames above this value will decreased to this volume # not supported yet
decrease - number to !decrease! image # not supported yet
brightness - number to make more bright # not supported yet
contras_ratio - number to make more bright # not supported yet
rotate_image (only 0, 1, 2, 3) - how many 90-turnes of video # not supported yet
inverted (bool) - is image reversed relative vertical axis # not supported yet
methods:
self.to_dict() - convert self to dict
self.save_to_file() - save self to file
self.set_X(value), self.get_X - set field X value and get field X
for all fields X
"""
def __init__(self, filepath="", **kwargs):
"""
If filepath is True, Settings will be read from file.
You can specify only one among (filepath, kwargs).
Filepath must be end by SETTING_EXTENTION.
Format of **kwargs is the same like format of self.to_dict()
"""
if filepath and kwargs:
err_msg = "Settings.__init__() takes filepath or kwargs\nfilepath = {}\nkwargs = {}\nwere given"
raise ValueError(err_msg.format(str(filepath), str(kwargs)))
filepath = filepath.strip()
if filepath and not filepath.endswith("." + SETTING_EXTENTION):
error = "'filepath' must ends with '{}', '{}' were given"
raise ValueError(error.format("." + SETTING_EXTENTION, filepath))
if filepath:
with open(filepath, "r") as file:
kwargs = eval("".join(file.readlines()))
for elem in TRIVIAL_DICT:
self.__dict__[elem] = kwargs.get(elem, TRIVIAL_DICT[elem])
for elem in kwargs:
if elem not in TRIVIAL_DICT:
err_msg = "'{}' is an invalid keyword argument for Settings()\nList of valid options {}"
raise TypeError(err_msg.format(elem, list(TRIVIAL_DICT.keys())))
def check_type_decorators_generator(excpected_type=numbers.Number):
def check_type_decorator(func):
def wrapper(self, arg1, *args, **kwargs):
if not isinstance(arg1, excpected_type):
msg = f"""function '{Settings.__name__}.{func.__name__}'
expected '{excpected_type.__name__}' type
(or inherited classes).
Type({arg1}) = '{type(arg1).__name__}' were given."""
raise TypeError(str2error_message(msg))
return func(self, arg1, *args, **kwargs)
return wrapper
return check_type_decorator
@check_type_decorators_generator()
def set_global_speed(self, value):
self.global_speed = abs(value)
def get_global_speed(self):
return self.global_speed
@check_type_decorators_generator()
def set_loud_speed(self, value):
self.loud_speed = abs(value)
def get_loud_speed(self):
return self.loud_speed
def get_real_loud_speed(self):
return self.loud_speed * self.global_speed
@check_type_decorators_generator()
def set_quiet_speed(self, value):
self.quiet_speed = abs(value)
def get_quiet_speed(self):
return self.quiet_speed
def get_real_quiet_speed(self):
return self.quiet_speed * self.global_speed
@check_type_decorators_generator()
def set_min_quiet_time(self, value):
self.min_quiet_time = abs(value)
def get_min_quiet_time(self):
return self.min_quiet_time
@check_type_decorators_generator()
def set_max_quiet_time(self, value):
self.max_quiet_time = abs(value)
def get_max_quiet_time(self):
return self.max_quiet_time
@check_type_decorators_generator()
def set_volume_coefficient(self, value):
self.volume_coefficient = abs(value)
def get_volume_coefficient(self):
return self.volume_coefficient
@check_type_decorators_generator()
def set_quiet_volume_coefficient(self, value):
self.quiet_volume_coefficient = abs(value)
def get_quiet_volume_coefficient(self):
return self.quiet_volume_coefficient
@check_type_decorators_generator()
def set_loud_volume_coefficient(self, value):
self.loud_volume_coefficient = abs(value)
def get_loud_volume_coefficient(self):
return self.loud_volume_coefficient
@check_type_decorators_generator()
def set_max_volume(self, value):
self.max_volume = abs(value)
def get_max_volume(self):
return self.max_volume
@check_type_decorators_generator()
def set_decrease(self, value):
self.decrease = abs(value)
def get_decrease(self):
return self.decrease
def get_brightness(self):
return self.brightness
@check_type_decorators_generator()
def set_brightness(self, value):
self.brightness = abs(value)
def get_contras_ratio(self):
return self.contras_ratio
@check_type_decorators_generator()
def set_contras_ratio(self, value):
if value <= 0:
return
self.contras_ratio = value
@check_type_decorators_generator(int)
def set_rotate_image(self, value):
self.rotate_image = value % 4
def get_rotate_image(self):
return self.rotate_image
def get_sound_threshold(self):
return self.sound_threshold
@check_type_decorators_generator(float)
def set_sound_threshold(self, value):
self.sound_threshold = value
@check_type_decorators_generator(bool)
def set_inverted(self, value):
self.inverted = value
def get_inverted(self):
return self.inverted
def full_dict(self):
"""convert self to dict
for inverse operation use smth = Settings(**dictionary)"""
rt = {}
for elem in TRIVIAL_DICT:
if self.__dict__[elem] != TRIVIAL_DICT[elem]:
rt[elem] = self.__dict__[elem]
return rt
def __getitem__(self, key):
return self.full_dict()[key]
def to_dict(self):
full_dict, part_dict = self.full_dict(), {}
for elem in full_dict:
if full_dict[elem] != TRIVIAL_DICT[elem]:
part_dict[elem] = full_dict[elem]
return part_dict
def __str__(self):
self_dict = self.to_dict()
temp = ", ".join(
["{} = {}".format(elem, self_dict[elem]) for elem in self_dict]
)
return "Settings({})".format(temp)
def save_to_file(self, filepath):
"""Save self to filepath"""
if not filepath.endswith("." + SETTING_EXTENTION):
filepath += "." + SETTING_EXTENTION
with open(filepath, "w") as file:
print("{}: {}".format(filepath, self.to_dict()))
file.write(str(self.to_dict()))
def is_trivial(self):
return not bool(self.to_dict())
def process_interestingpartsarray(self, interesting_parts):
"""
Changes lenght
:param interesting_parts: interesting parts at usual format
[[start_of_piece0, end_of_piece0], [start_of_piece1, end_of_piece1], [start_of_piece2, end_of_piece2]]
:return: new calculated interesting_parts_np_array and boring_parts_np_array in the same format
"""
min_q, max_q = self.get_min_quiet_time(), self.get_max_quiet_time()
begin_sound_indexes, end_sound_indexes = (
interesting_parts[:, 0],
interesting_parts[:, 1],
)
end_sound_indexes[:-1] += min_q
is_changing = begin_sound_indexes[1:] > end_sound_indexes[:-1]
begin_sound_indexes = begin_sound_indexes[np.hstack([True, is_changing])]
end_sound_indexes = end_sound_indexes[np.hstack([is_changing, True])]
interesting_parts = np.vstack([begin_sound_indexes, end_sound_indexes])
boring_parts_beginnings = np.hstack([0, end_sound_indexes[:-1]])
boring_parts_ends = np.minimum(
begin_sound_indexes,
boring_parts_beginnings + max_q - min_q,
)
boring_parts_ends[0] = np.minimum(
begin_sound_indexes[0],
boring_parts_beginnings[0] + self.get_max_quiet_time(),
)
boring_parts = np.vstack([boring_parts_beginnings, boring_parts_ends])
return interesting_parts.transpose((1, 0)), boring_parts.transpose((1, 0))