Skip to content

Repository files navigation

geomag_model

Tools for calibrating a camera from the project's ordered ArUco board and inspecting the camera's board-relative motion through sampled video. The repository covers printable target generation, intrinsic calibration, per-frame board pose estimation, diagnostics, and Open3D visualization. Dense reconstruction and geomagnetic model fitting are not yet implemented.

Current functionality

  • Generate PNG markers for OpenCV's predefined ArUco dictionaries.
  • Generate nine print-ready A4 PDFs for the canonical ordered 9 x 9 DICT_5X5_100 board, including crop marks, orientation labels, scale references, and an assembly preview.
  • Construct the calibration board analytically from its four canonical metadata fields.
  • Calibrate an OpenCV pinhole camera from multiple board photographs, with per-view reprojection diagnostics.
  • Sample a video at a requested rate and estimate each usable frame's board-relative camera pose with PnP RANSAC and nonlinear refinement.
  • Save pose matrices and frame-level diagnostics, and render an MP4 showing the rectified board, camera frustum, trajectory, source frame, and pose status.
  • Open an interactive pose viewer with previous/current source frames and optional temporal marker-corner correspondences.

Environment and setup

The Conda environment is defined in environment/environment.yaml and uses conda-forge with Python 3.12, OpenCV, Open3D, NumPy, PyYAML, ReportLab, Mypy, and uv.

make create-env
conda activate geomag

Update an existing environment after dependency changes with:

make update-env

Ordered calibration board

The calibration target is a standard OpenCV ArUco GridBoard:

  • dictionary: DICT_5X5_100
  • grid: 9 rows x 9 columns
  • marker IDs: 0..80 in row-major order (id = row * 9 + column)
  • marker size: 50 x 50 mm
  • marker separation: 10 mm
  • marker orientation: canonical ArUco orientation

The logical marker-grid footprint is 530 x 530 mm:

9 * 50 mm + 8 * 10 mm = 530 mm

This logical region is centered at the project board origin and is the only board area used by calibration, pose estimation, projection, and visualization. The paper mosaic or physical backing may extend to approximately 550 x 550 mm; that blank outer material is not part of the computer-vision geometry.

metadata.yaml stores only the fundamental fields:

dictionary: DICT_5X5_100
grid_shape: [9, 9]
marker_size_mm: 50.0
marker_spacing_mm: 10.0

Board size, marker count, pitch, IDs, and centered object points are derived from those values. No reference photograph or custom_aruco_board.yaml is needed to define marker geometry.

ArUco assets and printable board

Generate PNGs for every predefined ArUco dictionary exposed by the installed OpenCV version:

python scripts/generate_aruco.py

The PNGs are written below assets/aruco/ and are ignored by Git. This script has no CLI options.

Generate the ordered board's nine A4 tile PDFs and assembly preview:

python scripts/generate_aruco_a4_board_tiles.py

The default output directory is assets/aruco_board_a4/; override it with --output-dir. Print tile PDFs at 100% / Actual Size, with fit-to-page and shrink options disabled, and verify the printed 100 mm reference before trimming.

The PDF generator's page margins, 180 mm crop regions, tile offsets, and 550 mm physical backing description are print-layout details. They do not change the 530 mm logical calibration geometry.

Board and calibration data

The ordered board calibration directory has this layout:

data/calibration/aruco_5x5__grid_9x9__50_mm_ordered/
├── metadata.yaml
├── images/
├── calibration_<camera>.yaml
└── videos/
  • metadata.yaml contains the four canonical board fields shown above.
  • images/ contains calibration photographs of the ordered board.
  • calibration_<camera>.yaml stores intrinsics, distortion, an inline copy of the canonical board specification, calibration summary values, per-view extrinsics, and reprojection errors.
  • videos/ is a convenient location for source videos. Captures and generated video products are ignored by Git.

Embedding the board specification in each calibration makes it self-contained and prevents later metadata edits from reinterpreting an existing calibration. The current calibration schema is format version 2; older custom-board calibrations must be regenerated.

Calibration workflow

Place at least five calibration photographs in:

data/calibration/aruco_5x5__grid_9x9__50_mm_ordered/images/

Then calibrate:

python scripts/calibrate.py pixel_9 \
    --path data/calibration/aruco_5x5__grid_9x9__50_mm_ordered

The --path option defaults to that ordered-board directory. Calibration reads metadata.yaml directly, constructs the ordered board, and processes every supported image in images/. It requires at least four known markers per usable image and at least five usable views, and rejects mixed image resolutions.

The command writes calibration_<camera-name>.yaml in the calibration directory and prints the number of views, overall RMS reprojection error, and output path. There is no board-discovery or custom-board generation step.

Camera pose estimation

Estimate poses from a video with:

python scripts/estimate_camera_poses.py path/to/video.mp4 \
    --fps 5 \
    --calibration \
    data/calibration/aruco_5x5__grid_9x9__50_mm_ordered/calibration_pixel_9.yaml

--fps is the source-video sampling rate and cannot exceed the source FPS. Pose estimation gets the exact ordered-board geometry from the calibration YAML; there is no separate board argument or sidecar file. --output-dir overrides the default <video-stem>_poses directory next to the video.

Every run writes:

  • camera_poses.npy: one 4 x 4 transform per successful sampled frame.
  • camera_poses_metadata.yaml: source-frame mapping, sampling/video information, calibration path, inline board specification, transform convention, skipped frames, marker/corner counts, inlier statistics, and reprojection RMSE.
  • camera_poses_visualization.mp4: a fixed Open3D overview with the camera trajectory, current rectified board image, source-video inset, and diagnostic status.

Add --interactive to open the interactive viewer after those files are saved:

python scripts/estimate_camera_poses.py path/to/video.mp4 \
    --fps 5 \
    --calibration \
    data/calibration/aruco_5x5__grid_9x9__50_mm_ordered/calibration_pixel_9.yaml \
    --interactive

The visualization renderer needs a working Open3D graphics context.

Pose and board coordinate convention

The logical 530 x 530 mm marker grid is centered at the board origin, with bounds from -265 to +265 mm on both axes. The board plane is z = 0; x points right, y points up, and z points above the board. Object coordinates and saved translations are in millimeters.

OpenCV GridBoard points use a top-left origin with y increasing down. The reusable ordered-board module applies one deterministic transform into the centered project frame before calibration or pose estimation uses the points.

Each saved pose is T_board_camera:

p_board = T_board_camera @ p_camera

It maps homogeneous points from OpenCV camera coordinates into the board/world frame. The camera position shown by the visualization is therefore the translation component of T_board_camera.

Interactive visualization

The interactive viewer shows the current rectified source image on the board plane, current camera frustum, and trajectory through all valid poses up to the selected pose. A previous/current source frame pair appears at the top right. The Show corner matches checkbox draws common marker corners between consecutive valid poses; green marks are current-frame PnP inliers and red marks are rejected corners.

Input Action
Left arrow or J Previous valid pose
Right arrow or L Next valid pose
Home First pose
End Last pose
Mouse Standard Open3D rotate, pan, and zoom
Q or Escape Close the viewer

The viewer also prints the selected pose status to the terminal.

Pose diagnostics

  • markers: detected IDs matched to the ordered board.
  • corners: candidate marker corners submitted to PnP.
  • inliers: corners retained by PnP RANSAC.
  • ratio: inlier corners divided by candidate corners.
  • RMSE: reprojection error over refined inlier corners, in pixels.

Repository layout

calibration/       ordered-board geometry, ArUco detection, calibration, and calibration I/O
reconstruction/    video sampling, pose estimation, board projection, and visualization
scripts/           thin command-line entry points
tests/             focused board, calibration/pose pipeline, and printable-board tests
assets/            generated marker and printable-board assets
data/calibration/  local board metadata, images, calibrations, videos, and pose products
environment/       Conda environment definition

Development checks

Run checks from the activated geomag environment:

uvx ruff check .
uvx ruff format --check .
mypy .
python -m unittest discover -s tests -v
python -m compileall -q calibration reconstruction scripts tests

License

Distributed under the GNU General Public License; see LICENSE.

Copyright (C) Saeed Gholami Shahbandi.

Portions of this project were developed with the assistance of ChatGPT, a product of OpenAI.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages