이 글은 핀홀 카메라만 다루고 있습니다.
카메라 캘리브레이션의 목적은 카메라 내부 파라미터 (Intrinsic parameter)와 왜곡 계수(Distortion Coefficients)를 구하는 것이다.
왜곡 계수
핀홀 카메라의 왜곡은 방사형 왜곡(Radial Distortion)과 접선 왜곡(Tangential Distortion) 2가지로 나뉜다.
![](https://velog.velcdn.com/images/openjr/post/c94d8d93-2aeb-4666-9679-857f382c0f5b/image.png)
방사형 왜곡
렌즈에 의해 발생하는 왜곡이다. 왜곡으로 인해 변형되는 픽셀의 값은 다음과 같다.
xd=(1+k1r2+k2r4+k3r6)xuyd=(1+k1r2+k2r4+k3r6)yur2=(xd−cx)2+(yd−cy)2
접선 왜곡
접선 왜곡은 제조과정에서 카메라 렌즈와 카메라 센서(CMOS)가 완벽히 평행하지 않아 발행되는 왜곡이다.
xd=xu+[2p1xuyy+p2(r2+2xu2)]yd=yu+[2p2xuyy+p1(r2+2yu2)]r2=(xd−cx)2+(yd−cy)2
결국, 우리가 알아내야 하는 값은 k1, k2, k3, p1, p2이며 이 값들은 OpenCV에서 왜곡 계수는 [k1, k2, p1, p2, k3] 순으로 값이 구해지게 된다.
카메라 내부 파라미터
![](https://velog.velcdn.com/images/openjr/post/f9393c3d-4465-4a07-8d7d-81845f7618a2/image.png)
![](https://velog.velcdn.com/images/openjr/post/5d16c1a4-f06b-4e48-bc26-6c8467a709ca/image.png)
카메라 내부 파라미터를 구성하는 요소들은 다음과 같다.
- Focal Length (초점 거리): 렌즈 중심에서 이미지 센서까지의 거리.
- Principal Point (주점): 렌즈의 중심에서 이미지 센서에 내린 수선의 발의 이미지 상 좌표.
- Skew Coefficient (비대칭 계수): 이미지 센서가 제조 공정상 기울어진 정도 (현대 카메라에서는 거의 없음)
위 값들은 3차원 물체의 위치를 2차원 이미지의 좌표로 투영할 때 사용된다.
OpenCV 코드
전체적인 코드를 보기를 전 주요한 OpenCV 함수들에 대해 먼저 알아보겠습니다.
findChessboardCorners()
retval, corners = cv2.findChessboardCorners(image, patternSize, flags)
- image: 체커보드 이미지
- patternSize: 체커보드 행과 열의 코너 수
- flags: Corner Detection 알고리즘 적용 시 옵션 값 (default=
CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE
)
CALIB_CB_ADAPTIVE_THRESH
: 이진화 시, Adaptive Threshold 적용
CALIB_CB_NORMALIZE_IMAGE
: 이진화 적용 전, 히스토그램 평활화로 흰색과 검은색 분리
CALIB_CB_FILTER_QUADS
: 코너 점 찾은 후, 점들 간의 위치로 사각형의 코너가 아닌 점들을 필터링
CALIB_CB_FAST_CHECK
: Corner Detection 알고리즘이 동작 전, 이미지에 체스보드 패턴이 있는지 검사해, 없으면 빠르게 false를 리턴
cornerSubPix()
corners2 = cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria)
- image: 체커보드 이미지
- corners:
findChessboardCorners()
로 검출된 코너 값 (개선 전)
- winSize: 코너를 개선하기위해 gradient vector를 고려할 윈도우의 크기. (11, 11)은 총 23X23의 윈도우 크기를 가진다.
- zeroZone: winSize에서 배제될 영역의 크기, 보통은 (-1, -1)로 설정하지 않게 된다.
- criteria: 알고리즘이 종료될 조건을 설정하는 부분. 보통 (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)로 설정하며, 이것은 최대 반복 수 30, 이전 값과의 차이 0.001 미만 일 때 종료라는 의미이다.
![](https://velog.velcdn.com/images/openjr/post/b0c204e6-59cb-468b-a540-61c3ee916b71/image.png)
winSize=(3, 3), zeroZone=(1, 1)일 경우,
- 초록색: grdient가 고려될 픽셀들
- 회색: zeroZone으로 배제될 픽셀들
calibrateCamera()
return_value, camera_matrix, distortion_coefficients, rotation_vectors, translation_vectors = cv2.calibrateCamera(object_points, image_points, imageSize, init_matrix, init_coefficients, rvecs, tvecs, flags, criteria)
- object_points: 실제 객체들의 3차원 좌표
- image_points: 이미지에 투영된 객체들의 이미지 좌표
- imageSize: 이미지 크기
- init_matrix: 초기 추정 내부 파라미터
- init_coefficients: 초기 추정 왜곡 계수
- rvecs: 초기 추정 rotation vectors
- tvecs: 초기 추정 translation vectors
- flags: 캘리브레이션 옵션 (옵션이 13개나 있다. 이것 만큼은 직접 찾아보자. 주로 초기 추정 값이 있으면 아래의 옵션을 추가한다.)
- CALIB_USE_INTRINSIC_GUESS: 내부 파라미터 초기 값으로 최적화
- criteria: 알고리즘이 종료될 조건을 설정하는 부분. 보통 (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)로 설정하며, 이것은 최대 반복 수 30, 이전 값과의 차이 0.001 미만 일 때 종료라는 의미이다.
getOptimalNewCameraMatrix()
undistort()
initUndistortRectifyMap()
& remap