카메라 왜곡보정 - 이론 및 실제

영상처리 2013. 2. 4. 02:49

저번 카메라 캘리브레이션에 대한 포스팅에 이어 오늘은 카메라 렌즈 왜곡 보정에 대해 이론에서 실제까지 전반적인 내용을 포스팅합니다.

 

카메라 캘리브레이션 및 왜곡 보정은 영상처리 분야에서는 거의 필수적으로 필요한 내용입니다. 하지만 막상 본인 스스로 이런 것들을 하려면 쉽지가 않습니다. 전반적인 카메라 시스템에 대한 이해가 필요하며 이것 저것 알아보는데 많은 시간이 필요합니다. 외국의 경우 (주로 영어권) 이러한 정보공유가 잘 되어 있어서 서로서로 잘 발전해 나가지만 우리에게는 진입장벽이 높은 편입니다. 본 글은 이러한 시간을 단축시키고 많은 분들이 좀더 손쉽게 캘리브레이션 및 영상 왜곡보정에 접근할 수 있도록 관련된 실질적인 이론 및 방법, 절차를 최대한 쉽게 정리하고자 노력하였습니다.

 

1. 렌즈계 왜곡의 종류

2. 렌즈계 왜곡의 수학적 모델

3. 영상 왜곡 보정

4. 영상좌표 왜곡 보정

5. 샘플 프로그램

 

카메라에 시야각(FOV)이 넓은 광각렌즈나 초광각 렌즈를 사용하면 넓은 범위를 볼 수 있지만 이로 인해 아래 그림과 같이 상대적으로 영상왜곡이 심해지는 문제가 있습니다.

 

그림출처: http://www.ivs.auckland.ac.nz/web/calibration.php

 

이러한 영상 왜곡은 시각적인 문제 외에도 영상분석을 통해 정확한 수치 계산이 필요할 때 특히 문제가 됩니다. 예를 들어서, 영상에서 검출한 물체의 실제 위치를 알기 위해 영상좌표를 물리적인 좌표로 변환한다면 영상왜곡 정도에 따라 심각한 오차가 발생할 것입니다.

 

 

1. 렌즈계 왜곡의 종류

 

렌즈 왜곡에는 크게 방사왜곡(radial distortion)과 접선왜곡(tangential distortion)이 있습니다.

 

방사왜곡은 볼록렌즈의 굴절률에 의한 것으로서 아래 그림과 같이 영상의 왜곡 정도가 중심에서의 거리에 의해 결정되는 왜곡입니다. 

 

방사왜곡(radial distortion)

 

반면, 접선왜곡(tangential distortion)은 카메라 제조(조립) 과정에서 카메라 렌즈와 이미지센서(CCD, CMOS)의 수평이 맞지 않거나 또는 렌즈 자체의 centering이 맞지 않아서 발생하는 왜곡으로서 아래 그림과 같이 타원형 형태로 왜곡 분포가 달라집니다 (접선왜곡은 다른 말로 decentering distortion 이라고도 불립니다). 참고로 http://carstart.tistory.com/181에 보면 방사왜곡과 접선왜곡의 개념이 그림을 통해 직관적으로 잘 설명되어 있습니다. 

 

접선왜곡(tangential distortion)

 

 

2. 렌즈계 왜곡의 수학적 모델

 

일반적으로 렌즈 왜곡의 수학적 모델은 카메라 내부 파라미터의 영향이 제거된 normalized image plane에서 정의됩니다.

 

렌즈계의 왜곡이 없다고 할 경우, 3차원 공간상의 한 점 (Xc, Yc, Zc)는 central projection (pinhole projection)에 의해 normalized image plane상의 한 점 (xn_u, yn_u)로 투영됩니다 (첨자 n: normalized, u: undistorted):

 

(1)

 

그러나 실제로는 (xn_u, yn_u)는 렌즈계의 비선형성에 의해 왜곡(주로 radial distortion)이 됩니다. (xn_d, yn_d)를 렌즈계의 왜곡이 반영된 normalized 좌표라면, 렌즈계 왜곡 모델은 다음과 같습니다 (첨자 d: distorted):

 

(2)

 

단,

 

 

위 수식에서, 우변의 첫번째 항은 radial distortion, 두번째 항은 tangential distortion을 나타냅니다 (k1, k2, k3는 radial distortion coefficient, p1, p2는 tangential distortion coefficient). ru는 왜곡이 없을 때의 중심(principal point)까지의 거리(반지름)입니다.

 

이 때, (xn_d, yn_d)는 normalized image plane에서의 좌표이며 실제 영상 픽셀 좌표 (xp_d, yp_d)는 카메라 내부 파라미터를 반영하여 다음과 같이 구해집니다.

 

(3)

 

즉,

 

(4)

 

여기서, fx, fy는 초점거리, cx, cy는 렌즈 중심 영상좌표(principal point), skew_c는 비대칭계수를 나타내는 카메라 내부 파라미터들입니다. 카메라 내부 파라미터에 대한 자세한 내용은 [영상처리] - 카메라 캘리브레이션 (Camera Calibration)를 참조하시기 바랍니다.

 

 

3. 영상 왜곡 보정

 

왜곡된 영상으로부터 보정된 영상을 생성하는 것은 비교적 간단하게 구현할 수 있습니다 (참고로, 왜곡된 영상을 보정하기 위해서는 먼저 카메라 캘리브레이션을 통해 카메라 내부 파라미터(intrinsic parameter)를 구해야 합니다. 카메라 캘리브레이션에 대해서는 [영상처리] - 카메라 캘리브레이션 (Camera Calibration)를 참조하시기 바랍니다).

 

왜곡된 영상을 Id, 보정된 Iu라 하겠습니다. 기본 아이디어는 Iu의 각 픽셀값을 해당 픽셀 좌표를 왜곡시켰을 때의 Id의 대응되는 픽셀값으로 채우는 것입니다.

 

영상 Iu의 한 점을 (xp_u, yp_u)라 하면, 일단 이것을 카메라 파라미터를 역으로 적용하여 normalized 좌표 (xn_u, yn_u)로 변환합니다.

 

(5)

 

즉,

 

(6)

 

다음으로, 중심까지의 거리 ru (ru2 = xn_u2 + yn_u2)를 구하고 식(2) 왜곡모델을 적용하여 왜곡된 좌표 (xn_d, yn_d)를 구합니다.

 

(7)

 

마지막으로 (xn_d, yn_d)를 다시 픽셀 좌표계로 변환하면 (xp_u, yp_u)의 왜곡된 영상에서의 좌표 (xp_d, yp_d)를 구할 수 있습니다.

 

(8)

 

 

영상 왜곡보정 (예제 코드)

 

function undistort_image(Id, Iu, fx, fy, cx ,cy, skew_c, k1, k2, k3, p1, p2)

    w: image width of Iu

    h: image height of Iu

    for y = 0:h-1,

        for x = 0:w-1,

            y_nu = (y-cy)/fy;

            x_nu = (x-cx)/fx – skew_c*y_nu;

 

            ru2 = x_nu*x_nu + y_nu*y_nu; // ru2 = ru*ru

            radial_d = 1 + k1*ru2 + k2*ru2*ru2 + k3*ru2*ru2*ru2;

 

            x_nd = radial_d*x_nu + 2*p1*x_nu*y_nu + p2*(ru2 + 2*x_nu*x_nu);

            y_nd = radial_d*y_nu + p1*(ru2 + 2*y_nu*y_nu) + 2*p2*x_nu*y_nu;

 

            x_pd = fx*(x_nd + skew_c*y_nd) + cx;

            y_pd = fy*y_nd + cy;

 

            Iu(x, y) = Id(x_pd, y_pd);

        end;

    end;    

return Iu;

 

 

 

☞ (2017.05.16) 정말 많은 분들이 왜 이렇게 왜곡보정을 해야 하는지 이해하기 힘들다고 합니다. 그래서 부연설명을 추가합니다. I가 입력영상(왜곡된 영상), I'을 왜곡을 편 영상(보정된 영상)이라 하겠습니다. 직관적으로 생각할 수 있는 방법은 원본영상의 각 픽셀 (x, y)에 대응되는 왜곡 보정된 좌표 (x', y')을 구한 후, 해당 위치의 보정영상에 대입하는 것입니다 (즉, ∀x,y, I'(x',y') = I(x,y)). 그런데, 이렇게 왜곡을 펴면 보정 영상(I')에 구멍이 뚫려서 보기 흉하게 되는 문제가 발생합니다. 이미지의 왜곡을 펴는 것은 손으로 잡고 쭉 늘이는 것과 같기 때문에 원본 픽셀을 보정영상에 대입하면 보정된 영상에서는 중간 중간 이빨이 빠진 것처럼 빈 픽셀(pixel)들이 발생하게 됩니다. 따라서 이러한 문제를 해결하기 위해서는 위의 예제 코드와 같이 발상의 전환이 필요합니다. 그건 입력영상의 왜곡을 펴서 보정영상을 만드는 것이 아니라 보정영상을 먼저 만들어 놓고 보정영상의 각 픽셀에 대응되는 원본영상의 픽셀을 가져오는 것입니다. 즉, 보정영상의 각 픽셀좌표 (x', y')에 대해 왜곡된(왜곡을 일부러 가한) 좌표를 구하고 이렇게 구한 좌표에 대응하는 원본영상의 픽셀을 가져와 보정영상에 대입합니다. 이렇게 하면 이빨빠짐 현상이 없는 깨끗한 영상이 얻어집니다.

 

☞ (2022.11.04) 위 설명도 지금보니 어렵네요. 다시 추가합니다.. 철수에게 늘어난(왜곡된) 그림을 주고는, 반듯하게 보정된 그림을 옆에 새로 그려라는 미션을 주었습니다. 철수는 고민하다가, 먼저 새로운 도화지에 눈금(모눈종이처럼)을 그립니다. 그리고, 첫번째 눈금에 해당되는 값을 원래의 일그러진 그림에서 찾아다가 그려 넣습니다. 그리고 두번째 눈금에 해당하는 값도 찾아서 넣습니다. 이렇게 그렸더니 깨끗하게 복원된 새로운 그림을 얻을 수 있었습니다. 

 

만일, 단순한 모델을 사용하고 싶거나 카메라 파라미터가 충분치 않으면 위 수식들을 적절히 수정하면 됩니다. 예를 들어, 대부분의 경우 radial distortion이 주이고 tangential distortion은 미약하기 때문에 식 (2)에서 tangential term을 생략하기도 합니다 (p1=p2=0). 또한 radial term도 k1, k2까지만 사용하는 것이 일반적입니다 (즉, k3 = 0). 비대칭 계수인 skew_c도 대부분 생략됩니다 (skew_c = 0). (cx, cy)도 구하기 힘든 경우에는 영상 중심(image_width/2, image_height/2)으로 놓기도 합니다 (하지만 cx, cy는 중요하기 때문에 가급적 정확하게 측정하는게 좋습니다).

 

 

4. 영상좌표 왜곡 보정

 

실제 영상처리에서는 종종 보정된 영상을 구하는 것보다는 보정된 영상좌표를 구하는 것이 훨씬 중요합니다. 왜냐하면 때로는 영상전체를 보정한 후에 영상처리 알고리즘을 적용하는 것보다는 원래 왜곡된 영상에서 처리를 한 후에 그 결과만 보정(undistort)을 하는 것이 효과적일 수 있기 때문입니다.

 

그런데, 왜곡된 영상좌표로부터 왜곡 보정된 영상좌표를 구하는 것은 closed-form solution이 없는 매우 어려운 문제로서 보통 근사적으로 해를 구합니다 (식 7을 잘 보면 n_u로부터 n_d를 구하는 것은 쉬우나 반대로 n_d에서 n_u를 구하는 것은 7차 방정식을 풀어야 하는 매우 어려운 문제임을 알 수 있습니다).

 

왜곡된 영상좌표 p_d로부터 왜곡 보정된 좌표 p_u를 구하는 한 방법은 p_u = p_d로 가정하고 식 (2)를 이용해서 p_u를 왜곡시켜 보는 것입니다. 이렇게 구한 점이 실제 p_d와 얼마나 오차가 나는지를 계산해서 그 오차를 p_u에 역으로 반영시킵니다. 예를 들어, p_u를 왜곡시킨 점이 p_d보다 δ만큼 크다면 p_u를 δ만큼 감소시킵니다. 이러한 과정을 오차가 임계값 이하가 될 때까지 반복합니다 (보통 3~4번만 반복해도 거의 정확한 p_u값을 얻을 수 있습니다).

 

영상좌표 왜곡보정 (예제 코드)

 

 

function undistort(point p_d)

      p_d’ = normalize(p_d);

      p_u’ = p_d’;

      while (1)

            err = distort_normal(p_u’) – p_d’;

            p_u’ = p_u’ – err;

            if(err<err_threshold) break;

      end;

      p_u = denormalize(p_u’);

return p_u;

 

function normalize(x, y)

      y_n = (y-cy)/fy;

      x_n = (x-cx)/fx – skew_c*y_n;

return (x_n, y_n);

 

function denormalize(x, y)

      x_p = fx*(x + skew_c*y) + cx;

      y_p = fy*y + cy;

return (x_p, y_p);

 

function distort_normal(x, y)

      r2 = x*x + y*y;

      radial_d = 1 + k1*r2 + k2*r2*r2 + k3*r2*r2*r2;

      x_d = radial_d*x + 2*p1*x*y + p2*(r2 + 2*x*x);

      y_d = radial_d*y + p1*(r2 + 2*y*y) + 2*p2*x*y;

return (x_d, y_d);

 

 

 

 

5. 샘플 프로그램

 

라이브로 카메라 영상 또는 비디오 파일을 왜곡 보정하여 보여주는 예제 프로그램(소스 포함)은 [개발한 것들] - 라이브 왜곡 보정 프로그램을 참조해 주세요.

 

 

관련 포스팅

 

by 다크 프로그래머

 

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

영상처리 2013. 2. 1. 16:59

카메라 캘리브레이션 (camera calibration)은 영상처리, 컴퓨터 비전 분야에서 번거롭지만 꼭 필요한 과정중의 하나입니다. 본 포스팅에서는 카메라 캘리브레이션의 개념, 카메라 내부 파라미터, 외부 파라미터, 카메라 핀홀 모델, 카메라 캘리브레이션 도구에 대해 관련된 개념이나 이론적 배경들을 전반적으로 정리해 보았습니다.


그림1. 카메라 캘리브레이션


0. 카메라 캘리브레이션이란?

1. 캘리브레이션 개요

2. 카메라 내부 파라미터(intrinsic parameters)

3. 카메라 외부 파라미터(extrinsic parameters)

4. 핀홀(pinhole) 카메라 모델

5. 캘리브레이션과 영상해상도 그리고 자동초점조절(auto focusing)

6. 캘리브레이션 도구(tool) 및 사용법

7. 캘리브레이션 결과가 달라지는 이유

8. 카메라 캘리브레이션 팁



0. 카메라 캘리브레이션이란?


우리가 실제 눈으로 보는 세상은 3차원입니다. 하지만 이것을 카메라로 찍으면 2차원의 이미지로 변하게 됩니다. 이 때, 3차원의 점들이 이미지 상에서 어디에 맺히는지는 기하학적으로 생각하면 영상을 찍을 당시의 카메라의 위치 및 방향에 의해 결정됩니다. 하지만 실제 이미지는 사용된 렌즈, 렌즈와 이미지 센서와의 거리, 렌즈와 이미지 센서가 이루는 각 등 카메라 내부의 기구적인 부분에 의해서 크게 영향을 받습니다. 따라서, 3차원 점들이 영상에 투영된 위치를 구하거나 역으로 영상좌표로부터 3차원 공간좌표를 복원할 때에는 이러한 내부 요인을 제거해야만 정확한 계산이 가능해집니다. 그리고 이러한 내부 요인의 파라미터 값을 구하는 과정을 카메라 캘리브레이션이라 부릅니다.



1. 캘리브레이션 개요


카메라 영상은 3차원 공간상의 점들을 2차원 이미지 평면에 투사(perspective projection)함으로써 얻어집니다. 핀홀(pinhole) 카메라 모델에서 이러한 변환 관계는 다음과 같이 모델링됩니다.


(1)


여기서, (X,Y,Z)는 월드 좌표계(world coordinate system) 상의 3D 점의 좌표, [R|t]는 월드 좌표계를 카메라 좌표계로 변환시키기 위한 회전/이동변환 행렬이며 A는 intrinsic camera matrix입니다.


그림 2. 카메라 좌표계


수식적으로 보면 카메라 캘리브레이션(camera calibration)은 위와 같은 3D 공간좌표와 2D 영상좌표 사이의 변환관계 또는 이 변환관계를 설명하는 파라미터를 찾는 과정입니다.


식(1)에서 [R|t]를 카메라 외부 파라미터(extrinsic parameter), A를 내부 파라미터(intrinsic parameter)라고 부릅니다. 그리고 A와 [R|t]를 합쳐서 camera matrix 또는 projection matrix라 부릅니다.


카메라 외부 파라미터는 카메라의 설치 높이, 방향(팬, 틸트) 등 카메라와 외부 공간과의 기하학적 관계에 관련된 파라미터이며 내부 파라미터는 카메라의 초점 거리, aspect ratio, 중심점 등 카메라 자체의 내부적인 파라미터를 의미합니다.



2. 카메라 내부 파라미터(intrinsic parameters)


카메라의 내부 파라미터로는 다음과 같은 것들이 있습니다.

  1. 초점거리(focal length): fx, fy
  2. 주점(principal point): cx, cy
  3. 비대칭계수(skew coefficient): skew_c = tanα



A. 초점거리(focal length)


흔히 초점거리라 하면 볼록렌즈의 초점을 생각하기 쉬운데, 여기서(카메라 모델) 말하는 초점거리는 렌즈중심과 이미지센서(CCD, CMOS 등)와의 거리를 말합니다.


그림 3. 카메라 모델


디지털 카메라 등에서 초점거리는 mm 단위로 표현되지만 카메라 모델에서 말하는 초점거리(f)는 픽셀(pixel) 단위로 표현됩니다. 즉, f의 단위로 픽셀이라는 의미입니다.


이미지의 픽셀(pixel)은 이미지 센서의 셀(cell)에 대응되기 때문에, 초점거리(f)가 픽셀(pixel) 단위라는 의미는 초점거리가 이미지 센서의 셀(cell) 크기에 대한 상대적인 값으로 표현된다는 의미입니다. 예를 들어, 이미지 센서의 셀(cell)의 크기가 0.1 mm이고 카메라의 초점거리가 f = 500 pixel이라고 하면 이 카메라의 렌즈 중심에서 이미지 센서까지의 거리는 이미지 센서 셀(cell) 크기의 500배 즉, 50 mm라는 의미입니다.


컴퓨터 비전 분야에서 카메라 초점거리를 물리단위(m, cm, mm, ...)가 아닌 픽셀단위로 표현하는 이유는 (이미지 픽셀과 동일한 단위로 초점거리를 표현함으로써) 영상에서의 기하학적 해석을 용이하게 하기 위함입니다.


그런데, 카메라 모델에서 초점거리를 하나의 값으로 f라 표현하지 않고 fx, fy로 구분하여 표현하는 경우가 있는데(실제로 카메라 캘리브레이션을 수행하면 fx, fy를 구분하여 반환한다) 이는 이미지 센서의 물리적인 셀 간격이 가로 방향과 세로 방향이 서로 다를 수 있음을 모델링하기 위함입니다. 이 경우 fx는 초점거리(렌즈중심에서 이미지 센서까지의 거리)가 가로 방향 셀 크기(간격)의 몇 배인지를 나타내고 fy는 초점거리가 세로 방향 센서 셀 크기(간격)의 몇 배인지를 나타냅니다. fx와 fy 모두 단위는 픽셀(pixel)이며 현대의 일반적인 카메라는 가로방향 셀 간격과 세로방향 셀 간격의 차이가 없기 때문에 f = fx = fy라 놓아도 무방합니다.


참고로, 동일한 카메라로 캘리브레이션을 수행했을 때, 이미지 해상도를 1/2로 낮추면 캘리브레이션 결과의 초점거리도 1/2로 작아집니다. 실제 물리적 초점거리가 변하는 것은 아니지만 카메라 모델에서의 초점거리는 상대적인 개념이기 때문에 해상도를 바꾸면 한 픽셀(pixel)에 대응하는 물리크기가 변하고 따라서 초점거리도 변하게 됩니다. 예컨데, 이미지 해상도를 1/2로 낮추면 이미지 센서의 2 x 2 셀(cell)들이 합쳐서 하나의 이미지 픽셀이 되기 때문에 한 픽셀에 대응하는 물리크기가 2배가 됩니다. 따라서 초점거리는 1/2이 되어야 합니다.


카메라 모델의 렌즈중심(초점)은 핀홀 카메라 모델(그림 6)에서 핀홀(pinhole)에 해당됩니다. 핀홀 카메라 모델은 모든 빛은 한 점(초점)을 직선으로 통과하여 이미지 평면(센서)에 투영된다는 모델입니다. 이러한 핀홀 모델은 3D 공간과 2D 이미지 평면 사이의 기하학적 투영(projection) 관계를 매우 단순화시켜 줍니다.


초점으로부터 거리가 1(unit distance)인 평면을 normalized image plane이라고 부르며 이 평면상의 좌표를 보통 normalized image coordinate라고 부릅니다. 물론 이것은 실제는 존재하지 않는 가상의(상상의) 이미지 평면입니다. 카메라 좌표계 상의 한 점 (Xc, Yc, Zc)를 영상좌표계로 변환할 때 먼저 Xc, Yc를 Zc(카메라 초점에서의 거리)로 나누는 것은 이 normalized image plane 상의 좌표로 변환하는 것이며, 여기에 다시 초점거리 f를 곱하면 우리가 원하는 이미지 평면에서의 영상좌표(pixel)가 나옵니다 (그림 4 참조). 그런데, 이미지에서 픽셀좌표는 이미지의 중심이 아닌 이미지의 좌상단 모서리를 기준(원점)으로 하기 때문에 실제 최종적인 영상좌표는 여기에 (cx, cy)를 더한 값이 됩니다. 즉, x = fxX/Z+cx, y = fyY/Z+cy. 카메라 모델에서 사용하는 좌표계 표현 및 변환에 대한 보다 자세한 내용에 대해서는 [영상처리] - [영상 Geometry #1] 좌표계 글을 참조하기 바랍니다.



그림 4. 카메라 투영(projection) 모델


☞ 초점거리에 대한 보다 자세한 내용에 대해서는 [영상처리] - 카메라의 초점거리(focal length) 글을 참조하기 바랍니다 (2013.10.23).

☞ 이미지평면(이미지센서)은 실제로는 렌즈 뒤쪽에 있지만, 기하학적 연산을 단순화하기 위해 위 그림처럼 렌즈 앞쪽에 위치시키는 것이 일반적입니다. (reflected model)



B. 주점(principal point)


주점 cx, cy는 카메라 렌즈의 중심 즉, 핀홀에서 이미지 센서에 내린 수선의 발의 영상좌표(단위는 픽셀)로서 일반적으로 말하는 영상 중심점(image center)과는 다른 의미입니다. 예를 들어서, 카메라 조립과정에서 오차로 인해 렌즈와 이미지 센서가 수평이 어긋나면 주점과 영상중심은 다른 값을 가질 것입니다.


영상기하학에서는 단순한 이미지 센터보다는 principal point가 훨씬 중요하며  영상의 모든 기하학적 해석은 이 주점을 이용하여 이루어집니다.



C. 비대칭 계수(skew coefficient)


비대칭 계수 skew_c는 이미지 센서의 cell array의 y축이 기울어진 정도를 나타냅니다 (skew_c = tanα).

그림 5. 카메라 비대칭 계수


요즘 카메라들은 이러한 skew 에러가 거의 없기 때문에 카메라 모델에서 보통 비대칭 계수까지는 고려하지 않는다고 합니다 (즉, skew_c = 0).


이러한 카메라 내부 파라미터들은 공개된 캘리브레이션 툴 등을 이용하면 비교적 쉽게 계산할 수 있습니다. 공개 캘리브레이션 툴 소개 및 사용법은 본 포스팅 하단을 참조하시기 바랍니다.



3. 카메라 외부 파라미터(extrinsic parameters)


카메라 외부 파라미터는 카메라 좌표계와 월드 좌표계 사이의 변환 관계를 설명하는 파라미터로서, 두 좌표계 사이의 회전(rotation) 및 평행이동(translation) 변환으로 표현됩니다.


카메라 외부 파라미터는 카메라 고유의 파라미터가 아니기 때문에 카메라를 어떤 위치에 어떤 방향으로 설치했는지에 따라 달라지고 또한 월드 좌표계를 어떻게 정의했느냐에 따라서 달라집니다.


카메라 외부 파라미터를 구하기 위해서는 먼저 캘리브레이션 툴 등을 이용하여 카메라 고유의 내부 파라미터들을 구합니다. 다음으로는 미리 알고 있는 또는 샘플로 뽑은 3D월드좌표–2D영상좌표 매칭 쌍들을 이용하여 식(1)에서 변환행렬을 구하면 됩니다. OpenCV에 있는 solvePnP함수를 이용하면 이러한 계산을 손쉽게 할 수 있습니다.


☞ 카메라 외부 파라미터 캘리브레이션 및 영상 기하학에 대한 전반적인 내용에 대해서는 [영상처리] - Extrinsic Camera Calibration - 카메라의 위치 및 자세 파악 글을 참고하기 바랍니다.



4. 핀홀(pinhole) 카메라 모델


핀홀 카메라 모델은 아래 그림과 같이 하나의 바늘구멍(pinhole)을 통해 외부의 상이 이미지로 투영된다는 모델입니다. 이 때, 이 바늘구멍(pinhole)이 렌즈 중심에 해당되며 이곳에서 뒷면의 상이 맺히는 곳까지의 거리가 카메라 초점거리입니다 (광학적으로 렌즈의 중심을 투과하는 빛은 굴절되지 않고 그대로 직선으로 투과한다고 합니다).


그림 6. 핀홀 카메라 모델

(그림출처: http://en.wikipedia.org/wiki/Pinhole_camera_model)


영상처리 분야에서 영상에 대한 모든 기하학적 해석은 이 핀홀 카메라 모델을 바탕으로 이루어집니다. 하지만, 사실 핀홀 카메라 모델은 매우 이상적인 카메라 모델이며 실제로는 렌즈계의 특성에 따른 영상 왜곡 등도 같이 고려되어야 합니다. 영상 왜곡에 대한 내용은 [영상처리] - 카메라 왜곡보정을 참조해 주시기 바랍니다.



5. 캘리브레이션과 영상 해상도 그리고 자동초점조절(auto focusing)


카메라에 있는 오토 포커싱(auto focusing) 기능을 켜면 계속 초점거리가 바뀔 수 있기 때문에 캘리브레이션 목적에는 적합하지 않습니다. 카메라에 대해 캘리브레이션을 수행하고 캘리브레이션 결과를 다른 계산 목적에 사용하고자 한다면 오토 포커싱 기능은 꺼 놓고 사용하는게 좋습니다.


카메라에는 보통 영상 해상도를 QVGA(320x240), VGA(640x480), 960x480, ... 등 다양하게 설정할 수 있습니다. 그런데, 영상 해상도를 바꾸면 카메라 캘리브레이션 결과도 바뀌는 것을 확인 할 수 있을 것입니다. 카메라 내부 파라미터중 초점거리 fx, fy, 주점 cx, cy는 픽셀 단위를 사용하는데, 카메라의 물리적인 초점거리나 이미지 센서의 크기는 변하지 않지만 한 픽셀이 나타내는 물리적 크기가 변하기 때문입니다. 그래서 만일 영상해상도를 VGA로 놓고 캘리브레이션 한 결과과 QVGA로 놓고 캘리브레이션 한 결과를 비교해 보면 QVGA의 경우가 fx, fy, cx ,cy의 값이 1/2씩 줄어들게 됩니다. 반면에 렌즈왜곡계수(k1, k2, p1, p2)는 normalized 좌표계에서 수행되기 때문에 영상 해상도와 관계없이 항상 동일합니다. 따라서, 한 해상도에서만 캘리브레이션을 수행해도 다른 모든 해상도에 대한 파라미터 값을 구할 수 있게 됩니다. 렌즈왜곡계수는 동일하며, fx,fy,cx,cy만 영상 해상도에 비례해서 조정해 주면 됩니다.



6. 캘리브레이션 도구(tool) 및 사용법


A. Dark Cam Calibrator


최근에 직접 구현한 것인데 필요하시면 한번 사용해 보시기 바랍니다 ([개발한 것들] - 카메라 캘리브레이션 프로그램 (DarkCamCalibrator)). 카메라에서 직접 영상을 획득할 수 있으며 Fisheye 왜곡모델에 대한 캘리브레이션도 가능하다는 특징이 있습니다. OpenCV를 이용하여 구현한 것으로서 캘리브레이션 성능 자체는 OpenCV 성능과 같습니다.



B. GML C++ Camera Calibration Toolbox


가장 손쉽게 이용할 수 있는 공개 캘리브레이션 툴로는 GML C++ Camera Calibration Toolbox가 있습니다. 현재 0.73버전이 가장 최신버전이며 소소코드도 같이 공개되어 있습니다.


사이트 링크: http://graphics.cs.msu.ru/en/node/909

직접 다운로드: GML_CameraCalibrationInstall_0.73.exe



그림 7. GML 카메라 캘리브레이션 툴


기본적인 사용법은 캘리브레이션 패턴(chess board)이 인쇄된 종이를 다양한 위치 및 각도에서 카메라로 촬영한 후 영상으로 저장하고 위 툴(tool)로 캘리브레이션을 수행하면 됩니다. 자세한 사용법 및 최적의 영상획득 방법 등은 프로그램 자체에 포함된 설명문(Help)을 참조하시기 바랍니다.


이 툴의 특징은 위 그림과 같이 여러 개의 캘리브레이션 패턴을 동시에 사용하여 캘리브레이션을 수행할 수 있다는 점입니다. 툴의 설명문에 보면 2개 이상의 패턴을 사용했을 때 캘리브레이션 효과가 좀더 좋다고 나와 있습니다. 물론 1개의 패턴만을 사용하는 것도 가능합니다.


위 툴을 사용하여 캘리브레이션을 수행하면 다음과 같은 형태로 결과를 볼 수 있습니다.


그림 8. GML 카메라 캘리브레이션 툴 실행 예시


캘리브레이션 결과는 위 예와 같이 추정치 ± 추정오차(3*sigma) 형태로 출력되며 각각의 항목의 의미는 다음과 같습니다.

  • Focal length: fx = 3497.576, fy = 3501.038
  • Principal point: cx = 1058.429, cy = 797.136
  • Distortion: k1 = -0.041196, k2 = -0.203893, p1 = 0.006114, p2 = 0.002318 (k1,k2: radial distortion 계수, p1,p2: tangential distortion 계수)



C. Camera Calibration Toolbox for Matlab


아마도 카메라 캘리브레이션 분야에 있어서 가장 대표적인 툴로 생각됩니다. Matlab으로 구현되어 있으며 다소 사용법이 복잡하지만 캘리브레이션 과정의 세세한 부분을 직접 설정할 수 있으며 보다 정밀한 캘리브레이션이 가능합니다.


사이트 링크: http://www.vision.caltech.edu/bouguetj/calib_doc/


그림 9. Caltech 카메라 캘리브레이션 툴


위 사이트는 또한 카메라 캘리브레이션 분야에 있어서 가장 대표적인 사이트로서 캘리브레이션 툴 뿐만 아니라 캘리브레이션에 대한 전반적인 이론 및 정보가 잘 정리되어 있습니다. 캘리브레이션을 연구하는 (영어권) 사람들은 주로 이 사이트를 통해 필요한 정보를 얻는 것으로 알고 있습니다.



7. 캘리브레이션 결과가 달라지는 이유 (2015.5.12 추가)


댓글로 문의를 많이 주시는 내용인데 본문에 내용을 추가하는 것도 좋을 것 같아서 추가합니다.


카메라 캘리브레이션 결과가 달라지는 것은 먼저 카메라의 auto focus 기능이 켜져 있는지 확인해야 합니다. 물론 auto focus 기능이 꺼져 있음에도 불구하고 결과가 달라질 수 있지만 그 편차는 auto focus 기능이 켜져 있는 경우에 비해 훨씬 줄어들 것입니다. 하지만, auto focusing 여부와 관계없이 근본적으로 동일한 카메라에 대해 캘리브레이션 결과가 달라질 수 있는 이유는 몇 가지 원인이 있는데 적어보면 다음과 같습니다.

  • 캘리브레이션은 완벽한 핀홀 카메라 모델을 가정하고 파라미터를 찾지만 실제 카메라는 핀홀 카메라 모델이 아닐 수 있습니다.
  • 카메라 캘리브레이션 과정에 렌즈계 왜곡모델이 들어가는데, 일반적으로 사용되는 렌즈계 왜곡모델은 왜곡 특성을 저차의 다항함수로 근사하는 것이기 때문에 실제의 렌즈계 왜곡과는 차이가 발생할 수 있습니다.
  • 마지막으로 카메라 캘리브레이션은 어떤 방정식을 풀어서 딱 떨어지게 해를 찾는 것이 아니라 해에 대한 초기 추정치부터 시작해서 최적화 기법을 적용하여 반복적인 탐색 과정을 거쳐 근사적인 해를 찾는 것이기 때문에 매번 해가 달라질 수 있습니다.

결국 카메라의 내부 파라미터 자체는 고유값이지만 캘리브레이션 모델 자체가 근사적인 모델이기 때문에 사용한 이미지에 따라 최적 근사해가 달라질 수 있습니다.



8. 카메라 캘리브레이션 팁 (2015.5.12 추가)


카메라 캘리브레이션 팁도 간단하게 같이 적어봅니다. 카메라와 패턴과의 거리에 대해 문의를 많이 주시는데 패턴과의 거리는 최대한 가까울수록 좋습니다. 그 이유는 캘리브레이션 자체는 패턴과의 거리와 관계없지만 패턴과의 거리가 가까우면 영상에서 좀더 정밀하게 코너점의 위치를 찾을 수 있기 때문입니다. (경험적으로) 패턴 영상의 개수는 4개 이상이면 어느정도 캘리브레이션이 가능하지만 많을수록 좋으며 20장 이상 정도면 무난하다고 생각됩니다. 마지막으로 패턴 영상을 획득할 때에는 되도록 다양한 각도에서 영상을 획득하면 좋습니다.



관련 포스팅


by 다크 프로그래머

수학을 공부하는 방법

수학 이야기 2013. 1. 30. 16:01

수학을 공부하는 방법에는 크게 2가지가 있습니다.




1. 하나는, 문제 풀이법을 익히는 방법입니다.


이는 다양한 유형의 문제 풀이법을 익히고 숙달시켜서 궁극적으로는 높은 시험 점수를 얻기 위한 방법입니다. 개인에 따라 이 방법은 끊임없는 반복과 풀이 연습을 요구하기 때문에 수학공부에 많은 시간을 투자해야 하며 또한 가르치는 사람과 학생 본인의 강한 인내가 필요한 방법이기도 합니다.

일종의 문제를 푸는데 있어서 프로를 만들고자 하는 것이라 볼 수 있으며 현재 한국 교육의 현실이기도 합니다.


2. 다른 하나는 수학 자체를 공부하는 것입니다.


이건 어떻게 따로 설명하기가 힘든 것 같습니다. 그저 순수한 배움이 목적이거나 스스로의 필요에 의해서 또는 수학이 재밌어서 수학을 공부하는 것입니다. '어떻게' 보다는 '왜'가 중요하며 스스로 납득했다는 것이 중요합니다. 때로는 한 문제를 붙잡고 몇 시간씩 씨름을 하기도 하지만 문제를 풀고 나면 성취감을 느끼기도 합니다. 잘 알고 있는 문제를 몸에 익히기 위해서, 또는 실수를 최소화하기 위해 반복해서 풀기 보다는 새로운 문제, 재미있는 문제에 흥미를 느낍니다. 시간의 효율성 같은 건 모릅니다. 그저 재미있어서 풀고 배움이 좋아서 합니다.


어떤 방법이 좋은지는 개인에 따라 상황에 따라 달라질 수 있을 것입니다. 예전에는 제가 학교에 다닐 때에는 진짜 수학을 잘 한다는 사람들은 대부분 두번째 경우였습니다. 하지만 요즘에는 첫번째 방법이 거의 사회적 흐름이 된 것 같습니다.


며칠 전 한 라디오 방송에서 들은 말로 외국의 수학자가 이런 말을 했다고 합니다.

"한국에서는 수학 올림피아드 우승자는 나올 수 있어도 훌륭한 수학자는 나오기 힘들다."


현실에서는 평균적으로는 첫번째 방법이 나을지도 모르겠습니다. 하지만 그렇게 오랜 시간을 공부하고 대학까지 나왔지만 막상 본인 스스로 무언가를 풀어내야 될 상황이 되면 잘 해내지 못하는 경우가 많습니다.


나름 초반엔 수학에 흥미도 느끼고 재능이 있는 학생들조차 이러한 시스템 속에서 개성과 흥미를 잃어가고 있는 건 아닌지 걱정됩니다...


관련 포스팅: 

by 다크 프로그래머

'수학 이야기' 카테고리의 다른 글

각에도 부피가 있을까  (14) 2013.02.15
대분수의 나눗셈  (2) 2013.01.30
수학공식 핸드북 (cheat sheet)  (4) 2013.01.28