# MC-Calib calibrates multi-camera rigs with Charuco boards

> MC-Calib is a C++ calibration toolbox for multi-camera systems, built on OpenCV, Ceres and Boost, that handles perspective, fisheye and mixed rigs from synchronized image sequences and outputs intrinsics, extrinsics and 3D board structure. It suits research labs and robotics teams with a fixed rig, and it assumes global shutter cameras and physical Charuco targets.

**rameau-fr/MC-Calib** — A generic and robust calibration toolbox for multi-camera systems

- Repository: https://github.com/rameau-fr/MC-Calib
- Stars: 579 · Forks: 84
- Language: C++
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/rameau-fr-mc-calib

## What the toolbox is for, and where the paper sits

MC-Calib is described as a generic calibration toolbox for multi-camera systems, and it is the implementation of a paper with the same name published in the International Journal of Computer Vision, with a researchgate link for open access and a preprint linked from an issue in the repository. The audience is anyone who has to align several cameras to a common object model, and the word generic in the title is doing real work. Most calibration code assumes a single camera, or a set of cameras that all share one intrinsic model. MC-Calib covers the harder cases, and the repository topics name them: multi-target-calibration, non-overlapping, stereo-calibration, sensor-calibration and camera-calibration. A rig where the cameras see different boards, or see each other only partially, is exactly the case that breaks single-target pipelines, and having one tool that produces a consistent 3D structure across all of them is the point. The licence is MIT and the last push to the repository was on 2026-10-05, with v1.5.0 released on 2026-07-27 after v1.4.0 in November 2024.

## The dependency stack: OpenCV, Ceres, Boost and C++17

The requirements are listed once and they are the first thing to check against your machine. The project needs Ceres, Boost, OpenCV and C++17, and the OpenCV versions listed are specific: 4.2.0, 4.5.5, 4.10.0, 4.11.0 and 5.0.0. That list is not a formality, because the Dockerfile builds OpenCV from source rather than installing a binary package, downloading both the opencv and opencv_contrib archives for version 5.0.0 and configuring the build with the contrib modules path before compiling. The Dockerfile is based on ubuntu:24.04 and installs build-essential, cmake, wget, unzip and git, plus python-is-python3 and python3-pip, and it sets NO_AT_BRIDGE 1 with a comment explaining that this suppresses GTK accessibility warnings because there is no dbus in the container. Boost comes from the distribution package libboost-all-dev, while Ceres is built from a pinned git clone of abseil-cpp at branch 20240722.0 followed by its own cmake build. The overall shape is a research toolchain assembled from source, and a reviewer should note that the container images exist precisely because reproducing that locally is painful.

## Running it in Docker, and compiling from source

Two routes are documented. For Windows users there is a separate installation guide, and the Docker route is the one the README recommends. You install Docker, then pull an image, and both a production and a development environment are offered.

```bash
   docker pull bailool/mc-calib-prod:opencv500 # production environment (recommended)
   docker pull bailool/mc-calib-dev:opencv500  # development environment (recommended)
   # legacy compatibility images are also available (opencv4110, opencv455, opencv420)
```

You then run the pulled image with the repository root and your data directory mounted, and you set the two path variables appropriately.

```bash
   docker run \
               -ti --rm \
               --volume="$PATH_TO_REPO_ROOT:/home/MC-Calib" \
               --volume="$PATH_TO_DATA:/home/MC-Calib/data" \
               bailool/mc-calib-prod:opencv500
```

The legacy tags are worth noticing, since they exist for a reason: a calibration result depends on the OpenCV version, so a team that has already calibrated with one version should stay on that version when re-calibrating. If you build from source instead, the sequence is short.

```bash
   cd MC-Calib
   mkdir build
   cd build
   cmake -DCMAKE_BUILD_TYPE=Release ..
   make -j10  
```

The repository also has a Dockerfile of its own at the top level, a CMakeLists.txt, an McCalib/ directory holding the library code, apps/ for the executables, configs/ for the YAML configuration files, python_utils/ for the post-processing scripts and a tests/ directory.

## Charuco boards: generate, print, then measure the squares

The calibration procedure starts with physical targets, and the toolbox helps you make them. If all your boards are similar, meaning the same number of squares in the x and y directions, you only need to specify number_x_square, number_y_square and number_board, and then run the board generator.

```bash
      ./apps/create_charuco_boards/generate_charuco ../configs/calib_param.yml
```

If each board has a specific format, with a different number of squares, you specify number_x_square_per_board and number_y_square_per_board instead.

```bash
      number_board: 2 
      number_x_square_per_board: [10,5]
      number_y_square_per_board: [3,4]
```

The example is two boards of size 10x3 and 5x4. The board images are saved to the root folder where the code is executed, and a sample of Charuco boards is provided in the board_samples directory under docs. Then you print the boards and measure the squares. If the boards have all the same square size you set square_size and leave square_size_per_board empty, otherwise you specify square_size_per_board, and the documentation gives the example square_size_per_board: [1, 25] meaning the first and second boards are composed of squares of size 0.1cm and 0.25cm respectively. One detail that saves a lot of confusion later: the square size can be in any unit you prefer, and the resulting calibration will also be expressed in that unit.

## The assumptions that will break your calibration if ignored

Two requirements in the acquisition step are non-negotiable and both are stated plainly. The first is synchronization. MC-Calib has been designed for synchronized cameras, so you have to make sure that all the cameras in the rig capture images at the exact same time. The second is shutter type. The toolbox has been designed and tested for global shutter cameras, so the documentation says it cannot guarantee highly accurate results if you are using rolling shutter sensors. A third, softer requirement is that for high-quality calibration you should make sure to have a limited quantity of motion blur during your sequence. These are not the kind of caveat that appears in a footnote of a paper. They define the class of rig the method is valid for, and a rig that violates them will still produce numbers, which is the dangerous part, because a calibration that is quietly wrong is worse than one that failed. The image organisation is also specific. The images extracted from each camera have to be stored in different folders with a common prefix followed by a three digit index starting from 001, so for two cameras the folders can be called Cam_001 and Cam_002, and the folder naming is how the toolbox knows which camera each image came from.

## Configuration: distortion models, outputs and the reliability threshold

The configuration file is where the rig's character is declared. You set the number of cameras in number_camera. If the system is homogeneous, you set distortion_model, where 0 signifies that all your cameras are perspective using the Brown distortion model and 1 uses the Kannala distortion model for fisheye. If you are calibrating a hybrid vision system composed of both fisheye and perspective cameras, you specify the model per camera in the vector distortion_per_camera. The image path goes in root_path, for instance "../Data/Image_folder/". By default, MC-Calib generates the camera calibration results, the reprojection error log, the 3D object structure, the detected keypoints, and the pose of the object for each frame where it has been detected, and you can additionally save the detection and reprojection images by setting save_detection and save_reprojection to 1. If you prepared many boards but only a few appear in your sequence, you can list the board indexes in boards_index, which avoids trying to detect all the boards and speeds up the calibration. The advanced parameter worth understanding is min_perc_pts, which the documentation recommends setting to at least 0.4 for a general setup so that 40% of the board's points have to appear, with the note that it can be reduced significantly for a limited field of view overlapping with a single board, and that an automatic colinear points check should avoid most degenerated configurations.

## Running the calibration and the post-calibration analysis

The calibration itself is a single executable pointed at the configuration file, and the post-processing is a Python script pointed at the output directory.

```bash
	./apps/calibrate/calibrate ../configs/calib_param.yml
```

```bash
	python3 python_utils/post_calibration_analysis.py -d save_path_from_calib_param.yml
```

The configuration files themselves are the starting point for a new setup, with the instruction to duplicate the most relevant one from configs/*.yml and fill in the details. The example file shows the board parameters block with number_x_square and number_y_square set to 5, resolution_x and resolution_y at 500 pixels, and length_square at 0.04. A parameter called length_square rather than square_size in that example is a small inconsistency in the documentation, and it is the kind of thing to expect when a research toolbox has been through several versions. The documentation is published online at codedocs.xyz for the project, and the instructions for generating local documentation live in docs/Documentation.md, with the docs/ directory in the repository also holding the Windows installation guide, the board samples and the documentation build notes. The last push to the repository was on 2026-10-05, so the tree is still receiving changes even though the newest tagged release is v1.5.0 from 2026-07-27.

## Conclusion

Adopt MC-Calib if you have a fixed multi-camera rig and need intrinsics, extrinsics and board geometry for perspective, fisheye or mixed camera sets, since it handles the hybrid case and the non-overlapping field of view case in one tool rather than stitching together separate calibrations. Do not adopt it if you are calibrating a single camera, where a plain OpenCV calibration is less work, or if your rig has rolling shutter sensors, because the documentation states the toolbox was designed and tested for global shutter cameras and cannot guarantee accurate results otherwise. Verify two things before you spend a day printing boards: that the cameras genuinely capture at the same time, since the toolbox was designed for synchronized cameras and unsynchronized captures will degrade the result, and that your OpenCV version is one of the supported ones, 4.2.0, 4.5.5, 4.10.0, 4.11.0 or 5.0.0. The practical first step is to pull the Docker image, generate the Charuco boards with the board generator, and measure the printed squares before acquiring any images.

## FAQ

### What is MC-Calib used for?

It is a calibration toolbox for multi-camera systems, implementing the paper of the same name. It calibrates perspective, fisheye and hybrid rigs from synchronized images of Charuco boards, producing intrinsics, extrinsics, a 3D board structure and per-frame object poses.

### How do I run MC-Calib with Docker?

Pull bailool/mc-calib-prod:opencv500 or bailool/mc-calib-dev:opencv500, then run the image with the repository root and your data directory mounted as volumes, and with PATH_TO_REPO_ROOT and PATH_TO_DATA set. Legacy compatibility images exist for opencv4110, opencv455 and opencv420.

### What are the system requirements for MC-Calib?

Ceres, Boost, OpenCV and C++17, with OpenCV versions 4.2.0, 4.5.5, 4.10.0, 4.11.0 and 5.0.0 listed as supported. The Dockerfile builds OpenCV 5.0.0 and its contrib modules from source on ubuntu:24.04.

### Can MC-Calib calibrate a mix of fisheye and perspective cameras?

Yes. For a homogeneous rig you set distortion_model, where 0 is the Brown perspective model and 1 is the Kannala fisheye model. For a hybrid system you specify the model per camera in the vector distortion_per_camera.

### Does MC-Calib work with rolling shutter cameras?

The documentation states the toolbox has been designed and tested for global shutter cameras, so it cannot guarantee highly accurate results with rolling shutter sensors. It has also been designed for synchronized cameras, meaning all cameras in the rig must capture at the exact same time.

### How do I generate the Charuco boards for MC-Calib?

Set number_x_square, number_y_square and number_board in the configuration file, then run the board generator at apps/create_charuco_boards/generate_charuco with the configuration path. If boards differ in shape, use number_x_square_per_board and number_y_square_per_board instead, then print them and measure the square size.

## Sources

- [Issues](https://github.com/rameau-fr/MC-Calib/issues)
- [License: MIT](https://github.com/rameau-fr/MC-Calib/blob/master/LICENSE)
- [rameau-fr/MC-Calib on GitHub](https://github.com/rameau-fr/MC-Calib)
- [README](https://github.com/rameau-fr/MC-Calib/blob/master/README.md)
- [Releases](https://github.com/rameau-fr/MC-Calib/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rameau-fr-mc-calib
