diff --git a/mapillary_tools/exif_read.py b/mapillary_tools/exif_read.py index 284d59377..8a025d255 100644 --- a/mapillary_tools/exif_read.py +++ b/mapillary_tools/exif_read.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import abc import datetime import io @@ -477,9 +479,9 @@ def extract_orientation(self) -> int: def _extract_alternative_fields( self, - fields: T.Sequence[str], - field_type: T.Type[_FIELD_TYPE], - ) -> T.Optional[_FIELD_TYPE]: + fields: T.Iterable[str], + field_type: type[_FIELD_TYPE], + ) -> _FIELD_TYPE | None: """ Extract a value for a list of ordered fields. Return the value of the first existed field in the list @@ -736,17 +738,7 @@ def extract_direction(self) -> T.Optional[float]: "GPS GPSImgDirection", "GPS GPSTrack", ] - direction = self._extract_alternative_fields(fields, float) - if direction is not None: - if direction > 360: - # fix negative value wrongly parsed in exifread - # -360 degree -> 4294966935 when converting from hex - bearing1 = bin(int(direction))[2:] - bearing2 = "".join([str(int(int(a) == 0)) for a in bearing1]) - direction = -float(int(bearing2, 2)) - direction %= 360 - - return direction + return self._extract_alternative_fields(fields, float) def extract_lon_lat(self) -> T.Optional[T.Tuple[float, float]]: lat_tag = self.tags.get("GPS GPSLatitude") @@ -774,7 +766,9 @@ def extract_make(self) -> T.Optional[str]: """ Extract camera make """ - make = self._extract_alternative_fields(["Image Make", "EXIF LensMake"], str) + make = self._extract_alternative_fields( + ["Image Make", "EXIF Make", "EXIF LensMake"], str + ) if make is None: return None return make.strip() @@ -783,7 +777,9 @@ def extract_model(self) -> T.Optional[str]: """ Extract camera model """ - model = self._extract_alternative_fields(["Image Model", "EXIF LensModel"], str) + model = self._extract_alternative_fields( + ["Image Model", "EXIF Model", "EXIF LensModel"], str + ) if model is None: return None return model.strip() @@ -818,8 +814,8 @@ def extract_orientation(self) -> int: def _extract_alternative_fields( self, fields: T.Sequence[str], - field_type: T.Type[_FIELD_TYPE], - ) -> T.Optional[_FIELD_TYPE]: + field_type: type[_FIELD_TYPE], + ) -> _FIELD_TYPE | None: """ Extract a value for a list of ordered fields. Return the value of the first existed field in the list diff --git a/mapillary_tools/exiftool_read_video.py b/mapillary_tools/exiftool_read_video.py index a8ee18423..25be9e5b4 100644 --- a/mapillary_tools/exiftool_read_video.py +++ b/mapillary_tools/exiftool_read_video.py @@ -86,6 +86,7 @@ def _aggregate_gps_track( lon_tag: str, lat_tag: str, alt_tag: T.Optional[str] = None, + gps_time_tag: T.Optional[str] = None, direction_tag: T.Optional[str] = None, ground_speed_tag: T.Optional[str] = None, ) -> T.List[GPSPoint]: @@ -161,6 +162,15 @@ def _aggregate_float_values_same_length( # aggregate speeds (optional) ground_speeds = _aggregate_float_values_same_length(ground_speed_tag) + # GPS timestamp (optional) + epoch_time = None + if gps_time_tag is not None: + gps_time_text = _extract_alternative_fields(texts_by_tag, [gps_time_tag], str) + if gps_time_text is not None: + dt = exif_read.parse_gps_datetime(gps_time_text) + if dt is not None: + epoch_time = geo.as_unix_time(dt) + # build track track = [] for timestamp, lon, lat, alt, direction, ground_speed in zip( @@ -180,7 +190,7 @@ def _aggregate_float_values_same_length( lat=lat, alt=alt, angle=direction, - epoch_time=None, + epoch_time=epoch_time, fix=None, precision=None, ground_speed=ground_speed, @@ -228,6 +238,7 @@ def _aggregate_gps_track_by_sample_time( lon_tag: str, lat_tag: str, alt_tag: T.Optional[str] = None, + gps_time_tag: T.Optional[str] = None, direction_tag: T.Optional[str] = None, ground_speed_tag: T.Optional[str] = None, gps_fix_tag: T.Optional[str] = None,