The Beginner’s Guide: Camera Calibration (Un-distortion)

DeepLCH
3 min readJun 12, 2020

--

This tutorial is tested on multiple Linux and works with webcams also. But since all dependencies can be done via pip, instead of compilation, Windows should work similarly.

Purpose: A simple guide to camera calibration, solving cameras’ lens distortion with OpenCV.

Package Focus: OpenCV (most versions should work), Pickle, Numpy.

Side Note: Feel free to run in Spyder, so that you can play around with the code yourself.

Tutorial Content

  1. Obtain Images For Calibration
  2. Camera Calibration
  3. Before-After Test

1. Obtain Images For Calibration

It is best to get images that don’t orientated similarly.

This is step helps you acquire the images needed for calibration. Just copy & paste the codes, it’s a lot easier. Code comments and explanations are followed by “#” in the code sections.

# Import Libraries 
import cv2
# Input "0" means your connected usb webcap. Can be replaced with a RTSP url
cap = cv2.VideoCapture(0)
cv2.namedWindow("Image Acquisition")
# For file naming
imgNum = 0
while True:
ret, frame = cap.read()
if not ret:
print("Cannot Read Frame!!!")
break
cv2.imshow("Image Acquisition", frame)
comm = cv2.waitKey(1)
if comm%256 == 27:
# ESC key is pressed
print(" Command: Ending program..")
break
elif comm%256 == 32:
# SPACE key is pressed
fileName = "CalibFrame_{}.png".format(imgNum)
cv2.imwrite(fileName, frame)
imgNum += 1
print(" Command: {} is saved!".format(fileName))
cap.release()
cv2.destroyAllWindows()

Run the program, and press “Space” when the orientation of the checker-board is desirable.

2. Camera Calibration

It will look like this when the program is calibrating.

This is part is where calibration happens. It will be based on OpenCV’s tutorial https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html#calibration with a bit of modifications.

Note: My checker board is 10 * 7, therefore when I will be asking the program to only calibrate based on a 9*6 surface.

# Import more libraries
import numpy as np
import glob
import matplotlib.pyplot as plt
boardHeight = 6
boardWidth = 9
# Prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((boardHeight*boardWidth,3), np.float32)
objp[:,:2] = np.mgrid[0:boardWidth, 0:boardHeight].T.reshape(-1,2)
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d points in real world space
imgpoints = [] # 2d points in image plane.
# Make a list of calibration images
images = glob.glob('./CalibFrame*.png')
# Step through the list and search for chessboard corners
for idx, fname in enumerate(images):
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the chessboard corners
ret, corners = cv2.findChessboardCorners(gray, (boardWidth,boardHeight), None)
# If found, add object points, image points
if ret == True:
objpoints.append(objp)
imgpoints.append(corners)
# Draw and display the corners
cv2.drawChessboardCorners(img, (boardWidth,boardHeight), corners, ret)
#write_name = 'corners_found'+str(idx)+'.jpg'
#cv2.imwrite(write_name, img)
cv2.imshow('img', img)
cv2.waitKey(500)
cv2.destroyAllWindows()

3. Before-After Test

Here’s one of my results.

Let’s see how good is the calibration.

# Import one last library
import pickle


# Read a test image
img = cv2.imread('./CalibFrame10.png')
img_size = (img.shape[1], img.shape[0])

# Do camera calibration given object and image points
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, img_size,None,None)

dst = cv2.undistort(img, mtx, dist, None, mtx)
cv2.imwrite('./CalibFrame10_undist.png',dst)

# Save the camera calibration results
dist_pickle = {}
dist_pickle["mtx"] = mtx
dist_pickle["dist"] = dist
pickle.dump(dist_pickle, open( "./undist_params.p", "wb" )) #This is your calibration results, just load and use in the future
#dst = cv2.cvtColor(dst, cv2.COLOR_BGR2RGB) #uncomment this if your image color looks weird. It relates to how cv2 process image channels# Visualize calibrated result
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
ax1.imshow(img)
ax1.set_title('Original Image', fontsize=30)
ax2.imshow(dst)
ax2.set_title('Undistorted Image', fontsize=30)

— END —

--

--

DeepLCH

Deep learning Scientist, specialized in computer vision and data analytics.