OTVision 0.6.4__py3-none-any.whl → 0.6.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. OTVision/abstraction/defaults.py +15 -0
  2. OTVision/application/config.py +475 -0
  3. OTVision/application/config_parser.py +280 -0
  4. OTVision/application/configure_logger.py +1 -1
  5. OTVision/application/detect/factory.py +1 -1
  6. OTVision/application/detect/update_detect_config_with_cli_args.py +2 -1
  7. OTVision/application/get_config.py +2 -1
  8. OTVision/application/get_current_config.py +1 -1
  9. OTVision/application/track/__init__.py +0 -0
  10. OTVision/application/track/get_track_cli_args.py +20 -0
  11. OTVision/application/track/update_current_track_config.py +42 -0
  12. OTVision/application/track/update_track_config_with_cli_args.py +52 -0
  13. OTVision/application/update_current_config.py +1 -1
  14. OTVision/config.py +61 -668
  15. OTVision/convert/convert.py +3 -3
  16. OTVision/detect/builder.py +27 -20
  17. OTVision/detect/cli.py +3 -3
  18. OTVision/detect/detected_frame_buffer.py +3 -0
  19. OTVision/detect/file_based_detect_builder.py +19 -0
  20. OTVision/detect/otdet.py +54 -1
  21. OTVision/detect/otdet_file_writer.py +3 -2
  22. OTVision/detect/rtsp_based_detect_builder.py +37 -0
  23. OTVision/detect/rtsp_input_source.py +199 -0
  24. OTVision/detect/timestamper.py +1 -1
  25. OTVision/detect/video_input_source.py +2 -1
  26. OTVision/detect/yolo.py +17 -1
  27. OTVision/domain/cli.py +31 -1
  28. OTVision/domain/current_config.py +1 -1
  29. OTVision/domain/object_detection.py +6 -1
  30. OTVision/domain/serialization.py +12 -0
  31. OTVision/domain/time.py +13 -0
  32. OTVision/helpers/files.py +14 -15
  33. OTVision/plugin/__init__.py +0 -0
  34. OTVision/plugin/yaml_serialization.py +20 -0
  35. OTVision/track/builder.py +132 -0
  36. OTVision/track/cli.py +128 -0
  37. OTVision/track/exporter/filebased_exporter.py +2 -1
  38. OTVision/track/id_generator.py +15 -0
  39. OTVision/track/model/track_exporter.py +2 -1
  40. OTVision/track/model/tracking_interfaces.py +6 -6
  41. OTVision/track/parser/frame_group_parser_plugins.py +35 -5
  42. OTVision/track/track.py +54 -133
  43. OTVision/track/tracker/filebased_tracking.py +8 -7
  44. OTVision/track/tracker/tracker_plugin_iou.py +14 -9
  45. OTVision/transform/transform.py +2 -2
  46. OTVision/version.py +1 -1
  47. otvision-0.6.5.dist-info/METADATA +182 -0
  48. {otvision-0.6.4.dist-info → otvision-0.6.5.dist-info}/RECORD +50 -33
  49. otvision-0.6.4.dist-info/METADATA +0 -49
  50. {otvision-0.6.4.dist-info → otvision-0.6.5.dist-info}/WHEEL +0 -0
  51. {otvision-0.6.4.dist-info → otvision-0.6.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,280 @@
1
+ from datetime import datetime, timedelta
2
+ from pathlib import Path
3
+
4
+ from OTVision.application.config import (
5
+ COL_WIDTH,
6
+ CONF,
7
+ CONVERT,
8
+ DATETIME_FORMAT,
9
+ DEFAULT_FILETYPE,
10
+ DELETE_INPUT,
11
+ DETECT,
12
+ DETECT_END,
13
+ DETECT_START,
14
+ EXPECTED_DURATION,
15
+ FLUSH_BUFFER_SIZE,
16
+ FONT,
17
+ FONT_SIZE,
18
+ FPS_FROM_FILENAME,
19
+ FRAME_WIDTH,
20
+ GUI,
21
+ HALF_PRECISION,
22
+ IMG,
23
+ IMG_SIZE,
24
+ INPUT_FPS,
25
+ IOU,
26
+ LOCATION_X,
27
+ LOCATION_Y,
28
+ LOG,
29
+ LOG_LEVEL_CONSOLE,
30
+ LOG_LEVEL_FILE,
31
+ NORMALIZED,
32
+ OUTPUT_FILETYPE,
33
+ OUTPUT_FPS,
34
+ OVERWRITE,
35
+ PATHS,
36
+ REFPTS,
37
+ ROTATION,
38
+ RUN_CHAINED,
39
+ SEARCH_SUBDIRS,
40
+ SIGMA_H,
41
+ SIGMA_IOU,
42
+ SIGMA_L,
43
+ START_TIME,
44
+ STREAM,
45
+ STREAM_NAME,
46
+ STREAM_SAVE_DIR,
47
+ STREAM_SOURCE,
48
+ T_MIN,
49
+ T_MISS_MAX,
50
+ TRACK,
51
+ TRANSFORM,
52
+ UNDISTORT,
53
+ VID,
54
+ WEIGHTS,
55
+ WINDOW,
56
+ YOLO,
57
+ Config,
58
+ ConvertConfig,
59
+ DetectConfig,
60
+ StreamConfig,
61
+ TrackConfig,
62
+ YoloConfig,
63
+ _DefaultFiletype,
64
+ _GuiConfig,
65
+ _GuiWindowConfig,
66
+ _LogConfig,
67
+ _TrackIouConfig,
68
+ _TransformConfig,
69
+ _UndistortConfig,
70
+ )
71
+ from OTVision.domain.serialization import Deserializer
72
+
73
+
74
+ class ConfigParser:
75
+
76
+ def __init__(self, deserializer: Deserializer) -> None:
77
+ self._deserialize = deserializer
78
+
79
+ def parse(self, file: Path) -> Config:
80
+ data = self._deserialize.deserialize(file)
81
+ return self.parse_from_dict(data)
82
+
83
+ def parse_from_dict(self, d: dict) -> Config:
84
+ log_dict = d.get(LOG)
85
+ default_filtetype_dict = d.get(DEFAULT_FILETYPE)
86
+ convert_dict = d.get(CONVERT)
87
+ detect_dict = d.get(DETECT)
88
+ track_dict = d.get(TRACK)
89
+ undistort_dict = d.get(UNDISTORT)
90
+ transform_dict = d.get(TRANSFORM)
91
+ gui_dict = d.get(GUI)
92
+ stream_config_dict = d.get(STREAM)
93
+
94
+ log_config = self.parse_log_config(log_dict) if log_dict else Config.log
95
+ default_filetype = (
96
+ self.parse_default_filetype(default_filtetype_dict)
97
+ if default_filtetype_dict
98
+ else Config.default_filetype
99
+ )
100
+ convert_config = (
101
+ self.parse_convert_config(convert_dict) if convert_dict else Config.convert
102
+ )
103
+ detect_config = (
104
+ self.parse_detect_config(detect_dict) if detect_dict else Config.detect
105
+ )
106
+ track_config = (
107
+ self.parse_track_config(track_dict) if track_dict else Config.track
108
+ )
109
+ undistort_config = (
110
+ self.parse_undistort_config(undistort_dict)
111
+ if undistort_dict
112
+ else Config.undistort
113
+ )
114
+ transform_config = (
115
+ self.parse_transform_config(transform_dict)
116
+ if transform_dict
117
+ else Config.transform
118
+ )
119
+ gui_config = self.parse_gui_config(gui_dict) if gui_dict else Config.gui
120
+ stream_config = None
121
+ if stream_config_dict is not None:
122
+ stream_config = self.parse_stream_config(stream_config_dict)
123
+
124
+ return Config(
125
+ log=log_config,
126
+ search_subdirs=d.get(SEARCH_SUBDIRS, Config.search_subdirs),
127
+ default_filetype=default_filetype,
128
+ convert=convert_config,
129
+ detect=detect_config,
130
+ track=track_config,
131
+ undistort=undistort_config,
132
+ transform=transform_config,
133
+ gui=gui_config,
134
+ stream=stream_config,
135
+ )
136
+
137
+ def parse_log_config(self, data: dict) -> _LogConfig:
138
+ return _LogConfig(
139
+ data.get(LOG_LEVEL_CONSOLE, _LogConfig.log_level_console),
140
+ data.get(LOG_LEVEL_FILE, _LogConfig.log_level_file),
141
+ )
142
+
143
+ def parse_default_filetype(self, data: dict) -> _DefaultFiletype:
144
+ return _DefaultFiletype(
145
+ data.get(VID, _DefaultFiletype.video),
146
+ data.get(IMG, _DefaultFiletype.image),
147
+ data.get(DETECT, _DefaultFiletype.detect),
148
+ data.get(TRACK, _DefaultFiletype.track),
149
+ data.get(REFPTS, _DefaultFiletype.refpts),
150
+ )
151
+
152
+ def parse_convert_config(self, data: dict) -> ConvertConfig:
153
+ sources = self.parse_sources(data.get(PATHS, []))
154
+ return ConvertConfig(
155
+ sources,
156
+ data.get(RUN_CHAINED, ConvertConfig.run_chained),
157
+ data.get(OUTPUT_FILETYPE, ConvertConfig.output_filetype),
158
+ data.get(INPUT_FPS, ConvertConfig.input_fps),
159
+ data.get(OUTPUT_FPS, ConvertConfig.output_fps),
160
+ data.get(FPS_FROM_FILENAME, ConvertConfig.fps_from_filename),
161
+ data.get(DELETE_INPUT, ConvertConfig.delete_input),
162
+ data.get(ROTATION, ConvertConfig.rotation),
163
+ data.get(OVERWRITE, ConvertConfig.overwrite),
164
+ )
165
+
166
+ def parse_sources(self, sources: list[str]) -> list[str]:
167
+ return [str(Path(source).expanduser()) for source in sources]
168
+
169
+ def parse_detect_config(self, data: dict) -> DetectConfig:
170
+ yolo_config_dict = data.get(YOLO)
171
+ yolo_config = (
172
+ self.parse_yolo_config(yolo_config_dict)
173
+ if yolo_config_dict
174
+ else DetectConfig.yolo_config
175
+ )
176
+ sources = self.parse_sources(data.get(PATHS, []))
177
+
178
+ expected_duration = data.get(EXPECTED_DURATION, None)
179
+ if expected_duration is not None:
180
+ expected_duration = timedelta(seconds=int(expected_duration))
181
+
182
+ start_time = self._parse_start_time(data)
183
+ return DetectConfig(
184
+ sources,
185
+ data.get(RUN_CHAINED, DetectConfig.run_chained),
186
+ yolo_config,
187
+ expected_duration,
188
+ data.get(OVERWRITE, DetectConfig.overwrite),
189
+ data.get(HALF_PRECISION, DetectConfig.half_precision),
190
+ start_time,
191
+ data.get(DETECT_START, DetectConfig.detect_start),
192
+ data.get(DETECT_END, DetectConfig.detect_end),
193
+ )
194
+
195
+ def parse_yolo_config(self, data: dict) -> YoloConfig:
196
+ return YoloConfig(
197
+ weights=data.get(WEIGHTS, YoloConfig.weights),
198
+ conf=data.get(CONF, YoloConfig.conf),
199
+ iou=data.get(IOU, YoloConfig.iou),
200
+ img_size=data.get(IMG_SIZE, YoloConfig.img_size),
201
+ normalized=data.get(NORMALIZED, YoloConfig.normalized),
202
+ )
203
+
204
+ @staticmethod
205
+ def _parse_start_time(d: dict) -> datetime | None:
206
+ if start_time := d.get(START_TIME, DetectConfig.start_time):
207
+ return datetime.strptime(start_time, DATETIME_FORMAT)
208
+ return start_time
209
+
210
+ def parse_track_config(self, data: dict) -> TrackConfig:
211
+ iou_config_dict = data.get(IOU)
212
+ iou_config = (
213
+ self.parse_track_iou_config(iou_config_dict)
214
+ if iou_config_dict
215
+ else TrackConfig.iou
216
+ )
217
+ sources = self.parse_sources(data.get(PATHS, []))
218
+
219
+ return TrackConfig(
220
+ sources,
221
+ data.get(RUN_CHAINED, TrackConfig.run_chained),
222
+ iou_config,
223
+ data.get(OVERWRITE, TrackConfig.overwrite),
224
+ )
225
+
226
+ def parse_track_iou_config(self, data: dict) -> _TrackIouConfig:
227
+ return _TrackIouConfig(
228
+ data.get(SIGMA_L, _TrackIouConfig.sigma_l),
229
+ data.get(SIGMA_H, _TrackIouConfig.sigma_h),
230
+ data.get(SIGMA_IOU, _TrackIouConfig.sigma_iou),
231
+ data.get(T_MIN, _TrackIouConfig.t_min),
232
+ data.get(T_MISS_MAX, _TrackIouConfig.t_miss_max),
233
+ )
234
+
235
+ def parse_undistort_config(self, data: dict) -> _UndistortConfig:
236
+ return _UndistortConfig(
237
+ data.get(OVERWRITE, _UndistortConfig.overwrite),
238
+ )
239
+
240
+ def parse_transform_config(self, d: dict) -> _TransformConfig:
241
+ sources = self.parse_sources(d.get(PATHS, []))
242
+ return _TransformConfig(
243
+ sources,
244
+ d.get(RUN_CHAINED, _TransformConfig.run_chained),
245
+ d.get(OVERWRITE, _TransformConfig.overwrite),
246
+ )
247
+
248
+ def parse_gui_config(self, data: dict) -> _GuiConfig:
249
+ window_config_dict = data.get(WINDOW)
250
+ window_config = (
251
+ self.parse_gui_window_config(window_config_dict)
252
+ if window_config_dict
253
+ else _GuiConfig.window_config
254
+ )
255
+
256
+ return _GuiConfig(
257
+ font=data.get(FONT, _GuiConfig.font),
258
+ font_size=data.get(FONT_SIZE, _GuiConfig.font_size),
259
+ window_config=window_config,
260
+ frame_width=data.get(FRAME_WIDTH, _GuiConfig.frame_width),
261
+ col_width=data.get(COL_WIDTH, _GuiConfig.col_width),
262
+ )
263
+
264
+ def parse_gui_window_config(self, data: dict) -> _GuiWindowConfig:
265
+ return _GuiWindowConfig(
266
+ data.get(LOCATION_X, _GuiWindowConfig.location_x),
267
+ data.get(LOCATION_Y, _GuiWindowConfig.location_y),
268
+ )
269
+
270
+ def parse_stream_config(self, data: dict) -> StreamConfig:
271
+ name = data[STREAM_NAME]
272
+ source = data[STREAM_SOURCE]
273
+ save_dir = Path(data[STREAM_SAVE_DIR])
274
+ flush_buffer_size = int(data[FLUSH_BUFFER_SIZE])
275
+ return StreamConfig(
276
+ name=name,
277
+ source=source,
278
+ save_dir=save_dir,
279
+ flush_buffer_size=flush_buffer_size,
280
+ )
@@ -2,7 +2,7 @@ import logging
2
2
  from logging import Logger
3
3
  from pathlib import Path
4
4
 
5
- from OTVision.config import Config
5
+ from OTVision.application.config import Config
6
6
  from OTVision.helpers.log import LOGGER_NAME, log
7
7
 
8
8
 
@@ -1,4 +1,4 @@
1
- from OTVision.config import DetectConfig
1
+ from OTVision.application.config import DetectConfig
2
2
  from OTVision.domain.object_detection import ObjectDetector, ObjectDetectorFactory
3
3
 
4
4
 
@@ -1,5 +1,5 @@
1
+ from OTVision.application.config import Config, DetectConfig, YoloConfig, _LogConfig
1
2
  from OTVision.application.detect.get_detect_cli_args import GetDetectCliArgs
2
- from OTVision.config import Config, DetectConfig, YoloConfig, _LogConfig
3
3
  from OTVision.domain.cli import DetectCliArgs
4
4
 
5
5
 
@@ -20,6 +20,7 @@ class UpdateDetectConfigWithCliArgs:
20
20
  undistort=config.undistort,
21
21
  transform=config.transform,
22
22
  gui=config.gui,
23
+ stream=config.stream,
23
24
  )
24
25
 
25
26
  def _update_detect_config(
@@ -1,6 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
- from OTVision.config import Config, ConfigParser
3
+ from OTVision.application.config import Config
4
+ from OTVision.application.config_parser import ConfigParser
4
5
  from OTVision.domain.cli import CliArgs
5
6
 
6
7
  DEFAULT_USER_CONFIG = "user_config.otvision.yaml"
@@ -1,4 +1,4 @@
1
- from OTVision.config import Config
1
+ from OTVision.application.config import Config
2
2
  from OTVision.domain.current_config import CurrentConfig
3
3
 
4
4
 
File without changes
@@ -0,0 +1,20 @@
1
+ from OTVision.domain.cli import TrackCliArgs, TrackCliParser
2
+
3
+
4
+ class GetTrackCliArgs:
5
+ """Use case to retrieve the CLI arguments for OTVision track.
6
+
7
+ Args:
8
+ cli_parser (TrackCliParser): the CLI parser to parse the track CLI arguments.
9
+ """
10
+
11
+ def __init__(self, cli_parser: TrackCliParser) -> None:
12
+ self._cli_parser = cli_parser
13
+
14
+ def get(self) -> TrackCliArgs:
15
+ """Get the track CLI arguments.
16
+
17
+ Returns:
18
+ TrackCliArgs: the track CLI arguments.
19
+ """
20
+ return self._cli_parser.parse()
@@ -0,0 +1,42 @@
1
+ from OTVision.application.config import Config, TrackConfig
2
+ from OTVision.application.get_current_config import GetCurrentConfig
3
+ from OTVision.application.update_current_config import UpdateCurrentConfig
4
+
5
+
6
+ class UpdateCurrentTrackConfig:
7
+ """Use case to update the current track configuration with a TrackConfig object"""
8
+
9
+ def __init__(
10
+ self,
11
+ get_current_config: GetCurrentConfig,
12
+ update_current_config: UpdateCurrentConfig,
13
+ ) -> None:
14
+ self._get_current_config = get_current_config
15
+ self._update_current_config = update_current_config
16
+
17
+ def update(self, track_config: TrackConfig) -> None:
18
+ """Update current configuration with a TrackConfig object.
19
+
20
+ Args:
21
+ track_config (TrackConfig): TrackConfig object to update current
22
+ configuration with.
23
+ """
24
+ updated_config = self._update_with(track_config)
25
+ self._update_current_config.update(updated_config)
26
+
27
+ def _update_with(self, track_config: TrackConfig) -> Config:
28
+ current_config = self._get_current_config.get()
29
+ return Config(
30
+ log=current_config.log,
31
+ search_subdirs=current_config.search_subdirs,
32
+ default_filetype=current_config.default_filetype,
33
+ filetypes=current_config.filetypes,
34
+ last_paths=current_config.last_paths,
35
+ convert=current_config.convert,
36
+ detect=current_config.detect,
37
+ track=track_config,
38
+ undistort=current_config.undistort,
39
+ transform=current_config.transform,
40
+ gui=current_config.gui,
41
+ stream=current_config.stream,
42
+ )
@@ -0,0 +1,52 @@
1
+ from OTVision.abstraction.defaults import value_or_default
2
+ from OTVision.application.config import Config, TrackConfig, _LogConfig, _TrackIouConfig
3
+ from OTVision.application.track.get_track_cli_args import GetTrackCliArgs
4
+ from OTVision.domain.cli import TrackCliArgs
5
+
6
+
7
+ class UpdateTrackConfigWithCliArgs:
8
+ def __init__(self, get_detect_cli_args: GetTrackCliArgs) -> None:
9
+ self._get_track_cli_args = get_detect_cli_args
10
+
11
+ def update(self, config: Config) -> Config:
12
+ cli_args = self._get_track_cli_args.get()
13
+ return Config(
14
+ log=self._update_log_config(config, cli_args),
15
+ search_subdirs=config.search_subdirs,
16
+ default_filetype=config.default_filetype,
17
+ last_paths=config.last_paths,
18
+ convert=config.convert,
19
+ detect=config.detect,
20
+ track=self._update_track_config(config.track, cli_args),
21
+ undistort=config.undistort,
22
+ transform=config.transform,
23
+ gui=config.gui,
24
+ stream=config.stream,
25
+ )
26
+
27
+ def _update_track_config(
28
+ self, track_config: TrackConfig, cli_args: TrackCliArgs
29
+ ) -> TrackConfig:
30
+ iou_config = _TrackIouConfig(
31
+ sigma_l=value_or_default(cli_args.sigma_l, track_config.sigma_l),
32
+ sigma_h=value_or_default(cli_args.sigma_h, track_config.sigma_h),
33
+ sigma_iou=value_or_default(cli_args.sigma_iou, track_config.sigma_iou),
34
+ t_min=value_or_default(cli_args.t_min, track_config.t_min),
35
+ t_miss_max=value_or_default(cli_args.t_miss_max, track_config.t_miss_max),
36
+ )
37
+ return TrackConfig(
38
+ paths=value_or_default(cli_args.paths, track_config.paths),
39
+ run_chained=track_config.run_chained,
40
+ iou=iou_config,
41
+ overwrite=value_or_default(cli_args.overwrite, track_config.overwrite),
42
+ )
43
+
44
+ def _update_log_config(self, config: Config, cli_args: TrackCliArgs) -> _LogConfig:
45
+ return _LogConfig(
46
+ log_level_console=value_or_default(
47
+ cli_args.log_level_console, config.log.log_level_console
48
+ ),
49
+ log_level_file=value_or_default(
50
+ cli_args.log_level_file, config.log.log_level_file
51
+ ),
52
+ )
@@ -1,4 +1,4 @@
1
- from OTVision.config import Config
1
+ from OTVision.application.config import Config
2
2
  from OTVision.domain.current_config import CurrentConfig
3
3
 
4
4