diff --git a/mapillary_tools/geotag/geotag_videos_from_exiftool_video.py b/mapillary_tools/geotag/geotag_videos_from_exiftool_video.py index 0eb022bbf..99a405808 100644 --- a/mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +++ b/mapillary_tools/geotag/geotag_videos_from_exiftool_video.py @@ -10,7 +10,6 @@ from ..exiftool_read_video import ExifToolReadVideo from ..gpmf import gpmf_gps_filter from ..telemetry import GPSPoint -from . import utils as video_utils from .geotag_from_generic import GeotagVideosFromGeneric LOG = logging.getLogger(__name__) @@ -57,15 +56,6 @@ def geotag_video(element: ET.Element) -> types.VideoMetadataOrError: if not points: raise exceptions.MapillaryGPSNoiseError("GPS is too noisy") - stationary = video_utils.is_video_stationary( - video_utils.get_max_distance_from_start( - [(p.lat, p.lon) for p in points] - ) - ) - - if stationary: - raise exceptions.MapillaryStationaryVideoError("Stationary video") - video_metadata = types.VideoMetadata( video_path, filesize=utils.get_file_size(video_path), diff --git a/mapillary_tools/geotag/geotag_videos_from_video.py b/mapillary_tools/geotag/geotag_videos_from_video.py index 100b93cf9..4f7092055 100644 --- a/mapillary_tools/geotag/geotag_videos_from_video.py +++ b/mapillary_tools/geotag/geotag_videos_from_video.py @@ -11,7 +11,7 @@ from ..gpmf import gpmf_gps_filter, gpmf_parser from ..mp4 import simple_mp4_parser as sparser from ..telemetry import GPSPoint -from . import blackvue_parser, utils as video_utils +from . import blackvue_parser from .geotag_from_generic import GeotagVideosFromGeneric LOG = logging.getLogger(__name__) @@ -164,14 +164,6 @@ def geotag_video( ) if not video_metadata.points: raise exceptions.MapillaryGPSNoiseError("GPS is too noisy") - - stationary = video_utils.is_video_stationary( - video_utils.get_max_distance_from_start( - [(p.lat, p.lon) for p in video_metadata.points] - ) - ) - if stationary: - raise exceptions.MapillaryStationaryVideoError("Stationary video") except Exception as ex: if not isinstance(ex, exceptions.MapillaryDescriptionError): LOG.warning( diff --git a/mapillary_tools/geotag/utils.py b/mapillary_tools/geotag/utils.py index 7f2abdeb5..807820dff 100644 --- a/mapillary_tools/geotag/utils.py +++ b/mapillary_tools/geotag/utils.py @@ -9,22 +9,6 @@ from .. import geo -def is_video_stationary(max_distance_from_start: float) -> bool: - radius_threshold = 10 - return max_distance_from_start < radius_threshold - - -def get_max_distance_from_start(latlons: T.Sequence[tuple[float, float]]) -> float: - """ - Returns the radius of an entire GPS track. Used to calculate whether or not the entire sequence was just stationary video - Takes a sequence of points as input - """ - if not latlons: - return 0 - start = latlons[0] - return max(geo.gps_distance(start, latlon) for latlon in latlons) - - def convert_points_to_gpx_segment(points: T.Sequence[geo.Point]): gpx_segment = gpxpy.gpx.GPXTrackSegment() for point in points: diff --git a/mapillary_tools/process_sequence_properties.py b/mapillary_tools/process_sequence_properties.py index 1faac48df..9c4e5ed8d 100644 --- a/mapillary_tools/process_sequence_properties.py +++ b/mapillary_tools/process_sequence_properties.py @@ -229,49 +229,69 @@ def _avg_speed(sequence: T.Sequence[geo.PointLike]) -> float: return total_distance / time_diff +def _is_video_stationary( + sequence: T.Sequence[geo.PointLike], max_radius_in_meters: float +) -> bool: + if not sequence: + return 0.0 <= max_radius_in_meters + + start = (sequence[0].lat, sequence[0].lon) + for p in sequence: + distance = geo.gps_distance(start, (p.lat, p.lon)) + if distance > max_radius_in_meters: + return False + + return True + + def _check_video_limits( video_metadatas: T.Sequence[types.VideoMetadata], max_sequence_filesize_in_bytes: int, max_avg_speed: float, + max_radius_for_stationary_check: float, ) -> T.Tuple[T.List[types.VideoMetadata], T.List[types.ErrorMetadata]]: output_video_metadatas: T.List[types.VideoMetadata] = [] error_metadatas: T.List[types.ErrorMetadata] = [] for video_metadata in video_metadatas: - if video_metadata.filesize is None: - filesize = utils.get_file_size(video_metadata.filename) - else: - filesize = video_metadata.filesize + try: + is_stationary = _is_video_stationary( + video_metadata.points, + max_radius_in_meters=max_radius_for_stationary_check, + ) + if is_stationary: + raise exceptions.MapillaryStationaryVideoError("Stationary video") - if filesize > max_sequence_filesize_in_bytes: - error_metadatas.append( - types.describe_error_metadata( - exc=exceptions.MapillaryFileTooLargeError( - f"Video file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)", - ), - filename=video_metadata.filename, - filetype=video_metadata.filetype, + video_filesize = ( + utils.get_file_size(video_metadata.filename) + if video_metadata.filesize is None + else video_metadata.filesize + ) + if video_filesize > max_sequence_filesize_in_bytes: + raise exceptions.MapillaryFileTooLargeError( + f"Video file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)", ) + + contains_null_island = any( + p.lat == 0 and p.lon == 0 for p in video_metadata.points ) - elif any(p.lat == 0 and p.lon == 0 for p in video_metadata.points): - error_metadatas.append( - types.describe_error_metadata( - exc=exceptions.MapillaryNullIslandError( - "Found GPS coordinates in Null Island (0, 0)", - ), - filename=video_metadata.filename, - filetype=video_metadata.filetype, + if contains_null_island: + raise exceptions.MapillaryNullIslandError( + "Found GPS coordinates in Null Island (0, 0)", ) + + too_fast = ( + len(video_metadata.points) >= 2 + and _avg_speed(video_metadata.points) > max_avg_speed ) - elif ( - len(video_metadata.points) >= 2 - and _avg_speed(video_metadata.points) > max_avg_speed - ): + if too_fast: + raise exceptions.MapillaryCaptureSpeedTooFastError( + f"Capture speed too fast (exceeds {round(max_avg_speed, 3)} m/s)", + ) + except exceptions.MapillaryDescriptionError as ex: error_metadatas.append( types.describe_error_metadata( - exc=exceptions.MapillaryCaptureSpeedTooFastError( - f"Capture speed is too fast (exceeds {round(max_avg_speed, 3)} m/s)", - ), + exc=ex, filename=video_metadata.filename, filetype=video_metadata.filetype, ) @@ -297,46 +317,42 @@ def _check_sequences_by_limits( output_errors: T.List[types.ErrorMetadata] = [] for sequence in input_sequences: - filesize = 0 - for image in sequence: - if image.filesize is None: - filesize += utils.get_file_size(image.filename) - else: - filesize += image.filesize - - if filesize > max_sequence_filesize_in_bytes: - for image in sequence: - output_errors.append( - types.describe_error_metadata( - exc=exceptions.MapillaryFileTooLargeError( - f"Sequence file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)", - ), - filename=image.filename, - filetype=types.FileType.IMAGE, - ) + sequence_filesize = sum( + utils.get_file_size(image.filename) + if image.filesize is None + else image.filesize + for image in sequence + ) + + try: + if sequence_filesize > max_sequence_filesize_in_bytes: + raise exceptions.MapillaryFileTooLargeError( + f"Sequence file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)", ) - elif any(image.lat == 0 and image.lon == 0 for image in sequence): - for image in sequence: - output_errors.append( - types.describe_error_metadata( - exc=exceptions.MapillaryNullIslandError( - "Found GPS coordinates in Null Island (0, 0)", - ), - filename=image.filename, - filetype=types.FileType.IMAGE, - ) + + contains_null_island = any( + image.lat == 0 and image.lon == 0 for image in sequence + ) + if contains_null_island: + raise exceptions.MapillaryNullIslandError( + "Found GPS coordinates in Null Island (0, 0)", + ) + + too_fast = len(sequence) >= 2 and _avg_speed(sequence) > max_avg_speed + if too_fast: + raise exceptions.MapillaryCaptureSpeedTooFastError( + f"Capture speed too fast (exceeds {round(max_avg_speed, 3)} m/s)", ) - elif len(sequence) >= 2 and _avg_speed(sequence) > max_avg_speed: + except exceptions.MapillaryDescriptionError as ex: for image in sequence: output_errors.append( types.describe_error_metadata( - exc=exceptions.MapillaryCaptureSpeedTooFastError( - f"Capture speed is too fast (exceeds {round(max_avg_speed, 3)} m/s)", - ), + exc=ex, filename=image.filename, filetype=types.FileType.IMAGE, ) ) + else: output_sequences.append(sequence) @@ -596,6 +612,7 @@ def process_sequence_properties( video_metadatas, max_sequence_filesize_in_bytes=max_sequence_filesize_in_bytes, max_avg_speed=max_avg_speed, + max_radius_for_stationary_check=10.0, ) error_metadatas.extend(video_error_metadatas) diff --git a/mapillary_tools/video_data_extraction/extract_video_data.py b/mapillary_tools/video_data_extraction/extract_video_data.py index b18d1f05b..b0b334e78 100644 --- a/mapillary_tools/video_data_extraction/extract_video_data.py +++ b/mapillary_tools/video_data_extraction/extract_video_data.py @@ -6,7 +6,6 @@ import tqdm from .. import exceptions, geo, utils -from ..geotag import utils as video_utils from ..gpmf import gpmf_gps_filter from ..telemetry import GPSPoint from ..types import ( @@ -165,11 +164,4 @@ def _sanitize_points(points: T.Sequence[geo.Point]) -> T.Sequence[geo.Point]: if not points: raise exceptions.MapillaryGPSNoiseError("GPS is too noisy") - stationary = video_utils.is_video_stationary( - video_utils.get_max_distance_from_start([(p.lat, p.lon) for p in points]) - ) - - if stationary: - raise exceptions.MapillaryStationaryVideoError("Stationary video") - return points diff --git a/tests/unit/test_sequence_processing.py b/tests/unit/test_sequence_processing.py index 9abca3cea..144c70209 100644 --- a/tests/unit/test_sequence_processing.py +++ b/tests/unit/test_sequence_processing.py @@ -545,7 +545,7 @@ def test_video_error(tmpdir: py.path.local): points=[ geo.Point(1, -0.00001, -0.00001, 1, angle=None), geo.Point(1, 0, 0, 1, angle=None), - geo.Point(1, 0.00001, 0.00001, 1, angle=None), + geo.Point(1, 0.00010, 0.00010, 1, angle=None), ], make="hello", model="world", @@ -566,7 +566,10 @@ def test_video_error(tmpdir: py.path.local): types.VideoMetadata( Path(curdir) / Path("test_video_file_too_large.mp4"), types.FileType.VIDEO, - points=[geo.Point(1, 1, 1, 1, angle=None)], + points=[ + geo.Point(1, 1, 1, 1, angle=None), + geo.Point(2, 1.0002, 1.0002, 1, angle=None), + ], make="hello", model="world", filesize=1024 * 1024 * 1024 * 200, @@ -574,7 +577,10 @@ def test_video_error(tmpdir: py.path.local): types.VideoMetadata( Path(curdir) / Path("test_good.mp4"), types.FileType.VIDEO, - points=[geo.Point(1, 1, 1, 1, angle=None)], + points=[ + geo.Point(1, 1, 1, 1, angle=None), + geo.Point(2, 1.0002, 1.0002, 1, angle=None), + ], make="hello", model="world", filesize=123,