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 +3 -0
- OTVision/detect/cli.py +6 -6
- OTVision/detect/detect.py +39 -27
- OTVision/detect/otdet.py +4 -0
- OTVision/helpers/log.py +17 -3
- OTVision/version.py +2 -2
- {otvision-0.5.3.dist-info → otvision-0.5.4.dist-info}/METADATA +1 -1
- {otvision-0.5.3.dist-info → otvision-0.5.4.dist-info}/RECORD +10 -10
- {otvision-0.5.3.dist-info → otvision-0.5.4.dist-info}/WHEEL +0 -0
- {otvision-0.5.3.dist-info → otvision-0.5.4.dist-info}/licenses/LICENSE +0 -0
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
|
-
"--
|
|
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
|
-
"--
|
|
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
|
-
"--
|
|
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
|
-
"--
|
|
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
|
-
"--
|
|
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
|
-
"--
|
|
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 =
|
|
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__(
|
|
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.
|
|
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
|
|
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,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OTVision
|
|
3
|
-
Version: 0.5.
|
|
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=
|
|
4
|
-
OTVision/version.py,sha256=
|
|
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=
|
|
16
|
-
OTVision/detect/detect.py,sha256=
|
|
17
|
-
OTVision/detect/otdet.py,sha256=
|
|
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=
|
|
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.
|
|
48
|
-
otvision-0.5.
|
|
49
|
-
otvision-0.5.
|
|
50
|
-
otvision-0.5.
|
|
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,,
|
|
File without changes
|
|
File without changes
|