Knowhow/Vision

Opencv large FoV image undistortion

침닦는수건 2022. 6. 16. 12:15
반응형

카메라 intrinsic calibration을 마치면 보통 K matrix와 distortion coefficient를 얻는다.

 

K matrix의 경우, fx, fy, cx, cy로 구성된 3x3 matrix일 것이고, distortion coefficient는 일반적인 화각의 카메라라면 5개, 그 외 다른 광각이라면 최대 14개까지 나올 것이다.

 

그리고 이 값을 사용해서 다음과 같은 함수를 통해 이미지의 왜곡을 펼치고 왜곡이 보정된 이미지 및 포인트를 사용하게 된다. 

   image_ud = cv2.undistort(image, K, dist)
   point_ud = cv2.undistortPoints(img_pt, K, dist, P=K)

 

하지만 광각 이미지의 경우, 위  함수를 통해 얻은 undistorted 이미지가 만족스럽지 못할 수 있다. 만족스럽지 못하다는 것이 왜곡 보정이 잘못된다는 것이 아니라 제대로 되는데 화각이 맘에 안 들 수 있다. 

 

그림으로 설명하자면,

왼쪽 그림처럼 광각 카메라의 경우, 광각 렌즈에 의해 scene으로부터 온 빛이 모이고 이 빛이 image plane에 찍혀 이미지가 된다. image plane은 평면인데 빛은 평면이 담을 수 있는 영역보다 넓은 곳에서 모이기 때문에 꾸역꾸역 우겨넣으려다 보니 왜곡이 생기는 상황이라고 볼 수 있다.

 

이를 일반적으로 사용하듯 cv2.undistort 로 펼치게 되면 오른쪽 그림처럼 scene으로부터 오는 빛은 그대로 있되, 렌즈가 평평해지는 것과 같은 상태로 변환한다고 볼 수 있는데 이러면 당연히도 image plane으로 찍히는 빛의 범위는 줄어든다. 즉, 현재 focal length로 평면이 원래 담을 수 있는 scene 영역만 image plane에 표현되게 된다. (외곽부분은 보이지가 않게 됨. image plane에 찍히지 않을 뿐 데이터는 존재함.) 

 

다음 예시를 보면 왜곡 보정 전 대비 왜곡 보정 후가 더 적은 영역을 커버하는 것을 볼 수 있다.

따라서 왜곡 보정 후 잘려나가는 영역에 사용하고자 했던 시각 정보가 있다면 왜곡 보정이 화각 때문에 만족스럽지 못할 수 있다.

 

해결 방법은, 임의로 image plane의 위치를 뒤로 옮겨서 scene에서 오는 빛을 다 받을 수 있도록 하는 것이다. 즉, focal length를 적정값으로 변경해주면 된다.

 

또 다시 그림으로 보면, 

왜곡을 펴는 것 까지 동일하고, 원래 image plane 위치 (점선)을 조금 더 뒤로( focal length를 짧게) 옮기면 평면 image plane으로 원래 scene에서 오는 빛을 그대로 받을 수 있다. 

 

image plane을 옮기는 행위 (focal length 변경)는 다행히 Opencv 에서 지원해준다. 그리고 그 옮기는 행위까지 한 번에 undistort함수에 반영할 수 있도록 되어있다.

 

 new_K, roi = cv2.getOptimalNewCameraMatrix(K, dist, (img_w, img_h), 1)
 image_ud = cv2.undistort(img, K, dist, None, new_K)
 point_ud = cv2.undistortPoints(img_pt, K, dist, new_K)

 

위 함수로 왜곡을 보정하게 되면, 왜곡을 펼치지만 화각 손실 없이 원래 scene에서 받은 빛을 전부 다 image plane에 표현할 수 있는 위치(최적 focal length)가 계산되고 해당 위치에서 이미지를 촬영한 것처럼 변환된다. 이미지 말고 point도 마찬가지다.

 

추천하기를, 렌즈 왜곡이 육안으로 봐선 얼마나 심한지 모르고 일반적으로 cv2.undistort를 쓰면 얼마나 scene이 잘려나갈지 감잡기가 어려우니 무조건 image plane을 옮기는 과정까지 포함해서 왜곡 보정하는 것이 좋다.

반응형