mapillary-tools 0.14.0a2__py3-none-any.whl → 0.14.1__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.
- mapillary_tools/__init__.py +1 -1
- mapillary_tools/api_v4.py +66 -262
- mapillary_tools/authenticate.py +54 -46
- mapillary_tools/blackvue_parser.py +79 -22
- mapillary_tools/commands/__main__.py +15 -16
- mapillary_tools/commands/upload.py +33 -4
- mapillary_tools/config.py +38 -17
- mapillary_tools/constants.py +127 -43
- mapillary_tools/exceptions.py +4 -0
- mapillary_tools/exif_read.py +2 -1
- mapillary_tools/exif_write.py +3 -1
- mapillary_tools/exiftool_read_video.py +52 -15
- mapillary_tools/exiftool_runner.py +4 -24
- mapillary_tools/ffmpeg.py +406 -232
- mapillary_tools/geo.py +16 -0
- mapillary_tools/geotag/__init__.py +0 -0
- mapillary_tools/geotag/base.py +8 -4
- mapillary_tools/geotag/factory.py +106 -89
- mapillary_tools/geotag/geotag_images_from_exiftool.py +27 -20
- mapillary_tools/geotag/geotag_images_from_gpx.py +7 -6
- mapillary_tools/geotag/geotag_images_from_video.py +35 -0
- mapillary_tools/geotag/geotag_videos_from_exiftool.py +61 -14
- mapillary_tools/geotag/geotag_videos_from_gpx.py +22 -9
- mapillary_tools/geotag/options.py +25 -3
- mapillary_tools/geotag/utils.py +9 -12
- mapillary_tools/geotag/video_extractors/base.py +1 -1
- mapillary_tools/geotag/video_extractors/exiftool.py +1 -1
- mapillary_tools/geotag/video_extractors/gpx.py +61 -70
- mapillary_tools/geotag/video_extractors/native.py +34 -31
- mapillary_tools/history.py +128 -8
- mapillary_tools/http.py +211 -0
- mapillary_tools/mp4/construct_mp4_parser.py +8 -2
- mapillary_tools/process_geotag_properties.py +47 -35
- mapillary_tools/process_sequence_properties.py +340 -325
- mapillary_tools/sample_video.py +8 -8
- mapillary_tools/serializer/description.py +587 -0
- mapillary_tools/serializer/gpx.py +132 -0
- mapillary_tools/types.py +44 -610
- mapillary_tools/upload.py +327 -352
- mapillary_tools/upload_api_v4.py +125 -72
- mapillary_tools/uploader.py +797 -216
- mapillary_tools/utils.py +57 -5
- {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/METADATA +91 -34
- mapillary_tools-0.14.1.dist-info/RECORD +76 -0
- {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/WHEEL +1 -1
- mapillary_tools-0.14.0a2.dist-info/RECORD +0 -72
- {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/entry_points.txt +0 -0
- {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/licenses/LICENSE +0 -0
- {mapillary_tools-0.14.0a2.dist-info → mapillary_tools-0.14.1.dist-info}/top_level.txt +0 -0
|
@@ -82,6 +82,32 @@ def _extract_alternative_fields(
|
|
|
82
82
|
return None
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def _same_gps_point(left: GPSPoint, right: GPSPoint) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
>>> left = GPSPoint(time=56.0, lat=36.741385, lon=29.021274, alt=141.6, angle=1.54, epoch_time=None, fix=None, precision=None, ground_speed=None)
|
|
88
|
+
>>> right = GPSPoint(time=56.0, lat=36.741385, lon=29.021274, alt=142.4, angle=1.54, epoch_time=None, fix=None, precision=None, ground_speed=None)
|
|
89
|
+
>>> _same_gps_point(left, right)
|
|
90
|
+
True
|
|
91
|
+
"""
|
|
92
|
+
return (
|
|
93
|
+
left.time == right.time
|
|
94
|
+
and left.lon == right.lon
|
|
95
|
+
and left.lat == right.lat
|
|
96
|
+
and left.epoch_time == right.epoch_time
|
|
97
|
+
and left.angle == right.angle
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _deduplicate_gps_points(
|
|
102
|
+
track: list[GPSPoint], same_gps_point: T.Callable[[GPSPoint, GPSPoint], bool]
|
|
103
|
+
) -> list[GPSPoint]:
|
|
104
|
+
deduplicated_track: list[GPSPoint] = []
|
|
105
|
+
for point in track:
|
|
106
|
+
if not deduplicated_track or not same_gps_point(deduplicated_track[-1], point):
|
|
107
|
+
deduplicated_track.append(point)
|
|
108
|
+
return deduplicated_track
|
|
109
|
+
|
|
110
|
+
|
|
85
111
|
def _aggregate_gps_track(
|
|
86
112
|
texts_by_tag: dict[str, list[str]],
|
|
87
113
|
time_tag: str | None,
|
|
@@ -174,7 +200,7 @@ def _aggregate_gps_track(
|
|
|
174
200
|
epoch_time = geo.as_unix_time(dt)
|
|
175
201
|
|
|
176
202
|
# build track
|
|
177
|
-
track = []
|
|
203
|
+
track: list[GPSPoint] = []
|
|
178
204
|
for timestamp, lon, lat, alt, direction, ground_speed in zip(
|
|
179
205
|
timestamps,
|
|
180
206
|
lons,
|
|
@@ -185,22 +211,26 @@ def _aggregate_gps_track(
|
|
|
185
211
|
):
|
|
186
212
|
if timestamp is None or lon is None or lat is None:
|
|
187
213
|
continue
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
214
|
+
|
|
215
|
+
point = GPSPoint(
|
|
216
|
+
time=timestamp,
|
|
217
|
+
lon=lon,
|
|
218
|
+
lat=lat,
|
|
219
|
+
alt=alt,
|
|
220
|
+
angle=direction,
|
|
221
|
+
epoch_time=epoch_time,
|
|
222
|
+
fix=None,
|
|
223
|
+
precision=None,
|
|
224
|
+
ground_speed=ground_speed,
|
|
200
225
|
)
|
|
201
226
|
|
|
227
|
+
if not track or not _same_gps_point(track[-1], point):
|
|
228
|
+
track.append(point)
|
|
229
|
+
|
|
202
230
|
track.sort(key=lambda point: point.time)
|
|
203
231
|
|
|
232
|
+
track = _deduplicate_gps_points(track, same_gps_point=_same_gps_point)
|
|
233
|
+
|
|
204
234
|
if time_tag is not None:
|
|
205
235
|
if track:
|
|
206
236
|
first_time = track[0].time
|
|
@@ -310,7 +340,10 @@ class ExifToolReadVideo:
|
|
|
310
340
|
etree: ET.ElementTree,
|
|
311
341
|
) -> None:
|
|
312
342
|
self.etree = etree
|
|
313
|
-
|
|
343
|
+
root = self.etree.getroot()
|
|
344
|
+
if root is None:
|
|
345
|
+
raise ValueError("ElementTree root is None")
|
|
346
|
+
self._texts_by_tag = _index_text_by_tag(root)
|
|
314
347
|
self._all_tags = set(self._texts_by_tag.keys())
|
|
315
348
|
|
|
316
349
|
def extract_gps_track(self) -> list[geo.Point]:
|
|
@@ -371,6 +404,10 @@ class ExifToolReadVideo:
|
|
|
371
404
|
return model
|
|
372
405
|
|
|
373
406
|
def _extract_gps_track_from_track(self) -> list[GPSPoint]:
|
|
407
|
+
root = self.etree.getroot()
|
|
408
|
+
if root is None:
|
|
409
|
+
raise ValueError("ElementTree root is None")
|
|
410
|
+
|
|
374
411
|
for track_id in range(1, MAX_TRACK_ID + 1):
|
|
375
412
|
track_ns = f"Track{track_id}"
|
|
376
413
|
if self._all_tags_exists(
|
|
@@ -382,7 +419,7 @@ class ExifToolReadVideo:
|
|
|
382
419
|
}
|
|
383
420
|
):
|
|
384
421
|
sample_iterator = _aggregate_samples(
|
|
385
|
-
|
|
422
|
+
root,
|
|
386
423
|
f"{track_ns}:SampleTime",
|
|
387
424
|
f"{track_ns}:SampleDuration",
|
|
388
425
|
)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import platform
|
|
4
|
-
import shutil
|
|
5
3
|
import subprocess
|
|
6
4
|
import typing as T
|
|
7
5
|
from pathlib import Path
|
|
@@ -12,32 +10,14 @@ class ExiftoolRunner:
|
|
|
12
10
|
Wrapper around ExifTool to run it in a subprocess
|
|
13
11
|
"""
|
|
14
12
|
|
|
15
|
-
def __init__(self,
|
|
16
|
-
|
|
17
|
-
exiftool_path = self._search_preferred_exiftool_path()
|
|
18
|
-
self.exiftool_path = exiftool_path
|
|
13
|
+
def __init__(self, exiftool_executable: str = "exiftool", recursive: bool = False):
|
|
14
|
+
self.exiftool_executable = exiftool_executable
|
|
19
15
|
self.recursive = recursive
|
|
20
16
|
|
|
21
|
-
def _search_preferred_exiftool_path(self) -> str:
|
|
22
|
-
system = platform.system()
|
|
23
|
-
|
|
24
|
-
if system and system.lower() == "windows":
|
|
25
|
-
exiftool_paths = ["exiftool.exe", "exiftool"]
|
|
26
|
-
else:
|
|
27
|
-
exiftool_paths = ["exiftool", "exiftool.exe"]
|
|
28
|
-
|
|
29
|
-
for path in exiftool_paths:
|
|
30
|
-
full_path = shutil.which(path)
|
|
31
|
-
if full_path:
|
|
32
|
-
return path
|
|
33
|
-
|
|
34
|
-
# Always return the prefered one, even if it is not found,
|
|
35
|
-
# and let the subprocess.run figure out the error later
|
|
36
|
-
return exiftool_paths[0]
|
|
37
|
-
|
|
38
17
|
def _build_args_read_stdin(self) -> list[str]:
|
|
39
18
|
args: list[str] = [
|
|
40
|
-
self.
|
|
19
|
+
self.exiftool_executable,
|
|
20
|
+
"-fast",
|
|
41
21
|
"-q",
|
|
42
22
|
"-n", # Disable print conversion
|
|
43
23
|
"-X", # XML output
|