# How to Handle Loop Closures and Use the Loop Scene Example for Trajectory Correction in LingBot-Map

> Learn how LingBot-Map handles loop closures and uses scene examples for trajectory correction. Optimize your robot's path and create seamless closed loops.

- Repository: [Robbyant/lingbot-map](https://github.com/Robbyant/lingbot-map)
- Tags: how-to-guide
- Published: 2026-07-30

---

**LingBot-Map detects loop closures by comparing current frames against stored key-frames in its streaming pipeline, then corrects accumulated drift using a global pose-graph optimizer that adjusts the entire trajectory to create a seamless closed loop.**

The LingBot-Map repository by Robbyant provides a real-time dense mapping system that processes video sequences through a neural network to estimate camera poses and reconstruct 3D geometry. When the camera revisits a previously mapped area, the system triggers **loop closure** events to correct accumulated drift. Understanding how to handle loop closures and use the loop scene example for trajectory correction in LingBot-Map is essential for achieving accurate, globally consistent reconstructions on long sequences.

## Understanding Loop Closure Detection

LingBot-Map processes video as a stream of frames using **streaming mode**, where each incoming frame is processed sequentially in order. The system stores **key-frames** at regular intervals to balance memory usage against the ability to recognize previously visited locations.

When the current camera pose aligns closely with a previously stored key-frame, the system identifies a loop closure. The underlying **pose-graph optimizer**, implemented in [`lingbot_map/models/gct_stream.py`](https://github.com/Robbyant/lingbot-map/blob/main/lingbot_map/models/gct_stream.py) and [`lingbot_map/models/gct_stream_window_v2.py`](https://github.com/Robbyant/lingbot-map/blob/main/lingbot_map/models/gct_stream_window_v2.py), solves a global least-squares problem that distributes the correction across the entire trajectory rather than applying a local adjustment.

## Running the Loop Scene Example

The repository includes a ready-made **loop scene** in `example/loop` that demonstrates trajectory correction on a synthetic sequence intentionally designed to loop back on itself. Follow these steps to observe the correction mechanism in action:

1. **Download the pre-trained model** checkpoint referenced in the repository README.

2. **Run the demo on the loop scene** using the default streaming configuration:

   ```bash
   python demo.py \
       --model_path /path/to/lingbot-map.pt \
       --image_folder example/loop \
       --mask_sky
   ```

3. **Observe the correction** in the browser-based viewer (via **viser**) at `http://localhost:8080`. The first pass through the loop may show drift, but when the camera returns to the start region, the model detects the loop and refines the pose graph. The visualizer automatically updates to display the smooth, closed trajectory.

## Configuring Trajectory Correction Parameters

Fine-tuning the correction behavior requires adjusting key-frame storage intervals and processing modes based on sequence length and memory constraints.

### Adjusting Key-Frame Intervals

The `--keyframe_interval` flag controls how often the system stores a full key-frame with KV-cache. Reducing this interval provides the optimizer with finer granularity for realignment after loop closures:

```bash
python demo.py \
    --model_path /path/to/lingbot-map.pt \
    --image_folder example/loop \
    --keyframe_interval 2 \
    --mask_sky

```

### Using Windowed Mode for Long Sequences

For sequences involving thousands of frames, use **windowed mode** to segment the stream into overlapping windows. Each window can incorporate loop-closure updates independently without overwhelming memory:

```bash
python demo.py \
    --model_path /path/to/lingbot-map.pt \
    --image_folder example/loop \
    --mode windowed \
    --window_size 128 \
    --overlap_keyframes 16 \
    --keyframe_interval 2 \
    --mask_sky

```

This configuration processes the sequence in chunks of 128 frames with 16 overlapping key-frames between windows, ensuring continuity while maintaining computational efficiency.

## Programmatic API Usage

Integrate loop-closure handling directly into Python applications using the `LingBotMap` class:

```python
from lingbot_map import LingBotMap

# Initialize the model

mapper = LingBotMap(model_path="lingbot-map.pt")

# Process the loop scene with custom parameters

trajectory = mapper.run(
    image_folder="example/loop",
    keyframe_interval=2,
    mode="windowed",
    window_size=128,
    overlap_keyframes=16,
    mask_sky=True,
)

# Access the drift-corrected poses

print(trajectory)

```

The returned `trajectory` object contains the globally optimized camera poses after loop-closure correction has been applied.

## Key Source Files and Implementation Details

Understanding the source structure helps when customizing the correction pipeline:

- **[`demo.py`](https://github.com/Robbyant/lingbot-map/blob/main/demo.py)** – Entry point that parses CLI flags, runs streaming or windowed inference, and launches the visualizer.
- **`example/loop/`** – Directory containing the synthetic image sequence forming a closed loop for demonstration purposes.
- **[`lingbot_map/models/gct_stream.py`](https://github.com/Robbyant/lingbot-map/blob/main/lingbot_map/models/gct_stream.py)** – Implements the streaming phase-2 loop and the pose-graph optimizer that handles loop closures.
- **[`lingbot_map/models/gct_stream_window_v2.py`](https://github.com/Robbyant/lingbot-map/blob/main/lingbot_map/models/gct_stream_window_v2.py)** – Provides the windowed streaming variant for processing long sequences with limited memory.
- **[`lingbot_map/vis/point_cloud_viewer.py`](https://github.com/Robbyant/lingbot-map/blob/main/lingbot_map/vis/point_cloud_viewer.py)** – Visualizer that displays the evolving point cloud and camera trajectory, automatically updating after loop-closure corrections.

## Summary

- LingBot-Map detects loop closures by matching current frames against stored key-frames in its streaming pipeline.
- The **pose-graph optimizer** in [`gct_stream.py`](https://github.com/Robbyant/lingbot-map/blob/main/gct_stream.py) modules solves a global least-squares problem to distribute corrections across the entire trajectory.
- The **`example/loop`** scene provides a ready-made test case for observing drift correction in real-time.
- Use `--keyframe_interval` to control the granularity of correction, with lower values enabling finer adjustments.
- **Windowed mode** (`--mode windowed`) processes long sequences in overlapping chunks to manage memory while preserving loop-closure capabilities.
- The **viser** visualizer at `localhost:8080` automatically displays corrected trajectories when loop closures occur.

## Frequently Asked Questions

### What is a loop closure in the context of LingBot-Map?

A loop closure occurs when the camera revisits a previously mapped area, allowing the system to recognize the location and correct accumulated drift. In LingBot-Map, this detection triggers the pose-graph optimizer to adjust the entire trajectory so that the start and end points of the loop align geometrically, eliminating accumulated errors from odometry drift.

### How does LingBot-Map detect loop closures during streaming?

The system compares the current frame's pose against stored key-frames maintained at intervals defined by `--keyframe_interval`. When the spatial distance between the current estimate and a historical key-frame falls below a threshold, the system registers a loop edge in the pose graph, which the optimizer in [`gct_stream.py`](https://github.com/Robbyant/lingbot-map/blob/main/gct_stream.py) uses to compute global corrections.

### When should I use windowed mode instead of standard streaming?

Use **windowed mode** when processing sequences containing thousands of frames that exceed available GPU memory for maintaining a full key-frame cache. By segmenting the stream into overlapping windows (configured via `--window_size` and `--overlap_keyframes`), the system restricts the optimization to local segments while preserving the ability to close loops across window boundaries.

### How do I verify that loop closure correction has been applied successfully?

Run the demo with the `--image_folder example/loop` argument and observe the trajectory in the viser viewer at `http://localhost:8080`. A successful correction shows the camera path forming a smooth, closed loop without gaps or misalignment at the closure point, whereas uncorrected drift would display the start and end positions at different coordinates.