OTVision 0.5.3__py3-none-any.whl → 0.5.4__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.
OTVision/dataformat.py CHANGED
@@ -38,6 +38,9 @@ INTERPOLATED_DETECTION: str = "interpolated-detection"
38
38
  MODEL: str = "model"
39
39
  CHUNKSIZE: str = "chunksize"
40
40
  NORMALIZED_BBOX: str = "normalized_bbox"
41
+ DETECT_START = "detect_start"
42
+ DETECT_END = "detect_end"
43
+
41
44
  # Detektor model config
42
45
  NAME: str = "name"
43
46
  WEIGHTS: str = "weights"
OTVision/detect/cli.py CHANGED
@@ -67,7 +67,7 @@ class ArgparseDetectCliParser(DetectCliParser):
67
67
  help="Use half precision for detection.",
68
68
  )
69
69
  self._parser.add_argument(
70
- "--expected_duration",
70
+ "--expected-duration",
71
71
  type=int,
72
72
  help="Expected duration of a single video in seconds.",
73
73
  required=False,
@@ -79,14 +79,14 @@ class ArgparseDetectCliParser(DetectCliParser):
79
79
  help="Overwrite existing output files",
80
80
  )
81
81
  self._parser.add_argument(
82
- "--log_level_console",
82
+ "--log-level-console",
83
83
  type=str,
84
84
  choices=VALID_LOG_LEVELS,
85
85
  help="Log level for logging to the console",
86
86
  required=False,
87
87
  )
88
88
  self._parser.add_argument(
89
- "--log_level_file",
89
+ "--log-level-file",
90
90
  type=str,
91
91
  choices=VALID_LOG_LEVELS,
92
92
  help="Log level for logging to a log file",
@@ -100,20 +100,20 @@ class ArgparseDetectCliParser(DetectCliParser):
100
100
  required=False,
101
101
  )
102
102
  self._parser.add_argument(
103
- "--logfile_overwrite",
103
+ "--logfile-overwrite",
104
104
  action="store_true",
105
105
  help="Overwrite log file if it already exists.",
106
106
  required=False,
107
107
  )
108
108
  self._parser.add_argument(
109
- "--detect_start",
109
+ "--detect-start",
110
110
  default=None,
111
111
  type=int,
112
112
  help="Specify start of detection in seconds.",
113
113
  required=False,
114
114
  )
115
115
  self._parser.add_argument(
116
- "--detect_end",
116
+ "--detect-end",
117
117
  default=None,
118
118
  type=int,
119
119
  help="Specify end of detection in seconds.",
OTVision/detect/detect.py CHANGED
@@ -43,6 +43,7 @@ from OTVision.helpers.video import get_duration, get_fps, get_video_dimensions
43
43
  from OTVision.track.preprocess import OCCURRENCE
44
44
 
45
45
  log = logging.getLogger(LOGGER_NAME)
46
+ DATETIME_FORMAT = "%Y-%m-%d_%H-%M-%S"
46
47
 
47
48
 
48
49
  class OTVisionDetect:
@@ -92,6 +93,15 @@ class OTVisionDetect:
92
93
  detect_suffix=self.config.filetypes.detect,
93
94
  )
94
95
 
96
+ try:
97
+ parse_start_time_from(video_file)
98
+ except InproperFormattedFilename:
99
+ log.warning(
100
+ f"Video file name of '{video_file}' must include date "
101
+ f"and time in format: {DATETIME_FORMAT}"
102
+ )
103
+ continue
104
+
95
105
  if not self.config.detect.overwrite and detections_file.is_file():
96
106
  log.warning(
97
107
  f"{detections_file} already exists. To overwrite, set overwrite "
@@ -138,6 +148,8 @@ class OTVisionDetect:
138
148
  half_precision=model.half_precision,
139
149
  chunksize=1,
140
150
  classifications=model.classifications,
151
+ detect_start=self.config.detect.detect_start,
152
+ detect_end=self.config.detect.detect_end,
141
153
  )
142
154
  ).build(detections)
143
155
 
@@ -218,7 +230,7 @@ class Timestamper:
218
230
  Returns:
219
231
  dict: input dictionary with additional occurrence per frame
220
232
  """
221
- start_time = self._get_start_time_from(video_file)
233
+ start_time = parse_start_time_from(video_file)
222
234
  actual_duration = get_duration(video_file)
223
235
  if expected_duration:
224
236
  time_per_frame = self._get_time_per_frame(detections, expected_duration)
@@ -227,32 +239,6 @@ class Timestamper:
227
239
  self._update_metadata(detections, start_time, actual_duration)
228
240
  return self._stamp(detections, start_time, time_per_frame)
229
241
 
230
- @staticmethod
231
- def _get_start_time_from(video_file: Path) -> datetime:
232
- """Parse the given filename and retrieve the start date of the video.
233
-
234
- Args:
235
- video_file (Path): path to video file
236
-
237
- Raises:
238
- InproperFormattedFilename: if the filename is not formatted as expected, an
239
- exception will be raised
240
-
241
- Returns:
242
- datetime: start date of the video
243
- """
244
- match = re.search(
245
- FILE_NAME_PATTERN,
246
- video_file.name,
247
- )
248
- if match:
249
- start_date: str = match.group(START_DATE)
250
- return parse_date_string_to_utc_datime(
251
- start_date, "%Y-%m-%d_%H-%M-%S"
252
- ).replace(tzinfo=timezone.utc)
253
-
254
- raise InproperFormattedFilename(f"Could not parse {video_file.name}.")
255
-
256
242
  @staticmethod
257
243
  def _get_time_per_frame(detections: dict, duration: timedelta) -> timedelta:
258
244
  """Calculates the duration for each frame. This is done using the total
@@ -294,3 +280,29 @@ class Timestamper:
294
280
  occurrence = start_date + (int(key) - 1) * time_per_frame
295
281
  value[OCCURRENCE] = occurrence.timestamp()
296
282
  return detections
283
+
284
+
285
+ def parse_start_time_from(video_file: Path) -> datetime:
286
+ """Parse the given filename and retrieve the start date of the video.
287
+
288
+ Args:
289
+ video_file (Path): path to video file
290
+
291
+ Raises:
292
+ InproperFormattedFilename: if the filename is not formatted as expected, an
293
+ exception will be raised
294
+
295
+ Returns:
296
+ datetime: start date of the video
297
+ """
298
+ match = re.search(
299
+ FILE_NAME_PATTERN,
300
+ video_file.name,
301
+ )
302
+ if match:
303
+ start_date: str = match.group(START_DATE)
304
+ return parse_date_string_to_utc_datime(start_date, "%Y-%m-%d_%H-%M-%S").replace(
305
+ tzinfo=timezone.utc
306
+ )
307
+
308
+ raise InproperFormattedFilename(f"Could not parse {video_file.name}.")
OTVision/detect/otdet.py CHANGED
@@ -24,6 +24,8 @@ class OtdetBuilderConfig:
24
24
  half_precision: bool
25
25
  chunksize: int
26
26
  classifications: dict[int, str]
27
+ detect_start: int | None
28
+ detect_end: int | None
27
29
 
28
30
 
29
31
  class OtdetBuilderError(Exception):
@@ -100,4 +102,6 @@ class OtdetBuilder:
100
102
  },
101
103
  dataformat.CHUNKSIZE: self.config.chunksize,
102
104
  dataformat.NORMALIZED_BBOX: self.config.normalized,
105
+ dataformat.DETECT_START: self.config.detect_start,
106
+ dataformat.DETECT_END: self.config.detect_end,
103
107
  }
OTVision/helpers/log.py CHANGED
@@ -24,6 +24,7 @@ import logging
24
24
  import sys
25
25
  from datetime import datetime
26
26
  from pathlib import Path
27
+ from typing import Callable
27
28
 
28
29
  LOGGER_NAME = "OTVision Logger"
29
30
 
@@ -57,7 +58,12 @@ class _OTVisionLogger:
57
58
  with LOGGER_NAME from the same module where this class is defined.
58
59
  """
59
60
 
60
- def __init__(self, name: str = LOGGER_NAME) -> None:
61
+ def __init__(
62
+ self,
63
+ name: str = LOGGER_NAME,
64
+ datetime_provider: Callable[[], datetime] = datetime.now,
65
+ ) -> None:
66
+ self._provide_datetime = datetime_provider
61
67
  self.logger = logging.getLogger(name=name)
62
68
  self.logger.setLevel("DEBUG")
63
69
  self._set_formatter()
@@ -92,12 +98,20 @@ class _OTVisionLogger:
92
98
  log_file and level are not intended to be optional, they have to be provided
93
99
  in every case. The default values provided are a safety net.
94
100
  """
95
- if log_file.exists() and not overwrite:
101
+ if log_file.is_file() and not overwrite:
96
102
  raise LogFileAlreadyExists(
97
103
  f"Log file '{log_file}' already exists. "
98
104
  "Please specify option to overwrite the log file when using the CLI."
99
105
  )
100
- log_file.parent.mkdir(parents=True, exist_ok=True)
106
+ log_dir = log_file.parent
107
+ if log_file.is_dir() or not log_file.suffix:
108
+ log_dir = log_file / "logs"
109
+ log_file = (
110
+ log_dir
111
+ / f"{self._provide_datetime().strftime(r'%Y-%m-%d_%H-%M-%S')}.{LOG_EXT}"
112
+ )
113
+
114
+ log_dir.mkdir(parents=True, exist_ok=True)
101
115
  log_file.touch()
102
116
  file_handler = logging.FileHandler(log_file, mode="w")
103
117
  self._add_handler(file_handler, level)
OTVision/version.py CHANGED
@@ -1,8 +1,8 @@
1
- __version__ = "v0.5.3"
1
+ __version__ = "v0.5.4"
2
2
 
3
3
 
4
4
  def otdet_version() -> str:
5
- return "1.3"
5
+ return "1.4"
6
6
 
7
7
 
8
8
  def ottrack_version() -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OTVision
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: OTVision is a core module of the OpenTrafficCam framework to perform object detection and tracking.
5
5
  Project-URL: Homepage, https://opentrafficcam.org/
6
6
  Project-URL: Documentation, https://opentrafficcam.org/overview/
@@ -1,7 +1,7 @@
1
1
  OTVision/__init__.py,sha256=b2goS-TYrN9y8WHmjG22z1oVwCrjV0WtGJE32NJfvJM,1042
2
2
  OTVision/config.py,sha256=qCCg2MT_exTiTqEXq3pdqjhlfzQCg4yKKcGJSr7Wkp0,21951
3
- OTVision/dataformat.py,sha256=atssfeVcwXBjysXbVsgMbmtdMiChWzu8AwW4hK4GZw4,1884
4
- OTVision/version.py,sha256=rRi91utnulgYKaZW-qxdRDD7ufdJJ0G1IesKOtXP-NE,175
3
+ OTVision/dataformat.py,sha256=BHF7qHzyNb80hI1EKfwcdJ9bgG_X4bp_hCXzdg7_MSA,1941
4
+ OTVision/version.py,sha256=LVnJBM50iwzU0Egq0hA4TxRmvsDdnlvBxZ3_tqZaxFs,175
5
5
  OTVision/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  OTVision/application/configure_logger.py,sha256=RmRgYkvSXWqpFX3N2n0h2LDna3uL8AY-yfVZU66t5q4,611
7
7
  OTVision/application/get_config.py,sha256=fRJZUWJvlTed6qriw82-B-05CAqfBma6NQ23WrKqYdE,771
@@ -12,9 +12,9 @@ OTVision/convert/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
12
12
  OTVision/convert/convert.py,sha256=vRIFcrAUf9MUWAuvF_q7JQ9aN89B1ouBOCtXrCLuDp8,11013
13
13
  OTVision/detect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  OTVision/detect/builder.py,sha256=opd3RQ8ycm9Z75Z4OUiDXfP02bHvDslJcsfeKmLDwkw,1615
15
- OTVision/detect/cli.py,sha256=HpvdaXl_IJZe0CxZ9KmGzYDLL-zFABmfSV8aG3Rtamo,5454
16
- OTVision/detect/detect.py,sha256=O8xo0yH9yCmQKkvVqxkoJxQ9FcRPyf3s6IesgdEXcdo,10968
17
- OTVision/detect/otdet.py,sha256=rIiZR1J0_xdTVc6fwu8n2CrsIwpuD4TQiI6o99RTjog,3456
15
+ OTVision/detect/cli.py,sha256=1t8TC9_R7PLeIA0hyE04rvJeFj1hAbPIEH6vqJF6cg8,5454
16
+ OTVision/detect/detect.py,sha256=Hbr95vnUfsjQpUmbM8lCCjKdcTWMM1pZ-P0Kb2oRicU,11357
17
+ OTVision/detect/otdet.py,sha256=BwRfbeDWGHwYAAgweDx2MY6IYwuHlZHfE-E059AVnOc,3634
18
18
  OTVision/detect/yolo.py,sha256=cxRUxIchy_KYxkYUHEYyBCM4PB7d6E_nUDk0fja6XJY,9181
19
19
  OTVision/detect/plugin_av/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  OTVision/detect/plugin_av/rotate_frame.py,sha256=4wJqTYI2HRlfa4p2Ffap33vLmKIzE_EwFvQraEkQ4R8,1055
@@ -24,7 +24,7 @@ OTVision/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
24
24
  OTVision/helpers/date.py,sha256=XK0fmXMombQ2CJ2_RXjk-bc-R8qqXRK2rDmCMBi0_G0,854
25
25
  OTVision/helpers/files.py,sha256=JxO0ijcybBgIijIuA-9fnNhy-No0FAZCaE4RKMW0ie0,18116
26
26
  OTVision/helpers/formats.py,sha256=YLo_QLA2nhVREyv5N-xNW20c4nIL7DIF40E1lrsAyLE,4365
27
- OTVision/helpers/log.py,sha256=s5EYBboiNrkIKQE7WkPxnC0NJFL_shH7L5p7AI9IGJE,4544
27
+ OTVision/helpers/log.py,sha256=fOSMTXQRQ3_3zzYL8pDlx85IXPwyDsI2WGpK-V_R47Q,4985
28
28
  OTVision/helpers/machine.py,sha256=8Bz_Eg7PS0IL4riOVeJcEIi5D9E8Ju8-JomTkW975p8,2166
29
29
  OTVision/helpers/video.py,sha256=ZXG1rhD9OVk95mnfYVPbBwLKrRturgSRCsaOsGJVT2U,1324
30
30
  OTVision/track/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -44,7 +44,7 @@ OTVision/view/view_helpers.py,sha256=a5yV_6ZxO5bxsSymOmxdHqzOEv0VFq4wFBopVRGuVRo
44
44
  OTVision/view/view_track.py,sha256=ioHenonuTJQn8yDzlIDV8Jc1yzWA0GHbC9CotYGtxHQ,5389
45
45
  OTVision/view/view_transform.py,sha256=HvRd8g8geKRy0OoiZUDn_oC3SJC5nuXhZf3uZelfGKg,5473
46
46
  OTVision/view/helpers/OTC.ico,sha256=G9kwlDtgBXmXO3yxW6Z-xVFV2q4nUGuz9E1VPHSu_I8,21662
47
- otvision-0.5.3.dist-info/METADATA,sha256=y9bE7wsK_cHxpU9EmFkdbuPdkaxB4PbbHgGvZTTE5AA,2244
48
- otvision-0.5.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
- otvision-0.5.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
50
- otvision-0.5.3.dist-info/RECORD,,
47
+ otvision-0.5.4.dist-info/METADATA,sha256=H_IZXzGbZm3MtW-Jy47zE5DxwhgZ4R1_zIUH4S_GhK0,2244
48
+ otvision-0.5.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ otvision-0.5.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
50
+ otvision-0.5.4.dist-info/RECORD,,