[Perception] ์นด๋ฉ๋ผ ์บ๋ฆฌ๋ธ๋ ์ด์ ์ค์ต (camera calibration): opencv, intrinsic, extrinsic, checker(chess) board ํ์ฉ
๐ก ๋ณธ ๋ฌธ์๋ '[Perception] ์นด๋ฉ๋ผ ์บ๋ฆฌ๋ธ๋ ์ด์ ์ค์ต (camera calibration): intrinsic, checker(chess) board ํ์ฉ'์ ๋ํด ์ ๋ฆฌํด๋์ ๊ธ์ ๋๋ค.
Checker board๋ฅผ ํ์ฉํ์ฌ Intrinsic Metrix๋ฅผ ๊ตฌํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์ฝ๋ ๋ฐ return๊ฐ์ ๋ํด ์ ๋ฆฌํ์์ผ๋ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
Intrinsic Metrix(K) ์ ์ฒด ์ฝ๋
import numpy as np
import cv2 as cv
import glob
wc = 8 - 1
hc = 5 - 1
square_size = 70 # QHD 7cm
square_size = 52.5 # FHD 5.25cm
# termination criteria
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((wc*hc,3), np.float32)
objp[:,:2] = np.mgrid[0:wc,0:hc].T.reshape(-1,2)*square_size # square_size unit [mm]
# 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.
dataset = "/home/avs/dataset/blackbox_intrinsic/QHD/"
images = glob.glob(dataset + '*.jpg')
for fname in images:
img = cv.imread(fname)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv.findChessboardCorners(gray, (wc,hc), None)
# If found, add object points, image points (after refining them)
if ret == True:
objpoints.append(objp)
corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners)
# Draw and display the corners
cv.drawChessboardCorners(img, (wc,hc), corners2, ret)
print(fname)
# cv.imshow('img', img)
# cv.waitKey(1000)
cv.destroyAllWindows()
ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print(ret, mtx, dist,rvecs,tvecs,sep='\n')
Intrinsic Metrix ๋ถ๋ถ ์ค๋ช
calibration metrix๋ฅผ ๊ตฌํ๊ธฐ ์ํด์๋ ๋๊ฒ chess board ์ฝ๋์ Width, Height์ chess board square size๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฃ์ด์ฃผ๋ฉด ๋ฉ๋๋ค. ์ ์ฝ๋์์๋ ์๋์ ๊ฐ์ด ๊ฐ๋ก์ ์ฌ๊ฐํ ๊ฐ์์ธ 8๊ฐ, ์ธ๋ก ์ฌ๊ฐํ ๊ฐ์์ธ 5๊ฐ ์ฌ์ด์ internal ์ฝ๋์ ๊ฐ์๋ฅผ ๊ตฌํ๊ธฐ ์ํด์ 1์ฉ ๋นผ์ค์ผ๋ก์ ๋ฃ์ด์ฃผ์์ต๋๋ค. ๋ํ chess board square size๋ ์ค์ ํฌ๊ธฐ๋ฅผ ๊ตฌํ ํ mm ๋จ์๋ก ๋ฃ์ด์ฃผ์ด 3์ฐจ์ ๋ณํ์ ์ฌ์ฉํฉ๋๋ค.
wc = 8 - 1
hc = 5 - 1
square_size = 70 # QHD 7cm
...
objp[:,:2] = np.mgrid[0:wc,0:hc].T.reshape(-1,2)*square_size # square_size unit [mm]
์ดํ์ ์ฝ๋๋ ๊ทธ๋๋ก ๋ฃ์ด์ฃผ๋ฉด๋๋ฉฐ, ๊ฒฐ๊ณผ ๊ฐ์ผ๋ก ๋ฝํ๋ ๊ฐ๋ค์ ๋ถ์ํด๋ณด๊ฒ ์ต๋๋ค.
ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
cv.calibrateCamera() which returns the camera matrix, distortion coefficients, rotation and translation vectors etc.
- retval: average re-projection error. This number gives a good estimation of precision of the found parameters. This should be as close to zero as possible.
- camera matrix(mtx): intrinsic parameters of the camera
- distortion coefficients(dist): radial and tangential distortion parameters (k1, k2, p1, p2, k3)
- rotation and translation vectors(rvecs, tvecs): extrinsic parameters of the camera
์ถ๊ฐ๋ก retval ์ ๊ฒฝ์ฐ, parameter๋ฅผ ์ผ๋ง๋ ์ ์ถ์ ํ๋์ง๋ฅผ ๋ํ๋ด๋ฉฐ, rms ๊ฐ์ด 1์ผ ๊ฒฝ์ฐ 3D chess board point๋ฅผ 2D์ ํฌ์ํ์ ๋ image point์ ๋น๊ตํ์ฌ ํ๊ท ์ ์ผ๋ก 1.0px๊ฐ ์ฐจ์ด๊ฐ ๋๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๋ฐ๋ผ์ 0์ ๊ฐ๊น์ธ์๋ก ์ข์ ๊ฐ์ด๋ฉฐ, ๋๊ฒ [0,1] ์ฌ์ด์ ๊ฐ์ ๊ฐ๋๋ค๊ณ ํฉ๋๋ค.
์ฐธ๊ณ
- [opencv] Camera Calibration: https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html
- [opencv] Camera calibration With OpenCV(retval): https://docs.opencv.org/2.4/doc/tutorials/calib3d/camera_calibration/camera_calibration.html
- [stackoverflow] Meaning of the retval return value in cv2.CalibrateCamera: https://stackoverflow.com/questions/29628445/meaning-of-the-retval-return-value-in-cv2-calibratecamera
- [stackoverflow] Camera Calibration with OpenCV - How to adjust chessboard square size?: https://stackoverflow.com/questions/37310210/camera-calibration-with-opencv-how-to-adjust-chessboard-square-size