Skip to main content

Sonar Context

CI
pip install sonar-context
Sonar Context SLAM on Aracati 2017: each forward-looking sonar keyframe gets a Sonar Context; revisits are found from it, verified by dense correlation and closed in a pose graph over DISO's sonar odometry, and the sonar map comes together

[ICRA 2023] Robust Imaging Sonar-based Place Recognition and Localization in Underwater Environments
Hogyun Kim, Gilhwan Kang, Seokhwan Jeong, Seungjun Ma, Younggun Cho · SPARO Lab, Inha University


Underwater there is no GPS and no light; a forward-looking imaging sonar sees 50 m ahead through murky water, but its images are noisy, low-resolution and change with the viewpoint. Sonar Context turns one sonar image into a small, robust place descriptor, so a robot can tell that it has been here before.

  • 🌊 Sonar Context: the polar sonar image pooled into patches (range rings × bearing sectors), plus a polar key (one value per range ring) that does not change with the heading.
  • 🔍 Coarse to fine: the polar key finds candidates in a k-d tree; the Sonar Context compares them column by column over every bearing shift (a rotation) and row by row (a motion along the beams).
  • 🔁 SLAM: DISO sonar odometry + Sonar Context loops, verified by dense phase correlation and optimized with iSAM2, on ROS 1 and ROS 2.
  • 👥 Multi-session and multi-robot: sessions recorded apart are aligned through their shared places; two robots merge their maps with Commerge from a few keyframes.
  • 📦 Library first: pip install sonar-context (NumPy), a C++17 library with the same results, and every application built on them.

📰 News

  • [Nov 2026] v2.0.0: Python and C++ libraries, SLAM with DISO (ROS 1 / ROS 2), multi-session SLAM, multi-robot SLAM with Commerge, and fixes to the matching (below). The ICRA 2023 code is kept at v1.0.0.
  • [Jan 2023] Sonar Context is accepted to ICRA 2023.

🛠️ Installation

pip install sonar-context                 # Python 3.9+, NumPy / SciPy / Pillow
git clone --recursive https://github.com/sparolab/sonar_context.git   # C++, SLAM (DISO as a submodule)

Python

import sonar_context as sc

# a polar sonar image: rows = range bins, columns = beams (layout="beam_range" if stored the other way)
desc = sc.sonar_context(image, patch=(4, 4))
dist, shift = sc.column_distance(desc_a, desc_b)        # 1 - similarity, best bearing shift (a rotation)

m = sc.SonarContextManager(col_threshold=0.2, exclude_recent=30)
for image in sequence:
    loop = m.update(image)                               # Loop(query, match, distance, column_shift, ...) or None
sonar-context describe polar_image.zip --layout beam_range --out seq.npz      # descriptors of a sequence
sonar-context loops seq.npz --out loops.csv --poses poses.txt               # online loop detection (+ precision)
sonar-context affinity a.npz b.npz --out affinity.npy                       # two sessions, for Commerge

C++

sudo apt install libeigen3-dev
cmake -S cpp -B cpp/build && cmake --build cpp/build -j && ctest --test-dir cpp/build
#include "sonar_context/sonar_context.hpp"
auto d = sonar_context::make_sonar_context(image);                 // CMake: sonar_context::sonar_context
auto m = sonar_context::column_distance(d_a, d_b);                 // m.distance, m.shift

Same distances and shifts as Python (checked in python/tests/test_cpp.py).

🗺️ SLAM

applications/slam: any odometry (default DISO, direct imaging sonar odometry, ICRA 2024) gives keyframes every 1 m; Sonar Context proposes revisits; each is verified by dense phase correlation of the two sonar frames (rotation searched, normalized peak ≥ 0.10) and closed with iSAM2. The core is ROS-free; the nodes are thin wrappers.

docker build -f docker/Dockerfile.slam -t sonar-context-slam:noetic .            # ROS 1: DISO + SLAM
docker run --rm -v <Aracati>:/data:ro -v $PWD/out:/out sonar-context-slam:noetic \
    roslaunch sonar_context_slam aracati2017.launch bag:=/data/ARACATI_2017_8bits_full.bag save_dir:=/out/slam \
    record:=/out/aracati_diso.bag                                                # + a bag for ROS 2
docker build -f docker/Dockerfile.slam-ros2 -t sonar-context-slam:humble .       # ROS 2: SLAM on recorded poses
docker run --rm -v $PWD/out:/out sonar-context-slam:humble \
    ros2 launch sonar_context_slam aracati2017.launch.py bag:=/out/aracati_diso_ros2 save_dir:=/out/slam_ros2

On Aracati 2017 (44 min, 620 m in a marina, BlueView P900-130), live with DISO, against the DGPS ground truth (evo_ape -a; scale-corrected -as in parentheses):

DISO odometry + Sonar Context loops loops
ROS 1 (DISO live) 4.54 m (4.16 m) 1.91 m (1.35 m) 40
ROS 2 (DISO poses recorded by ROS 1) 5.08 m 1.81 m 40

DISO is not deterministic from run to run (4.5 to 5.1 m here); the loops bring every run under 2 m. DISO's poses are in a z-down frame (flip_frame: true turns them, and the sonar beams, to z-up). Everything else: applications/slam.

👥 Multi-session SLAM

applications/multi-session-slam: LT-SLAM style (LT-mapper), as in RadLoc and ReFeree: two sessions saved by the SLAM keep their own frames and get one anchor node each; inter-session Sonar Context loops, verified by dense correlation, connect them through the anchors (Cauchy kernel).

sonar_context_align_sessions session_a/ session_b/ merged/ --threshold 0.25

Aracati 2017 split in two sessions: 47 inter-session loops (37 agree on one transform); the two sessions together come to 2.52 m APE (17.88 m with session B left in its own frame; 1.96 m and 2.33 m for each session alone).

🤖 Multi-robot SLAM with Commerge

applications/multi-robot-slam: two robots merge their maps by exchanging only a few keyframes, chosen by Commerge (IJRR 2026) from the Sonar Context affinity between them: on Aracati split into two robots, 4.5 % of the keyframes (2.6 KB of poses) merge the maps within 1.3 m.

Commerge on Aracati 2017 split into two sonar robots

🔧 What changed in v2.0.0

The matching of the ICRA 2023 code had bugs, fixed in both libraries (the old code: v1.0.0):

  • the best bearing shift was read one entry off (argmax + 1), and could index past the array;
  • shift 0 (the same heading) was never tested;
  • the row search compared unshifted rows, so it had no effect;
  • a shift with no non-empty overlap divided by zero.

New: skip_range drops the bright near field (on Aracati, 5 m), the polar image layout is explicit (range_beam / beam_range: Aracati's polar images are stored beams × range), and the descriptors of two sessions compare in one call (column_similarity_matrix, FFT-based).

🗃️ Datasets

Citation

See bibtex
@inproceedings{kim2023robust,
  title={Robust Imaging Sonar-based Place Recognition and Localization in Underwater Environments},
  author={Kim, Hogyun and Kang, Gilhwan and Jeong, Seokhwan and Ma, Seungjun and Cho, Younggun},
  booktitle={2023 IEEE International Conference on Robotics and Automation (ICRA)},
  pages={1083--1089},
  year={2023},
  organization={IEEE}
}

Acknowledgements

Sonar Context builds on Scan Context (Kim and Kim, IROS 2018); the multi-session SLAM follows LT-mapper (Kim et al., ICRA 2022). The SLAM uses DISO (Xu et al., ICRA 2024, GPLv3, a submodule) for odometry and GTSAM. Data: Aracati 2017 (dos Santos et al., RA-L 2022), HoloOcean (Potokar et al., ICRA 2022); multi-session underwater SLAM: Jang et al., ICRA 2021. Related: SOLiD, Commerge, ReFeree, RadLoc.

License

BSD 3-Clause for academic use; for any commercial purpose, please contact the authors (hg.kim@inha.edu). DISO (thirdparty/DISO) is GPLv3 and is not part of this license.

Metadata

Release files for sonar-context 2.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sonar-context 2.0.1
File Size Uploaded Provenance Actions
sonar_context-2.0.1.tar.gz 18.8 kB With provenance Details for sonar_context-2.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sonar-context 2.0.1
File Interpreter ABI Platform Actions
sonar_context-2.0.1-py3-none-any.whl Python 3 none any Details for sonar_context-2.0.1-py3-none-any.whl

Total release size: 35.0 kB

Release files / sonar_context-2.0.1.tar.gz

Download URL sonar_context-2.0.1.tar.gz
Size 18.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1044de11d8359e8bbd317d2a2a2079a48c0313a115d17c00c42cba798aae56e5
BLAKE2b-256 checksum
How to use checksums
90b1b674bdad95eafd6679c4b14c460f8175f2127e9457ef58275380698fb2ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / sonar_context-2.0.1-py3-none-any.whl

Download URL sonar_context-2.0.1-py3-none-any.whl
Size 16.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e0001b0a6c82d39b09aefeb42e876b6768aa5018ce2ae22db1e4be587b2e74ce
BLAKE2b-256 checksum
How to use checksums
7b5b0423077cdad86b855bbe63581fa96998075fc62b5eb23b3f5fd42c22787a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for sonar-context 2.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sonar_context-2.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.0.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page