mapillary-tools 0.13.3a1__py3-none-any.whl → 0.14.0__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 (87) hide show
  1. mapillary_tools/__init__.py +1 -1
  2. mapillary_tools/api_v4.py +287 -22
  3. mapillary_tools/authenticate.py +326 -64
  4. mapillary_tools/blackvue_parser.py +195 -0
  5. mapillary_tools/camm/camm_builder.py +55 -97
  6. mapillary_tools/camm/camm_parser.py +429 -181
  7. mapillary_tools/commands/__main__.py +17 -8
  8. mapillary_tools/commands/authenticate.py +8 -1
  9. mapillary_tools/commands/process.py +27 -51
  10. mapillary_tools/commands/process_and_upload.py +19 -5
  11. mapillary_tools/commands/sample_video.py +2 -3
  12. mapillary_tools/commands/upload.py +44 -13
  13. mapillary_tools/commands/video_process_and_upload.py +19 -5
  14. mapillary_tools/config.py +65 -26
  15. mapillary_tools/constants.py +141 -18
  16. mapillary_tools/exceptions.py +37 -34
  17. mapillary_tools/exif_read.py +221 -116
  18. mapillary_tools/exif_write.py +10 -8
  19. mapillary_tools/exiftool_read.py +33 -42
  20. mapillary_tools/exiftool_read_video.py +97 -47
  21. mapillary_tools/exiftool_runner.py +57 -0
  22. mapillary_tools/ffmpeg.py +417 -242
  23. mapillary_tools/geo.py +158 -118
  24. mapillary_tools/geotag/__init__.py +0 -1
  25. mapillary_tools/geotag/base.py +147 -0
  26. mapillary_tools/geotag/factory.py +307 -0
  27. mapillary_tools/geotag/geotag_images_from_exif.py +14 -131
  28. mapillary_tools/geotag/geotag_images_from_exiftool.py +136 -85
  29. mapillary_tools/geotag/geotag_images_from_gpx.py +60 -124
  30. mapillary_tools/geotag/geotag_images_from_gpx_file.py +13 -126
  31. mapillary_tools/geotag/geotag_images_from_nmea_file.py +4 -5
  32. mapillary_tools/geotag/geotag_images_from_video.py +88 -51
  33. mapillary_tools/geotag/geotag_videos_from_exiftool.py +123 -0
  34. mapillary_tools/geotag/geotag_videos_from_gpx.py +52 -0
  35. mapillary_tools/geotag/geotag_videos_from_video.py +20 -185
  36. mapillary_tools/geotag/image_extractors/base.py +18 -0
  37. mapillary_tools/geotag/image_extractors/exif.py +60 -0
  38. mapillary_tools/geotag/image_extractors/exiftool.py +18 -0
  39. mapillary_tools/geotag/options.py +182 -0
  40. mapillary_tools/geotag/utils.py +52 -16
  41. mapillary_tools/geotag/video_extractors/base.py +18 -0
  42. mapillary_tools/geotag/video_extractors/exiftool.py +70 -0
  43. mapillary_tools/geotag/video_extractors/gpx.py +116 -0
  44. mapillary_tools/geotag/video_extractors/native.py +160 -0
  45. mapillary_tools/{geotag → gpmf}/gpmf_parser.py +205 -182
  46. mapillary_tools/{geotag → gpmf}/gps_filter.py +5 -3
  47. mapillary_tools/history.py +134 -20
  48. mapillary_tools/mp4/construct_mp4_parser.py +17 -10
  49. mapillary_tools/mp4/io_utils.py +0 -1
  50. mapillary_tools/mp4/mp4_sample_parser.py +36 -28
  51. mapillary_tools/mp4/simple_mp4_builder.py +10 -9
  52. mapillary_tools/mp4/simple_mp4_parser.py +13 -22
  53. mapillary_tools/process_geotag_properties.py +184 -414
  54. mapillary_tools/process_sequence_properties.py +594 -225
  55. mapillary_tools/sample_video.py +20 -26
  56. mapillary_tools/serializer/description.py +587 -0
  57. mapillary_tools/serializer/gpx.py +132 -0
  58. mapillary_tools/telemetry.py +26 -13
  59. mapillary_tools/types.py +98 -611
  60. mapillary_tools/upload.py +408 -416
  61. mapillary_tools/upload_api_v4.py +172 -174
  62. mapillary_tools/uploader.py +804 -284
  63. mapillary_tools/utils.py +49 -18
  64. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/METADATA +93 -35
  65. mapillary_tools-0.14.0.dist-info/RECORD +75 -0
  66. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/WHEEL +1 -1
  67. mapillary_tools/geotag/blackvue_parser.py +0 -118
  68. mapillary_tools/geotag/geotag_from_generic.py +0 -22
  69. mapillary_tools/geotag/geotag_images_from_exiftool_both_image_and_video.py +0 -93
  70. mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +0 -145
  71. mapillary_tools/video_data_extraction/cli_options.py +0 -22
  72. mapillary_tools/video_data_extraction/extract_video_data.py +0 -176
  73. mapillary_tools/video_data_extraction/extractors/base_parser.py +0 -75
  74. mapillary_tools/video_data_extraction/extractors/blackvue_parser.py +0 -34
  75. mapillary_tools/video_data_extraction/extractors/camm_parser.py +0 -38
  76. mapillary_tools/video_data_extraction/extractors/exiftool_runtime_parser.py +0 -71
  77. mapillary_tools/video_data_extraction/extractors/exiftool_xml_parser.py +0 -53
  78. mapillary_tools/video_data_extraction/extractors/generic_video_parser.py +0 -52
  79. mapillary_tools/video_data_extraction/extractors/gopro_parser.py +0 -43
  80. mapillary_tools/video_data_extraction/extractors/gpx_parser.py +0 -108
  81. mapillary_tools/video_data_extraction/extractors/nmea_parser.py +0 -24
  82. mapillary_tools/video_data_extraction/video_data_parser_factory.py +0 -39
  83. mapillary_tools-0.13.3a1.dist-info/RECORD +0 -75
  84. /mapillary_tools/{geotag → gpmf}/gpmf_gps_filter.py +0 -0
  85. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/entry_points.txt +0 -0
  86. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info/licenses}/LICENSE +0 -0
  87. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,132 @@
1
+ import datetime
2
+ import json
3
+ import sys
4
+ import typing as T
5
+
6
+ if sys.version_info >= (3, 12):
7
+ from typing import override
8
+ else:
9
+ from typing_extensions import override
10
+
11
+ import gpxpy
12
+ import gpxpy.gpx
13
+
14
+ from .. import geo, types
15
+
16
+ from ..telemetry import CAMMGPSPoint, GPSPoint
17
+ from ..types import (
18
+ BaseSerializer,
19
+ ErrorMetadata,
20
+ ImageMetadata,
21
+ MetadataOrError,
22
+ VideoMetadata,
23
+ )
24
+ from .description import DescriptionJSONSerializer
25
+
26
+
27
+ class GPXSerializer(BaseSerializer):
28
+ @override
29
+ @classmethod
30
+ def serialize(cls, metadatas: T.Sequence[MetadataOrError]) -> bytes:
31
+ gpx = cls.as_gpx(metadatas)
32
+ return gpx.to_xml().encode("utf-8")
33
+
34
+ @classmethod
35
+ def as_gpx(cls, metadatas: T.Sequence[MetadataOrError]) -> gpxpy.gpx.GPX:
36
+ gpx = gpxpy.gpx.GPX()
37
+
38
+ error_metadatas = []
39
+ image_metadatas = []
40
+ video_metadatas = []
41
+
42
+ for metadata in metadatas:
43
+ if isinstance(metadata, ErrorMetadata):
44
+ error_metadatas.append(metadata)
45
+ elif isinstance(metadata, ImageMetadata):
46
+ image_metadatas.append(metadata)
47
+ elif isinstance(metadata, VideoMetadata):
48
+ video_metadatas.append(metadata)
49
+
50
+ for metadata in error_metadatas:
51
+ gpx_track = gpxpy.gpx.GPXTrack()
52
+ gpx_track.name = str(metadata.filename)
53
+ gpx_track.description = cls._build_gpx_description(metadata, ["filename"])
54
+ gpx.tracks.append(gpx_track)
55
+
56
+ sequences = types.group_and_sort_images(image_metadatas)
57
+ for sequence_uuid, sequence in sequences.items():
58
+ gpx.tracks.append(cls.image_sequence_as_gpx_track(sequence_uuid, sequence))
59
+
60
+ for metadata in video_metadatas:
61
+ gpx.tracks.append(cls.as_gpx_track(metadata))
62
+
63
+ return gpx
64
+
65
+ @classmethod
66
+ def as_gpx_point(cls, point: geo.Point) -> gpxpy.gpx.GPXTrackPoint:
67
+ gpx_point = gpxpy.gpx.GPXTrackPoint(
68
+ latitude=point.lat,
69
+ longitude=point.lon,
70
+ elevation=point.alt,
71
+ time=datetime.datetime.fromtimestamp(point.time, datetime.timezone.utc),
72
+ )
73
+
74
+ if isinstance(point, types.ImageMetadata):
75
+ gpx_point.name = point.filename.name
76
+ elif isinstance(point, CAMMGPSPoint):
77
+ gpx_point.time = datetime.datetime.fromtimestamp(
78
+ point.time_gps_epoch, datetime.timezone.utc
79
+ )
80
+ elif isinstance(point, GPSPoint):
81
+ if point.epoch_time is not None:
82
+ gpx_point.time = datetime.datetime.fromtimestamp(
83
+ point.epoch_time, datetime.timezone.utc
84
+ )
85
+
86
+ return gpx_point
87
+
88
+ @classmethod
89
+ def as_gpx_track(cls, metadata: VideoMetadata) -> gpxpy.gpx.GPXTrack:
90
+ gpx_segment = gpxpy.gpx.GPXTrackSegment()
91
+ for point in metadata.points:
92
+ gpx_point = cls.as_gpx_point(point)
93
+ gpx_segment.points.append(gpx_point)
94
+ gpx_track = gpxpy.gpx.GPXTrack()
95
+ gpx_track.name = str(metadata.filename)
96
+ gpx_track.description = cls._build_gpx_description(
97
+ metadata, ["filename", "MAPGPSTrack"]
98
+ )
99
+ gpx_track.segments.append(gpx_segment)
100
+ return gpx_track
101
+
102
+ @classmethod
103
+ def image_sequence_as_gpx_track(
104
+ cls, sequence_uuid: str, sequence: T.Sequence[ImageMetadata]
105
+ ) -> gpxpy.gpx.GPXTrack:
106
+ gpx_segment = gpxpy.gpx.GPXTrackSegment()
107
+ for metadata in sequence:
108
+ gpx_point = cls.as_gpx_point(metadata)
109
+ gpx_segment.points.append(gpx_point)
110
+ gpx_track = gpxpy.gpx.GPXTrack()
111
+ gpx_track.name = sequence_uuid
112
+ gpx_track.description = cls._build_gpx_description(
113
+ metadata,
114
+ [
115
+ "filename",
116
+ "MAPLongitude",
117
+ "MAPLatitude",
118
+ "MAPCaptureTime",
119
+ "MAPAltitude",
120
+ ],
121
+ )
122
+ gpx_track.segments.append(gpx_segment)
123
+ return gpx_track
124
+
125
+ @classmethod
126
+ def _build_gpx_description(
127
+ cls, metadata: MetadataOrError, excluded_properties: T.Sequence[str]
128
+ ) -> str:
129
+ desc = T.cast(T.Dict, DescriptionJSONSerializer.as_desc(metadata))
130
+ for prop in excluded_properties:
131
+ desc.pop(prop, None)
132
+ return json.dumps(desc, sort_keys=True, separators=(",", ":"))
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  import dataclasses
2
- import typing as T
3
4
  from enum import Enum, unique
4
5
 
5
6
  from .geo import Point
@@ -12,16 +13,8 @@ class GPSFix(Enum):
12
13
  FIX_3D = 3
13
14
 
14
15
 
15
- @dataclasses.dataclass
16
- class GPSPoint(Point):
17
- epoch_time: T.Optional[float]
18
- fix: T.Optional[GPSFix]
19
- precision: T.Optional[float]
20
- ground_speed: T.Optional[float]
21
-
22
-
23
16
  @dataclasses.dataclass(order=True)
24
- class TelemetryMeasurement:
17
+ class TimestampedMeasurement:
25
18
  """Base class for all telemetry measurements.
26
19
 
27
20
  All telemetry measurements must have a timestamp in seconds.
@@ -32,8 +25,28 @@ class TelemetryMeasurement:
32
25
  time: float
33
26
 
34
27
 
28
+ @dataclasses.dataclass
29
+ class GPSPoint(TimestampedMeasurement, Point):
30
+ epoch_time: float | None
31
+ fix: GPSFix | None
32
+ precision: float | None
33
+ ground_speed: float | None
34
+
35
+
36
+ @dataclasses.dataclass
37
+ class CAMMGPSPoint(TimestampedMeasurement, Point):
38
+ time_gps_epoch: float
39
+ gps_fix_type: int
40
+ horizontal_accuracy: float
41
+ vertical_accuracy: float
42
+ velocity_east: float
43
+ velocity_north: float
44
+ velocity_up: float
45
+ speed_accuracy: float
46
+
47
+
35
48
  @dataclasses.dataclass(order=True)
36
- class GyroscopeData(TelemetryMeasurement):
49
+ class GyroscopeData(TimestampedMeasurement):
37
50
  """Gyroscope signal in radians/seconds around XYZ axes of the camera."""
38
51
 
39
52
  x: float
@@ -42,7 +55,7 @@ class GyroscopeData(TelemetryMeasurement):
42
55
 
43
56
 
44
57
  @dataclasses.dataclass(order=True)
45
- class AccelerationData(TelemetryMeasurement):
58
+ class AccelerationData(TimestampedMeasurement):
46
59
  """Accelerometer reading in meters/second^2 along XYZ axes of the camera."""
47
60
 
48
61
  x: float
@@ -51,7 +64,7 @@ class AccelerationData(TelemetryMeasurement):
51
64
 
52
65
 
53
66
  @dataclasses.dataclass(order=True)
54
- class MagnetometerData(TelemetryMeasurement):
67
+ class MagnetometerData(TimestampedMeasurement):
55
68
  """Ambient magnetic field."""
56
69
 
57
70
  x: float