Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dfki-ric/uxo-dataset2024/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The MatchingContext class provides a unified interface for accessing and synchronizing multi-modal data from ARIS sonar recordings, GoPro video, and gantry positioning systems. It handles temporal alignment, metadata loading, and frame-by-frame data access across all three data sources. Module Path: scripts/common/matching_context.py

Class: MatchingContext

Constructor

MatchingContext(
    aris_dir: str,
    gantry_file: str,
    gopro_file: str,
    polar_img_format: str = 'png'
)
aris_dir
str
required
Path to the directory containing ARIS data files, including:
  • Raw frames (.pgm files)
  • Polar-transformed frames in polar/ subdirectory
  • {basename}_metadata.yaml - File-level metadata
  • {basename}_frames.csv - Per-frame metadata
  • {basename}_marks.yaml - Optional motion onset markers
gantry_file
str
required
Path to the gantry CSV data file containing timestamp and position columns
gopro_file
str
required
Path to the GoPro video file (MP4, AVI, etc.). Pass empty string or None if no GoPro data available
polar_img_format
str
default:"png"
Image format for polar-transformed ARIS frames (e.g., ‘png’, ‘jpg’)

Key Properties

ARIS Properties

aris_basename
str
Base name of the ARIS recording (derived from directory name)
aris_frames_raw
list[str]
Sorted list of file paths to raw ARIS frame images (.pgm format)
aris_frames_polar
list[str] | None
Sorted list of file paths to polar-transformed ARIS frames, or None if unavailable
aris_file_meta
dict
File-level metadata loaded from YAML
aris_frames_meta
pd.DataFrame
Per-frame metadata with columns matching FrameHeaderFields enum
aris_marks_meta
dict | None
Manual marks/annotations, including motion onset frame if available
aris_frames_total
int
Total number of ARIS frames in the recording
aris_t0
int
Start timestamp of ARIS recording (microseconds since epoch)
aris_duration
int
Duration of ARIS recording in microseconds
aris_motion_onset
int | None
Frame index where motion begins, if marked
aris_start_frame
int
Starting frame index for active region (defaults to onset if marked, else 0)
aris_end_frame
int
Ending frame index for active region (defaults to last frame)
aris_active_frames
int
Number of frames in the active region
aris_active_duration
int
Duration of active region in microseconds
aris_tick_step
int
Frame step size for playback/processing

Gantry Properties

gantry_basename
str
Base name of the gantry data file
gantry_meta
pd.Series
Metadata row for this gantry recording from the metadata CSV
gantry_data
pd.DataFrame
Gantry position data with columns: timestamp_us, x, y, z
gantry_t0
int
Start timestamp of gantry recording (microseconds since epoch)
gantry_onset
int
Timestamp when motion begins (microseconds since epoch)
gantry_duration
int
Duration of gantry recording in microseconds
gantry_offset
int
Time offset from start to motion onset in microseconds

GoPro Properties

has_gopro
bool
Whether GoPro video is available for this context
gopro_basename
str
Base name of the GoPro video file
gopro_clip
cv2.VideoCapture
OpenCV video capture object for the GoPro recording
gopro_frame_idx
int
Current GoPro frame index
gopro_frames_total
int
Total number of frames in the GoPro video
gopro_fps
float
GoPro video frame rate
gopro_offset
int
Frame offset for synchronizing GoPro with ARIS (adjustable)

Methods

get_aris_frametime

def get_aris_frametime(frame_idx: int) -> int
Retrieves the timestamp for a specific ARIS frame.
frame_idx
int
required
Frame index (0-based)
timestamp
int
Frame timestamp in microseconds since epoch (from FrameTime field)

get_aris_frametime_ext

def get_aris_frametime_ext(frame_idx: int) -> int
Retrieves or extrapolates timestamp for frames outside the recorded range.
frame_idx
int
required
Frame index (can be negative or beyond recording)
timestamp
int
Actual or extrapolated timestamp in microseconds since epoch

aristime_to_gopro_idx

def aristime_to_gopro_idx(aris_frametime: int) -> int
Converts ARIS timestamp to corresponding GoPro frame index.
aris_frametime
int
required
ARIS frame timestamp in microseconds since epoch
gopro_idx
int
Corresponding GoPro frame index, accounting for offset

get_gopro_frame

def get_gopro_frame(
    aris_frametime: int,
    exact: bool = True
) -> tuple[np.ndarray | None, int]
Retrieves the GoPro frame corresponding to an ARIS timestamp.
aris_frametime
int
required
ARIS frame timestamp in microseconds since epoch
exact
bool
default:"True"
If True, returns None if exact frame positioning fails
frame
np.ndarray | None
GoPro frame as BGR image array, or None if unavailable/positioning failed
frame_idx
int
Actual GoPro frame index that was retrieved

get_usable_gopro_range

def get_usable_gopro_range() -> tuple[int, int]
Calculates the valid range for GoPro offset adjustment.
range_min
int
Minimum useful offset (negative value)
range_max
int
Maximum useful offset (total GoPro frames)

get_gantry_odom

def get_gantry_odom(
    aris_frametime: int
) -> tuple[tuple[float, float, float], int]
Interpolates gantry position at a given ARIS timestamp.
aris_frametime
int
required
ARIS frame timestamp in microseconds since epoch
position
tuple[float, float, float]
Interpolated (x, y, z) position in meters
timestamp
int
Actual gantry timestamp used for interpolation (clamped to valid range)

Helper Functions

folder_basename

def folder_basename(s: str) -> str
Extracts the base name from a file or directory path, handling trailing slashes.

get_aris_metadata

def get_aris_metadata(aris_data_dir: str) -> tuple[dict, pd.DataFrame, dict | None]
Loads and caches ARIS metadata files (file metadata, frame metadata, and marks).

get_gopro_metadata

def get_gopro_metadata(gopro_files_dir: str) -> pd.DataFrame
Loads and caches GoPro metadata CSV.

get_gantry_metadata

def get_gantry_metadata(gantry_files_dir: str) -> pd.DataFrame
Loads and caches gantry metadata CSV.

Usage Example

import cv2
import numpy as np
from scripts.common.matching_context import MatchingContext

# Initialize context
ctx = MatchingContext(
    aris_dir='/data/recordings/rec_001_aris',
    gantry_file='/data/recordings/gantry/rec_001.csv',
    gopro_file='/data/recordings/gopro/rec_001.mp4'
)

print(f"Recording: {ctx.recording_label}")
print(f"ARIS frames: {ctx.aris_frames_total}")
print(f"Active region: frames {ctx.aris_start_frame}-{ctx.aris_end_frame}")
print(f"Duration: {ctx.aris_active_duration / 1e6:.2f} seconds")

# Process synchronized data
for aris_idx in range(ctx.aris_start_frame, ctx.aris_end_frame, ctx.aris_tick_step):
    # Load ARIS frame
    aris_frame = cv2.imread(ctx.aris_frames_raw[aris_idx], cv2.IMREAD_GRAYSCALE)
    
    # Get timestamp
    aris_time = ctx.get_aris_frametime(aris_idx)
    
    # Get corresponding GoPro frame
    if ctx.has_gopro:
        gopro_frame, gopro_idx = ctx.get_gopro_frame(aris_time)
        if gopro_frame is not None:
            print(f"ARIS frame {aris_idx} synced with GoPro frame {gopro_idx}")
    
    # Get gantry position
    (x, y, z), gantry_time = ctx.get_gantry_odom(aris_time)
    print(f"Position at frame {aris_idx}: ({x:.3f}, {y:.3f}, {z:.3f}) m")

# Adjust GoPro synchronization
ctx.gopro_offset = 30  # Delay GoPro by 30 frames

Common Workflows

Manual Synchronization

# Display both streams for manual alignment
aris_idx = ctx.aris_start_frame
while True:
    aris_frame = cv2.imread(ctx.aris_frames_raw[aris_idx], cv2.IMREAD_GRAYSCALE)
    aris_time = ctx.get_aris_frametime(aris_idx)
    
    gopro_frame, _ = ctx.get_gopro_frame(aris_time)
    
    # Display side-by-side
    cv2.imshow('ARIS', aris_frame)
    if gopro_frame is not None:
        cv2.imshow('GoPro', gopro_frame)
    
    key = cv2.waitKey(30)
    if key == ord('q'):
        break
    elif key == ord('a'):  # Advance GoPro
        ctx.gopro_offset += 1
    elif key == ord('d'):  # Delay GoPro
        ctx.gopro_offset -= 1
    
    aris_idx = (aris_idx + 1) % ctx.aris_frames_total

Position-Based Analysis

import matplotlib.pyplot as plt

# Track object position over time
positions = []
for aris_idx in range(ctx.aris_start_frame, ctx.aris_end_frame):
    aris_time = ctx.get_aris_frametime(aris_idx)
    (x, y, z), _ = ctx.get_gantry_odom(aris_time)
    positions.append((x, y, z))

positions = np.array(positions)

# Plot trajectory
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(positions[:, 0], positions[:, 1])
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.title('XY Trajectory')

plt.subplot(1, 2, 2)
plt.plot(positions[:, 2])
plt.xlabel('Frame')
plt.ylabel('Z (m)')
plt.title('Depth Profile')
plt.show()

Build docs developers (and LLMs) love