목표

카메라의 내부 파라미터 (초점거리, 주점좌표 등) 획득 후 이미지 왜곡 보정

$$ 내부파라미터 = \begin{bmatrix} f_x & 0 & c_x \\ 0 &f_y&c_y\\0&0&1 \end{bmatrix} $$

캘리브레이션 방법

체커보드 준비

19장의 체커보드 이미지 촬영. 내부 코너의 행렬 크기 : 7x4

19장의 체커보드 이미지 촬영. 내부 코너의 행렬 크기 : 7x4

캘리브레이션 python 구현 코드

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)

캘리브레이션 결과

Untitled

Untitled

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

내부 파라미터 획득 결과

19장 체커보드 추출 시 내부 파라미터와 왜곡 계수

19장 체커보드 추출 시 내부 파라미터와 왜곡 계수

Re-prohection Error

파라미터가 얼마나 정확한지 추정해준다. 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))