Skip to main content

A multi-camera calibration system using ChArUco boards to align and transform camera views into a single top-down perspective.

Project description

ChArUcal

PyPI Version Python Version License

charucal is a Python library designed to calibrate multi-camera systems and transform their outputs into a single top-down view. The library utilizes ChArUco boards for precise corner detection and OpenCV for homography estimation. To ensure the transformation remains efficient enough for real-time applications, charucal generates precomputed remap tables that minimize processing overhead during runtime.

The project was originally developed for the Hanze team’s participation in the Self Driving Challenge 2024 to assist with autonomous driving. It is now maintained as a standalone library for anyone who needs a real-time top-down view from multiple cameras.

Table of Contents

Getting Started

Installation

pip install charucal

Basic Usage

1. Define your board and calibrate

import cv2
from charucal import CalibrationPattern, Calibrator

pattern = CalibrationPattern(
    width=10,
    height=8,
    square_length=0.115,
    marker_length=0.086,
    aruco_dict=cv2.aruco.DICT_4X4_100,
)

calibrator = Calibrator(pattern)

captures = []
for frame_set in your_capture_source:
    capture = calibrator.detect(frame_set)
    if capture.is_complete:
        captures.append(capture)

result = calibrator.calibrate(*captures)
result.save("latest.json")

2. Load and transform

import cv2
from charucal import CalibrationResult, CameraTransformer, RenderDistance

calibration = CalibrationResult.load("latest.json")
transformer = CameraTransformer(
    calibration,
    render_distance=RenderDistance(front=10.0, lateral=5.0),
    output_shape=(1000, 1000),
    interpolation=cv2.INTER_LINEAR,
)

topdown = transformer.transform(frames)

How It Works

Step 1. Capture the Images

To calibrate the cameras, we need to capture images of the ChArUco board from all cameras. It is extremely important that the ChArUco board is clearly visible in all images. A ChArUco board is a chessboard with ArUco markers on it. The ArUco markers allow us to tell which corner is which, making it extremely useful for stitching images together.

# Import OpenCV
import cv2

# Initialize the cameras.
cam_left = cv2.VideoCapture(0)
cam_center = cv2.VideoCapture(1)
cam_right = cv2.VideoCapture(2)

# Get the frames of each camera.
ret, frame_left = cam_left.read()
ret, frame_center = cam_center.read()
ret, frame_right = cam_right.read()

Step 1


Step 2. Detect the Corners

Next up is locating the corners of the ChArUco board in all images. OpenCV has a built-in module for dealing with ArUco markers, called cv2.aruco. We can use this module to find the corners of the ChArUco board in each image.

Step 2

Step 3. Calibrate the Cameras

The next step is to find the homographies between the cameras. A homography is a transformation matrix that maps points from one image to another.

Step 3.1. Find the inter-camera homographies

For each camera, we find the homography that maps its pixel space to the reference camera's pixel space. The reference camera is selected automatically as the one with the most shared corners across all other cameras, though it can also be set manually.

Step 3.1

Step 3.2. Find the top-down homography

We also find the homography that maps the reference camera's pixel space to real-world metres, using the ChArUco board's known physical dimensions.

Step 3.2

The result is saved to a JSON file so you don't need to recalibrate between sessions.

Step 4. Transform the Images

The RenderDistance you provide determines what part of the world to show. It defines how many metres ahead and to each side of the camera the output image should cover. Since the ChArUco board can be placed at any angle, the top-down view would be rotated depending on how it was placed. We correct for this so the output is always properly aligned with the reference camera.

To figure out what to draw for each pixel in the output, we work backwards. Every pixel in the output represents a position in the real world, and from the calibration we know exactly how each of those world positions maps back to a pixel in each source camera. We precompute this mapping for the entire output canvas so that at runtime we can produce the top-down image as fast as possible.

Step 4

Capture Tips

  • Use a large board: The ChArUco board needs to be large enough for all cameras to see it clearly. If it's too small, corner detection and homography estimation will fail or become unstable.
  • Maximize overlap: The board has to be fully visible in every camera at the same time. Place it right in the middle where the camera views overlap.
  • Ensure good lighting: Reflections and bright spots on the board's surface will cause missed or inaccurate corner detections. Try to use matte materials or adjust your lighting to avoid glare.

Performance

INTER_NEAREST is 3.16× faster on average. Use INTER_LINEAR when output quality matters more than throughput.

Benchmark Benchmark results for 3 cameras (1080p) on a Ryzen 7 9800X3D (single-threaded)

Contributing

Contributions, bug reports, and feature requests are welcome! If you'd like to contribute, please follow these steps:

  1. Fork the repository.
  2. Create a new branch for your changes.
  3. Make your changes and commit them.
  4. Push your changes to your fork.
  5. Submit a pull request with a description of your changes.

Even if you're not a developer, you can still support the project in other ways. If you find this project useful, consider showing your appreciation by donating to my Ko-fi page.

ko-fi

License

This package is licensed under the MIT License. See the LICENSE file for more information.

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

charucal-0.1.2.tar.gz (27.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

charucal-0.1.2-py3-none-any.whl (33.7 kB view details)

Uploaded Python 3

File details

Details for the file charucal-0.1.2.tar.gz.

File metadata

  • Download URL: charucal-0.1.2.tar.gz
  • Upload date:
  • Size: 27.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for charucal-0.1.2.tar.gz
Algorithm Hash digest
SHA256 1874709357e1d056bbec7158007481b969f518630ea8ef4892c3dafdcb3b23a9
MD5 d242173b5bf16993f49ae42531233b4c
BLAKE2b-256 f38646f6102231f7255a737413aac6bd6176f883dd4c195dcf8283c5516a0934

See more details on using hashes here.

File details

Details for the file charucal-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: charucal-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 33.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for charucal-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 1eb25cce3b8d95c04388e0f64948e2565327720b26e8ba98313982ea421498ce
MD5 a2bd45a0aee6c0eea63005275897bacc
BLAKE2b-256 d44a8d6ffcb6f5f8f112f74ae2568089fd36ebf12515fb5f66b028513b08b13b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page