Opencv 를 이용해서 카메라를 intrinsic calibration하고자 할 때, 보통은 아주 쉽게 다음의 함수를 이용해서 할 수 있다.
import cv2
mtx = None
dist = None
rvecs = None
tvecs = None
obj_points = TARGET_3DPOINT
img_points = TARGET_2DPOINT
RMSE, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (img_w, img_h), mtx, dist, rvecs, tvecs)
하지만 광각 카메라로 취득한 이미지를 대상으로 intrinsic calibration을 시도할 때, 위 함수를 그대로 사용할 경우, reprojection error는 줄어들지만 이미지를 undistort하여 정성적으로 보면 이미지가 깨지는 경우가 있다.
즉, 최적화 방향이 잘못되어 reprojection error만 줄이고 정작 제대로 calibration이 되지 않은 것이다.
예시 결과인데, 평균 2.38px의 reprojection error로 수렴하여 calibration이 끝났다. 이미지 해상도가 1920x1080 일 때, 이 정도면 쓸만하다고 할 수 있다.
하지만 undistort까지 해서 정성적으로 보면 수치만 보고 잘됐다고 믿기엔 정상적이지 않다는 것을 알고 있다. 단순히 생각했을 때 광각 이미지는 undistort됐을 때 pincushion과 같은 모양으로 펼쳐져야 되는데 이러한 모양을 완전히 잘못됐다.
그 이유는, 일반적인 FoV 카메라에 적용하는 distortion 모델과 120도를 넘어가는 큰 FoV 카메라 적용하는 distortion 모델이 다르기 때문이다. (아래 링크와 pdf 참조)
해결법은 아주 단순하다. 하나의 flag를 넣어서 돌리면 끝난다. (fisheye 렌즈급으로 FoV가 180도를 넘어가면 이 방법도 안됨. 따로 cv2.fisheye 내의 calibration 함수를 써야 함.)
flags = cv2.CALIB_RATIONAL_MODEL
RMSE, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (img_w, img_h), mtx, dist, rvecs, tvecs, flags=flags)
그러면 위와 같이 정상적인 결과를 얻을 수 있다. 하나의 차이는 distortion 모델 (rational 모델)을 바꾸었기 때문에 일반적으로 우리가 아는 distortion coefficient가 5개가 아니라 14개 나온다.
즉, k1, k2, p1, p2, k3가 나오는게 아니라 k1, k2 , p1, p2, k3, k4, k5, k6 , s1, s2, s3, s4, τx, τy가 나온다.
따라서 distortion coefficient를 써야하는 경우가 있다면, 그 때도 일반적인 카메라가 아닌 광각 카메라의 파라미터라는 것을 유념하고 알맞게 사용해야 한다.
https://stackoverflow.com/questions/20121976/wide-angle-lenses-calibration-with-opencv
https://www.robots.ox.ac.uk/~dclaus/publications/claus05rf_model.pdf
'Knowhow > Vision' 카테고리의 다른 글
Obj file의 manifold/non-manifold 구분 (0) | 2022.06.30 |
---|---|
3D mesh voxelization (0) | 2022.06.17 |
Opencv large FoV image undistortion (0) | 2022.06.16 |
Opencv multi webcam 사용 시 인식 확인 (0) | 2022.06.13 |
Opencv webcam resolution control (0) | 2022.06.13 |