Single Camera Calibration - Carleton-SRCL/SPOT GitHub Wiki
Click here for raw code
"""
Used to calibrate the camera and eliminate lens distortion etc etc...
Pattern used is an 8x13 (8 rows x 13 col) chess board
Sudo:
Use Calibration Image Splitter to split original images
Run a test on the 'right' and 'left' eye on the camera for each package of split images
Generate the 3x3 calibration matrix for each
Compare to see if the same.
Written by Hayden Arms Sep 2023
"""
import numpy as np
import cv2
import os
import argparse
import glob
def main():
print("Camera calibration beginning")
dirpathLeft = r'/Users/PathforLeftEye' # "Path to folder containing checkerboard images for calibration"
dirpathRight = r'/Users/PathforRightEye'
dirPaths = [dirpathLeft,dirpathRight]
# 16.1 mm == 0.0121 m
square_size = 1.61/1000 # m # physical size of squares (manually measured)
visualize = False
width = 14
height = 9
CamMatrices = []
DistMatrices = []
for rpath in dirPaths:
ret, mtx, dist, rvecs, tvecs = calibrate(rpath, square_size, width, height, visualize)
print("Completed Calibration")
print("Path " + rpath + ".....\n")
CamMatrices.append(mtx)
DistMatrices.append(dist)
print("Matrices: ")
print(np.around(CamMatrices,3))
print("Measured Distances: ")
print(np.around(DistMatrices,3))
# np.save("calibration_matrix", mtx)
# np.save("distortion_coefficients", dist)
def calibrate(dirpath, square_size, width, height, visualize=False):
""" Apply camera calibration operation for images in the given directory path. """
# termination criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(8,6,0)
objp = np.zeros((height*width, 3), np.float32)
objp[:, :2] = np.mgrid[0:width, 0:height].T.reshape(-1, 2)
objp = objp * square_size
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
# images = os.listdir(dirpath)
ii = 1
iiT = len(glob.glob(os.path.join(dirpath,"*.jpg")))
for image_name in glob.glob(os.path.join(dirpath,"*.jpg")):
print("Reading Image {}".format(ii))
img = cv2.imread(image_name)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (width, height), None)
# If found, add object points, image points (after refining them)
if ret:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
imgpoints.append(corners2)
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (width, height), corners2, ret)
print("\tCorners Detected...")
if visualize:
cv2.imshow('img',img)
cv2.waitKey(0)
print("Completed {} %, of path".format(100*np.round(ii/iiT,2)))
ii = ii + 1
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# returns camera matrix, distortion coefficients, rotation and translation vectors etc
return [ret, mtx, dist, rvecs, tvecs]
if __name__ == "__main__":
main()
Purpose
- This function is used to calibrate and eliminate distortion of a single lens camera, required for ArUco marker detection and pose determination.
Input Variables
-
size_of_chessboard_squares_mm
- To calibrate a camera, a chessboard/checkerboard printout with known dimensions is required to measure lens distortion.
- This variable represents the width in mm of a single square on the checker board.
Figure 1: Chessboard image used in calibration.
-
chessboardsize
- The size of the chessboard is also required to determine number of squares on the printout. For example, a board with 13 columns and 8 rows of full squares would be input as (14,9) due to it having 13+1 columns and 8+1 rows.
Output Variables
-
calibration_matrix
- This output provides a camera calibration matrix that is used in Live_Pose_Det.py for calibration.
-
distortion_coefficients
- This output provides a camera distortion matrix that is used in Live_Pose_Det.py to accommodate lens distortion.