camera calibration과 왜곡 보정 (1)

정예슬·2023년 1월 23일
1

vision

목록 보기
1/21

설연휴 보내면서 좀좀따리 벨로그 쓰는 중..
연말 연초는 참 일하기도 공부하기도 싫다 ~~ ! 이제 설연휴 끝나면 핑계 댈 것도 없으니 열심히 해보기로... 🥹

오늘은 어쩌다가 vision쪽을 만지게 되면서 다시 친해지고 있는(???) opencv와 카메라 캘리브레이션에 대한 포스팅이다.


카메라의 왜곡(Distortion)

핀홀 카메라는 3D 이미지를 2D로 투영하는 과정에서 왜곡을 만든다. 이러한 왜곡에는 크게 2가지 종류가 있는데, 방사 왜곡(radial distortion)접선 왜곡(tangential distortion)이다.

방사 왜곡(radial distortion)

방사 왜곡은 직선이 곡선처럼 보이도록 만든다. 또한, 이미지의 센터점에서 더 먼 점들이 더 커보이도록 만든다.

예를 들면, 위 이미지에서 체스보드 판의 가장자리(빨간 선이 그려진 부분)를 보면, 일직선이 아니며 빨간 선과 비교했을 때 볼록해진 것을 알 수 있다.

방사 왜곡은 다음과 같은 식으로 표현된다.

xdistorted=x(1+k1r2+k2r4+k3r6)x_{distorted} = x(1 + k_1r^2 + k_2r^4+k_3r^6)
ydistorted=y(1+k1r2+k2r4+k3r6)y_{distorted} = y(1 + k_1r^2 + k_2r^4+k_3r^6)

접선 왜곡(tangential distortion)

접선 왜곡은 이미지의 일부분이 실제보다 가까워 보이도록 만든다.

접선 왜곡은 다음과 같은 식으로 표현된다.

xdistorted=x+[2p1xy+p2(r2+rx2)]x_{distorted} = x + [2p_1xy + p_2(r^2 + rx^2)]
ydistorted=y+[p1(r2+2y2)+2p2xy]y_{distorted} = y + [p_1(r^2 + 2y^2)+2p_2xy]

즉, 우리는 왜곡을 제거하기 위해 5개의 파라미터(k1k_1, k2k_2, p1p_1, p2p_2, k3k_3)를 구해야 하며, 이를 distortion coefficients라고 부른다.

또한, 카메라의 intrinsic, extrinsic 파라미터에 대한 정보가 추가로 필요하다.

Intrinsic parameters

Intrinsic 파라미터 값은 focal length (fxf_x, fyf_y)와 optical centers (cxc_x,cyc_y)를 포함하며, 카메라마다 특정되어 있다.

이러한 focal length와 optical centers를 사용하여, 다음과 같이 카메라 매트릭스(camera matrix)를 생성할 수 있다.

extrinsic parameters

extrinsic 파라미터는 좌표계의 3D 포인트 좌표를 변환한 rotation과 translation vectors에 해당한다.


카메라 캘리브레이션(Camera Calibration)

우리는 왜곡을 바로잡기 위해 이러한 파라미터들을 찾아야 한다. 따라서 체스 보드와 같은 well-defined된(체스 보드의 이미지상의 좌표와 실제 좌표를 알기 쉽기 때문에) 샘플 이미지를 사용하여 intrinsic parameters를 찾는다. 그리고 이러한 파라미터를 찾는 과정을 Camera Calibration이라고 한다.

opencv에서 캘리브레이션 함수를 사용하거나 체스보드 이미지를 활용해서 캘리브레이션을 시행해 주는 프로그램이 여러가지 있는데, 나는 darkprogramer의 캘리브레이션 툴(https://darkpgmr.tistory.com/32)을 사용해 보았다(핀홀 카메라만 적용할 수 있다).

캘리브레이션 과정

먼저 여러 각도, 위치에서 캘리브레이션을 하고자 하는 카메라로 특정 크기의 체스보드를 촬영한다. 나는 15*10 체스보드를 사용했다.

캘리브레이션이 잘 되기 위해서는 최소 10장 정도의 사진이 필요하다고 한다. 나는 약 20장 정도 촬영해서 프로그램을 돌려 보았다.

사진을 넣고 캘리브레이션을 수행하면, 왼쪽 아래에 intrinsic parameter들이 도출된다. 이제 이 파라미터들을 사용해서 왜곡을 보정할 수 있을 것이다.


왜곡 보정

방금 구한 파라미터들과 opencv의 왜곡 보정 함수를 사용하여 왜곡된 이미지를 복원해 보겠다.

import numpy as np
import cv2

dist = np.array([k1, k2, p1, p2, k3])
mtx = np.array([[fx, 0, cx],
      [0, fy, cy],
      [0, 0, 1]])

image = cv2.imread('./cali_images/WIN_20230110_13_21_30_Pro.jpg')

h, w = image.shape[:2]

newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,
                                                 dist,
                                                 (w, h),
                                                 1, (w, h))

# undistort
dst = cv2.undistort(image, mtx, dist, None, newcameramtx)

x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv2.imshow('result', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

왜곡 보정 전후를 비교하면 확실히 볼록한 면이 많이 사라진 걸 볼 수 있다.
일반 이미지에도 전과 후를 적용해보면 체스보드 만큼은 아니지만, 파라미터를 잘 찾았다면 대체로 잘 수행되는 것 같다.

profile
춘식이랑 함께하는 개발일지

0개의 댓글