openCV ChArUco
is an open-source Python project built with OpenCV that focuses on detecting and calibrating cameras using ChArUco markers — a hybrid of ArUco and chessboard markers. The goal is to make it easy for others to learn about marker-based camera calibration, pose estimation, and 3D vision techniques using real-world tools.
This project is intended both for self-learning and to help others understand and experiment with OpenCV's ChArUco tools. Contributions are welcome!
- Detect ChArUco boards using OpenCV's
cv2.aruco
module - Calibrate cameras using ChArUco board detection
- Visualize marker corners and IDs in a folder named detectedMarkersDrawn (the user can create the folder manually before running the script or the script will itself create the folder when running)
- Save and load camera calibration parameters for reuse
- Save the pose estimation from each scene as a json file in the CameraShaders folder
- Before running the script the user must ensure that there is a file called camShader.json in the CameraShaders folder because this one file provides a template to the script for writing all the json files for pose estimation
- A feature of this OpenCV project, setting it apart from other ChArUco-related projects, is that you can manufacture a viewing transformation in OpenGL using the numbers from a json file. Now this feature needs a huge explanation! For starters, please refer to this documentation.
- Crop images
- Undistort images
- Convert colored images to binary images
- Python 3.8+
- OpenCV 4.8.1 (
opencv-contrib-python
) - NumPy
Install with:
pip install opencv-contrib-python==4.8.1.78 numpy
- Create a folder called
calibration_images
which contains all the raw Nikon photos, with nef extension, of a 14*7 ChArUco board to be used used for camera calibration. - Run calibration
python calibrate.py --calibrate images
The above command tells the script to calibrate using the images in the calibration_images
folder.
- Use the Colors directory included with this repository. It is included to give you an idea of the structure of the Colors folder. Feel free to replace the images, just be aware of the folder structure and the file format. But just for the sake of getting started, just ensure the
Colors
folder - nothing else to do in this step. - Run calibration
python calibrate.py --calibrate colors
which tells the script to calibrate using the png images in the Colors directory
.
- Create a folder called
pairedImages
and refer to pairedImages1, included with this repository, to understand the structure of this folder. If you want you can just rename thepairedImages1
topairedImages
and jump to the next step - that works too. Just be aware of the naming scheme that:
_0.nef
tells the script that you want to use the image for calibration, i.e. it is a photo of a ChArUco board_1.nef
tells the script that you do not want to use the image for calibration.
- Run calibration
python calibrate.py --calibrate paired
If the script runs successfully, you will see two folders:
detectedMarkersDrawn
containing images with detected markers, corners and axes drawnundistorted_images
containing undistorted images
Check calibrate.py to modify:
- ChArUco board size (number of squares)
- Marker size vs square size
- ArUco dictionary (
DICT_4X4_50
,DICT_5X5_100
, etc.). For now it is hard-coded tocv2.aruco.DICT_4X4_250
.
Contributions are welcome!
If you're interested in adding features (Refer to the Issues for bugs and prospective features in this project), improving usability, or expanding documentation, feel free to open a pull request. Keep the educational purpose in mind: code clarity and comments are appreciated.
Any question regarding this project (even if it is an ELI5 question) can be shot to arnobg2002@gmail.com via email or Arnob1 via LinkedIn.
This project is licensed under the GNU General Public License (GPL-3.0).
That means:
- ✅ You can use, modify, and share the code freely.
- ✅ You must credit the original source.
- ❌ If you distribute modified versions, they must also be open-sourced under the same license.
- ❌ You cannot make it closed-source or proprietary.
This helps ensure that all versions of the project remain open and accessible to the community.
This project was built with the help of the following articles, guides, and community answers:
- Rotation vector vs Rotation matrices
- Mastering 3D spaces in OpenCV / COLMAP
- Reprojection error in OpenCV calibration
- Nikon 18-55mm Lens Review
- Using ChArUco boards in OpenCV
- argparse Python Tutorial
- Reading Nikon NEF raw images with rawpy vs imageio
- cv2.interpolateCornersCharuco estimation issue
- Meaning of the retval in cv2.calibrateCamera
- Interpreting reprojection error in OpenCV calibration
- Discussion of reprojection error discrepancies
- Also discussed here
- Calculating Field of View from camera matrix
- Sign of k1 and k2 in lens distortion
- Modern Robotics
- Licensed under the MIT License
- Copyright (c) 2019 NxRLab
- MIT License Text
- Understanding Lens Distortion
- Camera Calibration Intro Theory
- ISO, Aperture & Shutter Speed
- Not directly related to this project but to run this project you will need to take several photos of a ChArUco board and ISO, Aperture & Shutter Speed are generally some things to consider when taking photos. Just a good read.
- usbipd
- Thresholing a RGB image using inrange (OpenCV)
- Image Arithmetics
- calibrateCameraCharuco assertion failure fabs(sc) > DBL_EPSILON
- Otsu Thresholding With OpenCV
- A problem with simple thresholding is that you have to manually specify the threshold value.
- We can manually check how good a threshold is by trying different values but it is tedious and it may break down in the real world.
- Tutorial Threshold inRange
- Should we use hsv for thresholding? Why?
- drawing an small axis on pattern works, but a longer axis produce totally wrong result
Happy learning and posing! 🎯