카메라의 내부 파라미터 (초점거리, 주점좌표 등) 획득 후 이미지 왜곡 보정
$$ 내부파라미터 = \begin{bmatrix} f_x & 0 & c_x \\ 0 &f_y&c_y\\0&0&1 \end{bmatrix} $$
캘리브레이션 패턴 이용
알려진 패턴의 이미지를 여러 각도에서 촬영
OpenCv 내장 함수 이용

19장의 체커보드 이미지 촬영. 내부 코너의 행렬 크기 : 7x4
import cv2
import numpy as np
import os
import glob
#체커보드의 차원 정의
CHECKERBOARD = (7, 4) # 체커보드 내부 코너 행렬
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# cv2.TERM_CRITERIA_EPS : 주어진 정확도(epsilon 인자)에 도달하면 반복을 중단
# cv2.TERM_CRITERIA_MAX_ITER : max_iter 인자에 지정된 횟수만큼 반복하고 중단
# 각 체커보드 이미지에 대한 3D 점 벡터를 저장할 벡터 생성
objpoints = []
#각 체커보드 이미지에 대한 2D 점 벡터를 저장할 벡터 생성
imgpoints =[]
# 3D 점의 세계 좌표 정의
objp = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1,2)
prev_img_shape = None
# 개별 이미지의 경로 추출
images = glob.glob('./images/checkerboard/*.jpg')
for fname in images:
img = cv2.imread(fname)
#그레이스케일
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 체커보드 코너 찾기
#이미지에서 원하는 개수의 코너가 발견되면 ret = true
ret, corners = cv2.findChessboardCorners(gray,CHECKERBOARD,cv2.CALIB_CB_ADAPTIVE_THRESH+cv2.CALIB_CB_FAST_CHECK+cv2.CALIB_CB_NORMALIZE_IMAGE)
#원하는 개수의 코너가 감지되면,
#픽셀 좌표 미세조정 -> 체커보드 이미지 표시
if ret == True:
objpoints.append(objp)
#주어진 2D 점에 대한 픽셀 좌표 미세조정
corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints.append(corners2)
#코너 그리기 및 표시
img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 알려진 3D 점(objpoints) 값과 감지된 코너의 해당 픽셀 좌표(imgpoints) 전달, 카메라 캘리브레이션 수행
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("Camera matrix : \\n") # 내부 카메라 행렬
print(mtx)
print("dist : \\n") # 왜곡 계수
print(dist)


이미지에 대해 체커보드 코너가 그려진 모습 일부

19장 체커보드 추출 시 내부 파라미터와 왜곡 계수
파라미터가 얼마나 정확한지 추정해준다. 0에 가까울 수록 좋다.
mean_error = 0
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i],imgpoints2,cv2.NORM_L2)/len(imgpoints2)
tot_error += error
print("total error: ", tot_error/len(objpoints))