Skip to content

Commit e4f0708

Browse files
authored
refactor: move stationary check from geotagging to process_sequence_properties.py (#726)
* refactor: move stationary check from geotagging to process_sequence_properties.py * refactor * refactor * fix tests
1 parent f76354e commit e4f0708

6 files changed

Lines changed: 85 additions & 104 deletions

File tree

mapillary_tools/geotag/geotag_videos_from_exiftool_video.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from ..exiftool_read_video import ExifToolReadVideo
1111
from ..gpmf import gpmf_gps_filter
1212
from ..telemetry import GPSPoint
13-
from . import utils as video_utils
1413
from .geotag_from_generic import GeotagVideosFromGeneric
1514

1615
LOG = logging.getLogger(__name__)
@@ -57,15 +56,6 @@ def geotag_video(element: ET.Element) -> types.VideoMetadataOrError:
5756
if not points:
5857
raise exceptions.MapillaryGPSNoiseError("GPS is too noisy")
5958

60-
stationary = video_utils.is_video_stationary(
61-
video_utils.get_max_distance_from_start(
62-
[(p.lat, p.lon) for p in points]
63-
)
64-
)
65-
66-
if stationary:
67-
raise exceptions.MapillaryStationaryVideoError("Stationary video")
68-
6959
video_metadata = types.VideoMetadata(
7060
video_path,
7161
filesize=utils.get_file_size(video_path),

mapillary_tools/geotag/geotag_videos_from_video.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ..gpmf import gpmf_gps_filter, gpmf_parser
1212
from ..mp4 import simple_mp4_parser as sparser
1313
from ..telemetry import GPSPoint
14-
from . import blackvue_parser, utils as video_utils
14+
from . import blackvue_parser
1515
from .geotag_from_generic import GeotagVideosFromGeneric
1616

1717
LOG = logging.getLogger(__name__)
@@ -164,14 +164,6 @@ def geotag_video(
164164
)
165165
if not video_metadata.points:
166166
raise exceptions.MapillaryGPSNoiseError("GPS is too noisy")
167-
168-
stationary = video_utils.is_video_stationary(
169-
video_utils.get_max_distance_from_start(
170-
[(p.lat, p.lon) for p in video_metadata.points]
171-
)
172-
)
173-
if stationary:
174-
raise exceptions.MapillaryStationaryVideoError("Stationary video")
175167
except Exception as ex:
176168
if not isinstance(ex, exceptions.MapillaryDescriptionError):
177169
LOG.warning(

mapillary_tools/geotag/utils.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,6 @@
99
from .. import geo
1010

1111

12-
def is_video_stationary(max_distance_from_start: float) -> bool:
13-
radius_threshold = 10
14-
return max_distance_from_start < radius_threshold
15-
16-
17-
def get_max_distance_from_start(latlons: T.Sequence[tuple[float, float]]) -> float:
18-
"""
19-
Returns the radius of an entire GPS track. Used to calculate whether or not the entire sequence was just stationary video
20-
Takes a sequence of points as input
21-
"""
22-
if not latlons:
23-
return 0
24-
start = latlons[0]
25-
return max(geo.gps_distance(start, latlon) for latlon in latlons)
26-
27-
2812
def convert_points_to_gpx_segment(points: T.Sequence[geo.Point]):
2913
gpx_segment = gpxpy.gpx.GPXTrackSegment()
3014
for point in points:

mapillary_tools/process_sequence_properties.py

Lines changed: 75 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -229,49 +229,69 @@ def _avg_speed(sequence: T.Sequence[geo.PointLike]) -> float:
229229
return total_distance / time_diff
230230

231231

232+
def _is_video_stationary(
233+
sequence: T.Sequence[geo.PointLike], max_radius_in_meters: float
234+
) -> bool:
235+
if not sequence:
236+
return 0.0 <= max_radius_in_meters
237+
238+
start = (sequence[0].lat, sequence[0].lon)
239+
for p in sequence:
240+
distance = geo.gps_distance(start, (p.lat, p.lon))
241+
if distance > max_radius_in_meters:
242+
return False
243+
244+
return True
245+
246+
232247
def _check_video_limits(
233248
video_metadatas: T.Sequence[types.VideoMetadata],
234249
max_sequence_filesize_in_bytes: int,
235250
max_avg_speed: float,
251+
max_radius_for_stationary_check: float,
236252
) -> T.Tuple[T.List[types.VideoMetadata], T.List[types.ErrorMetadata]]:
237253
output_video_metadatas: T.List[types.VideoMetadata] = []
238254
error_metadatas: T.List[types.ErrorMetadata] = []
239255

240256
for video_metadata in video_metadatas:
241-
if video_metadata.filesize is None:
242-
filesize = utils.get_file_size(video_metadata.filename)
243-
else:
244-
filesize = video_metadata.filesize
257+
try:
258+
is_stationary = _is_video_stationary(
259+
video_metadata.points,
260+
max_radius_in_meters=max_radius_for_stationary_check,
261+
)
262+
if is_stationary:
263+
raise exceptions.MapillaryStationaryVideoError("Stationary video")
245264

246-
if filesize > max_sequence_filesize_in_bytes:
247-
error_metadatas.append(
248-
types.describe_error_metadata(
249-
exc=exceptions.MapillaryFileTooLargeError(
250-
f"Video file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)",
251-
),
252-
filename=video_metadata.filename,
253-
filetype=video_metadata.filetype,
265+
video_filesize = (
266+
utils.get_file_size(video_metadata.filename)
267+
if video_metadata.filesize is None
268+
else video_metadata.filesize
269+
)
270+
if video_filesize > max_sequence_filesize_in_bytes:
271+
raise exceptions.MapillaryFileTooLargeError(
272+
f"Video file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)",
254273
)
274+
275+
contains_null_island = any(
276+
p.lat == 0 and p.lon == 0 for p in video_metadata.points
255277
)
256-
elif any(p.lat == 0 and p.lon == 0 for p in video_metadata.points):
257-
error_metadatas.append(
258-
types.describe_error_metadata(
259-
exc=exceptions.MapillaryNullIslandError(
260-
"Found GPS coordinates in Null Island (0, 0)",
261-
),
262-
filename=video_metadata.filename,
263-
filetype=video_metadata.filetype,
278+
if contains_null_island:
279+
raise exceptions.MapillaryNullIslandError(
280+
"Found GPS coordinates in Null Island (0, 0)",
264281
)
282+
283+
too_fast = (
284+
len(video_metadata.points) >= 2
285+
and _avg_speed(video_metadata.points) > max_avg_speed
265286
)
266-
elif (
267-
len(video_metadata.points) >= 2
268-
and _avg_speed(video_metadata.points) > max_avg_speed
269-
):
287+
if too_fast:
288+
raise exceptions.MapillaryCaptureSpeedTooFastError(
289+
f"Capture speed too fast (exceeds {round(max_avg_speed, 3)} m/s)",
290+
)
291+
except exceptions.MapillaryDescriptionError as ex:
270292
error_metadatas.append(
271293
types.describe_error_metadata(
272-
exc=exceptions.MapillaryCaptureSpeedTooFastError(
273-
f"Capture speed is too fast (exceeds {round(max_avg_speed, 3)} m/s)",
274-
),
294+
exc=ex,
275295
filename=video_metadata.filename,
276296
filetype=video_metadata.filetype,
277297
)
@@ -297,46 +317,42 @@ def _check_sequences_by_limits(
297317
output_errors: T.List[types.ErrorMetadata] = []
298318

299319
for sequence in input_sequences:
300-
filesize = 0
301-
for image in sequence:
302-
if image.filesize is None:
303-
filesize += utils.get_file_size(image.filename)
304-
else:
305-
filesize += image.filesize
306-
307-
if filesize > max_sequence_filesize_in_bytes:
308-
for image in sequence:
309-
output_errors.append(
310-
types.describe_error_metadata(
311-
exc=exceptions.MapillaryFileTooLargeError(
312-
f"Sequence file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)",
313-
),
314-
filename=image.filename,
315-
filetype=types.FileType.IMAGE,
316-
)
320+
sequence_filesize = sum(
321+
utils.get_file_size(image.filename)
322+
if image.filesize is None
323+
else image.filesize
324+
for image in sequence
325+
)
326+
327+
try:
328+
if sequence_filesize > max_sequence_filesize_in_bytes:
329+
raise exceptions.MapillaryFileTooLargeError(
330+
f"Sequence file size exceeds the maximum allowed file size ({max_sequence_filesize_in_bytes} bytes)",
317331
)
318-
elif any(image.lat == 0 and image.lon == 0 for image in sequence):
319-
for image in sequence:
320-
output_errors.append(
321-
types.describe_error_metadata(
322-
exc=exceptions.MapillaryNullIslandError(
323-
"Found GPS coordinates in Null Island (0, 0)",
324-
),
325-
filename=image.filename,
326-
filetype=types.FileType.IMAGE,
327-
)
332+
333+
contains_null_island = any(
334+
image.lat == 0 and image.lon == 0 for image in sequence
335+
)
336+
if contains_null_island:
337+
raise exceptions.MapillaryNullIslandError(
338+
"Found GPS coordinates in Null Island (0, 0)",
339+
)
340+
341+
too_fast = len(sequence) >= 2 and _avg_speed(sequence) > max_avg_speed
342+
if too_fast:
343+
raise exceptions.MapillaryCaptureSpeedTooFastError(
344+
f"Capture speed too fast (exceeds {round(max_avg_speed, 3)} m/s)",
328345
)
329-
elif len(sequence) >= 2 and _avg_speed(sequence) > max_avg_speed:
346+
except exceptions.MapillaryDescriptionError as ex:
330347
for image in sequence:
331348
output_errors.append(
332349
types.describe_error_metadata(
333-
exc=exceptions.MapillaryCaptureSpeedTooFastError(
334-
f"Capture speed is too fast (exceeds {round(max_avg_speed, 3)} m/s)",
335-
),
350+
exc=ex,
336351
filename=image.filename,
337352
filetype=types.FileType.IMAGE,
338353
)
339354
)
355+
340356
else:
341357
output_sequences.append(sequence)
342358

@@ -596,6 +612,7 @@ def process_sequence_properties(
596612
video_metadatas,
597613
max_sequence_filesize_in_bytes=max_sequence_filesize_in_bytes,
598614
max_avg_speed=max_avg_speed,
615+
max_radius_for_stationary_check=10.0,
599616
)
600617
error_metadatas.extend(video_error_metadatas)
601618

mapillary_tools/video_data_extraction/extract_video_data.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import tqdm
77

88
from .. import exceptions, geo, utils
9-
from ..geotag import utils as video_utils
109
from ..gpmf import gpmf_gps_filter
1110
from ..telemetry import GPSPoint
1211
from ..types import (
@@ -165,11 +164,4 @@ def _sanitize_points(points: T.Sequence[geo.Point]) -> T.Sequence[geo.Point]:
165164
if not points:
166165
raise exceptions.MapillaryGPSNoiseError("GPS is too noisy")
167166

168-
stationary = video_utils.is_video_stationary(
169-
video_utils.get_max_distance_from_start([(p.lat, p.lon) for p in points])
170-
)
171-
172-
if stationary:
173-
raise exceptions.MapillaryStationaryVideoError("Stationary video")
174-
175167
return points

tests/unit/test_sequence_processing.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ def test_video_error(tmpdir: py.path.local):
545545
points=[
546546
geo.Point(1, -0.00001, -0.00001, 1, angle=None),
547547
geo.Point(1, 0, 0, 1, angle=None),
548-
geo.Point(1, 0.00001, 0.00001, 1, angle=None),
548+
geo.Point(1, 0.00010, 0.00010, 1, angle=None),
549549
],
550550
make="hello",
551551
model="world",
@@ -566,15 +566,21 @@ def test_video_error(tmpdir: py.path.local):
566566
types.VideoMetadata(
567567
Path(curdir) / Path("test_video_file_too_large.mp4"),
568568
types.FileType.VIDEO,
569-
points=[geo.Point(1, 1, 1, 1, angle=None)],
569+
points=[
570+
geo.Point(1, 1, 1, 1, angle=None),
571+
geo.Point(2, 1.0002, 1.0002, 1, angle=None),
572+
],
570573
make="hello",
571574
model="world",
572575
filesize=1024 * 1024 * 1024 * 200,
573576
),
574577
types.VideoMetadata(
575578
Path(curdir) / Path("test_good.mp4"),
576579
types.FileType.VIDEO,
577-
points=[geo.Point(1, 1, 1, 1, angle=None)],
580+
points=[
581+
geo.Point(1, 1, 1, 1, angle=None),
582+
geo.Point(2, 1.0002, 1.0002, 1, angle=None),
583+
],
578584
make="hello",
579585
model="world",
580586
filesize=123,

0 commit comments

Comments
 (0)