Skip to content

Commit d7ce843

Browse files
authored
Merge branch 'main' into remove-sequence-file-size-check
2 parents 9dba39c + d022852 commit d7ce843

3 files changed

Lines changed: 263 additions & 45 deletions

File tree

mapillary_tools/constants.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ def _parse_scaled_integers(
143143
)
144144
# Zig-zag detection parameters
145145
ZIGZAG_WINDOW_SIZE = int(os.getenv(_ENV_PREFIX + "ZIGZAG_WINDOW_SIZE", 5))
146-
ZIGZAG_BACKTRACK_THRESHOLD = float(
147-
os.getenv(_ENV_PREFIX + "ZIGZAG_BACKTRACK_THRESHOLD", 0.8)
146+
ZIGZAG_DEVIATION_THRESHOLD = float(
147+
os.getenv(_ENV_PREFIX + "ZIGZAG_DEVIATION_THRESHOLD", 0.8)
148148
)
149-
ZIGZAG_MIN_BACKTRACKS = int(os.getenv(_ENV_PREFIX + "ZIGZAG_MIN_BACKTRACKS", 1))
149+
ZIGZAG_MIN_DEVIATIONS = int(os.getenv(_ENV_PREFIX + "ZIGZAG_MIN_DEVIATIONS", 1))
150150
ZIGZAG_MIN_DISTANCE = float(os.getenv(_ENV_PREFIX + "ZIGZAG_MIN_DISTANCE", 30))
151151

152152

mapillary_tools/process_sequence_properties.py

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -434,25 +434,27 @@ def _check_sequences_duplication(
434434
def _check_sequences_zigzag(
435435
input_sequences: T.Sequence[PointSequence],
436436
window_size: int = 5,
437-
backtrack_threshold: float = 0.8,
438-
min_backtracks: int = 1,
437+
deviation_threshold: float = 0.8,
438+
min_deviations: int = 1,
439439
min_distance: float = 50.0,
440440
) -> tuple[list[PointSequence], list[types.ErrorMetadata]]:
441441
"""
442442
Check for zig-zag GPS patterns where images jump back and forth between locations.
443443
444-
Detects spatial backtracking - when an image returns closer to earlier images
444+
Detects spatial deviations - when an image returns closer to earlier images
445445
than the previous image was. This catches zig-zag patterns where the sequence
446446
jumps to a different location and then returns.
447447
448+
Only marks deviation points as errors, keeping the main path intact.
449+
448450
Args:
449451
input_sequences: List of image sequences to check
450-
window_size: Number of images to look back when checking for backtracking
451-
backtrack_threshold: Ratio threshold - if dist_curr < dist_prev * threshold,
452-
it's considered backtracking
453-
min_backtracks: Minimum number of backtrack events to fail the sequence
452+
window_size: Number of images to look back when checking for deviations
453+
deviation_threshold: Ratio threshold - if dist_curr < dist_prev * threshold,
454+
it's considered a deviation
455+
min_deviations: Minimum number of deviation events to mark errors
454456
min_distance: Minimum distance (in meters) between consecutive images (prev to curr)
455-
to consider for backtracking. This filters out small-scale
457+
to consider for deviation detection. This filters out small-scale
456458
movements like U-turns.
457459
"""
458460
output_sequences: list[PointSequence] = []
@@ -464,8 +466,8 @@ def _check_sequences_zigzag(
464466
output_sequences.append(sequence)
465467
continue
466468

467-
backtrack_count = 0
468-
backtrack_locations: list[str] = []
469+
# Track which indices are detected as deviations
470+
deviation_indices: set[int] = set()
469471

470472
for i in range(window_size, len(sequence)):
471473
curr = sequence[i]
@@ -481,36 +483,70 @@ def _check_sequences_zigzag(
481483
# Distance from previous image to reference
482484
dist_prev = geo.gps_distance((prev.lat, prev.lon), (ref.lat, ref.lon))
483485

484-
# Backtracking: current is closer to reference than previous was
486+
# Deviation: current is closer to reference than previous was
485487
# Only check if the jump between prev and curr is above min_distance
486488
if (
487489
dist_prev_curr > min_distance
488-
and dist_curr < dist_prev * backtrack_threshold
490+
and dist_curr < dist_prev * deviation_threshold
489491
):
490-
backtrack_count += 1
491-
backtrack_locations.append(curr.filename.name)
492492
LOG.debug(
493-
f"Potential zigzag at {curr.filename.name}: "
494-
f"dist_curr={dist_curr:.1f}m < dist_prev={dist_prev:.1f}m * {backtrack_threshold}, "
493+
f"Zigzag detected at {prev.filename.name}: "
494+
f"dist_curr={dist_curr:.1f}m < dist_prev={dist_prev:.1f}m * {deviation_threshold}, "
495495
f"jump={dist_prev_curr:.1f}m"
496496
)
497497

498-
if backtrack_count >= min_backtracks:
499-
locations_preview = ", ".join(backtrack_locations[:5])
500-
if len(backtrack_locations) > 5:
501-
locations_preview += "..."
498+
# Mark prev as deviation (it's the point that jumped away)
499+
deviation_indices.add(i - 1)
502500

503-
ex = exceptions.MapillaryZigZagError(
504-
f"GPS zig-zag pattern detected: {backtrack_count} backtrack events "
505-
f"found (at: {locations_preview})"
506-
)
507-
LOG.error(f"{_sequence_name(sequence)}: {ex}")
508-
for image in sequence:
501+
# Walk backwards from prev to ref+1 to find more deviation points
502+
# We're looking for deviations between prev and ref
503+
# Use the same check as above: compare distance to ref and jump to curr
504+
for j in range(i - 2, i - window_size, -1): # Stop at ref+1
505+
point_j = sequence[j]
506+
507+
# Distance from j to ref
508+
dist_j_to_ref = geo.gps_distance(
509+
(point_j.lat, point_j.lon), (ref.lat, ref.lon)
510+
)
511+
# Distance from j to curr
512+
dist_j_to_curr = geo.gps_distance(
513+
(point_j.lat, point_j.lon), (curr.lat, curr.lon)
514+
)
515+
516+
# Same check as original: j is a deviation if it's farther from ref
517+
# than curr is, and the jump from j to curr is significant
518+
if (
519+
dist_j_to_curr > min_distance
520+
and dist_curr < dist_j_to_ref * deviation_threshold
521+
):
522+
deviation_indices.add(j)
523+
LOG.debug(
524+
f"Backwards walk: {point_j.filename.name} also marked as deviation"
525+
)
526+
else:
527+
# j is on the normal path, stop walking backwards
528+
break
529+
530+
if len(deviation_indices) >= min_deviations:
531+
# Create errors only for deviation points
532+
for idx in sorted(deviation_indices):
533+
image = sequence[idx]
534+
ex = exceptions.MapillaryZigZagError("GPS zig-zag deviation detected")
535+
LOG.error(f"{image.filename.name}: {ex}")
509536
output_errors.append(
510537
types.describe_error_metadata(
511538
exc=ex, filename=image.filename, filetype=types.FileType.IMAGE
512539
)
513540
)
541+
542+
# Keep non-deviation points in output sequence
543+
non_deviation_points = [
544+
sequence[idx]
545+
for idx in range(len(sequence))
546+
if idx not in deviation_indices
547+
]
548+
if non_deviation_points:
549+
output_sequences.append(non_deviation_points)
514550
else:
515551
output_sequences.append(sequence)
516552

@@ -823,8 +859,8 @@ def process_sequence_properties(
823859
sequences, errors = _check_sequences_zigzag(
824860
sequences,
825861
window_size=constants.ZIGZAG_WINDOW_SIZE,
826-
backtrack_threshold=constants.ZIGZAG_BACKTRACK_THRESHOLD,
827-
min_backtracks=constants.ZIGZAG_MIN_BACKTRACKS,
862+
deviation_threshold=constants.ZIGZAG_DEVIATION_THRESHOLD,
863+
min_deviations=constants.ZIGZAG_MIN_DEVIATIONS,
828864
min_distance=constants.ZIGZAG_MIN_DISTANCE,
829865
)
830866
error_metadatas.extend(errors)

0 commit comments

Comments
 (0)