Extrinsic Camera Calibration - 카메라의 위치 및 자세 파악

영상처리 2014.01.29 16:22

그동안 카메라 영상 기하학에 관련된 글을 많이 올렸었는데, 이번 글은 그동안 올렸던 글들을 정리함과 동시에 마무리 단계로서 카메라의 외부 파라미터(extrinsic parameter)인 3차원 위치 및 자세(팬, 틸트 또는 pitch, roll, yaw)를 파악하는 방법을 정리해 보고자 합니다.


이 글에서 다룰 extrinsic camera calibration은 아래 그림과 같이 크기 및 형태를 미리 알고 있는 외부의 물체(마크)에 대한 영상을 분석하여 이 영상을 획득할 당시의 카메라의 3차원 위치(지면으로부터 높이 등) 및 3D 자세 정보(팬, 틸트 등)를 추출하는 것이 목적입니다.


<그림 1> 마크그림 출처: 3M Neo-CAPS



1. 관련 글


먼저, 그동안 올렸던 영상 기하학과 관련된 글들을 간략히 정리해 보면 다음과 같습니다.


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

-> 카메라 캘리브레이션에 대한 전반적인 내용 소개 (초점거리, 주점, 왜곡계수 등 내부 파라미터 설명 및 캘리브레이션 툴 소개)


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

-> 렌즈계의 영상왜곡 모델(수식) 및 보정 방법 소개


[영상 Geometry #1] 좌표계

[영상 Geometry #2] Homogeneous Coordinates

[영상 Geometry #3] 2D 변환 (Transformations)

[영상 Geometry #4] Homography 보완

[영상 Geometry #5] 3D 변환

[영상 Geometry #6] 이미지 투영(Imaging Geometry)

[영상 Geometry #7] Epipolar Geometry

->카메라 영상 기하학에 대한 전반적인 내용을 소개. #1 글에서는 영상기하학에서 사용하는 좌표계(월드 좌표계, 카메라 좌표계, 정규 이미지 좌표계, 픽셀 좌표계)의 개념 및 관계를 설명. #2: homogeneous 좌표 표현 소개. #3: 2D 이미지 상에서 물체의 변화를 모델링하기 위한 다양한 2D 변환 모델들을 소개. #4: 2D homography의 유효성을 판단하기 위한 팁 소개. #5: 3D 공간에서 물체의 변화를 모델링하기 위한 다양한 3D 변환 모델들을 소개. #6. 물체의 3D 공간좌표(월드좌표)가 어떤 과정을 거쳐서 2D 이미지 픽셀 좌표로 매핑되는지 설명. #7. essential matrix, fundamental matrix등 3차원 물체에 대한 카메라 영상과 영상 사이의 매핑 모델 소개


3D 좌표계 변환 방법 (예: 월드좌표계 - 카메라 좌표계)

-> 카메라의 3차원 위치 및 자세정보(팬,틸트)를 알고 있을 때, 3차원 월드좌표를 카메라 좌표로 변환시키는 변환 행렬을 구하는 방법 소개


solvePnP 함수 사용법과 Rodrigues 표현법

-> 3D월드좌표-2D이미지픽셀좌표 쌍들로부터 카메라의 3차원 위치 및 자세를 추출하는데 사용되는 함수인 opencv의 solvePnP 함수 사용법 예제 샘플코드


타겟 추적을 위한 카메라의 팬,틸트 제어

-> 추적하고자 하는 대상이 항상 카메라 영상 중심에 오도록 카메라의 팬, 틸트를 제어하기 위한 방법 및 수식 설명



2. 3D 공간좌표와 2D 영상좌표


위와 같이 그동안 영상 기하학(geometry)에 대한 여러 글들을 올렸지만 그 핵심은 결국 2D 영상을 3차원으로 해석하는데 있습니다.


그런데 주변에 보면 이미지를 3차원으로 해석하는 문제는 아예 딴세상의 영역으로 치부하고 막연한 두려움 또는 어려움을 느끼는 경우가 많은데 사실 알고보면 그렇게 어려운 수학이 필요한 것은 아닙니다. 카메라 좌표계 입장에서만 본다면 우리가 중학교때 배우는 도형의 닮음비 정도만 이용해도 충분히 수식 도출이 가능합니다.


월드좌표계는 무시하고 카메라를 중심으로 3차원 좌표계(카메라의 광학축 방향이 Z축, 오른쪽이 X축, 아래쪽이 Y축)를 설정했을 때, 외부의 한점 P(X,Y,Z)에 대한 영상좌표를 구하는 문제를 생각해 보겠습니다.


<그림 2>


그러면 P(X,Y,Z)는 카메라로부터 (수직방향으로) Z만큼 떨어진 거리에 있는 점이므로 카메라로부터의 거리가 1인 가상의 정규 이미지 평면에서의 좌표는 삼각형의 닯음비를 이용하면 P'(X/Z,Y/Z,1)이 됨을 쉽게 알수 있습니다. 그런데 실제 카메라 영상은 초점거리 f만큼 떨어진 이미지 평면에 투사되므로 P에 대응되는 이미지 좌표는 P''(f*X/Z, f*Y/Z, f)가 되고 이를 픽셀좌표계로 변환하면 우리가 원하는 최종 영상좌표를 얻을 수 있습니다.


좀더 구체적으로 들어가 보면, 카메라의 초점거리는 X축 방향은 fx, Y축 방향은 fy, 이렇게 서로 다르게 측정하여 사용하기 때문에 실제로는 P''을 (fx*X/Z, fy*Y/Z)로 계산하고, 이를 픽셀좌표계(이미지의 좌상단이 원점)에 맞추어 주면 영상중심을 (cx, cy)라 했을 때 x = fx*X/Z + cx, y = fy*Y/Z + cy가 최종 영상좌표가 됩니다(카메라 좌표계의 좌표축 방향을 어떻게 잡느냐에 따라서 변환 수식은 조금씩 달라질 수 있습니다).


역으로 2D 영상좌표 p(x, y)에 대응하는 3D 공간좌표를 구하고자 할 때에는 먼저 (x-cx, y-cy)로 영상좌표 원점을 영상중심으로 옮긴 후 Z거리가 1인 정규이미지 평면에서의 좌표 ((x-cx)/fx, (y-cy)/fy)로 바꿉니다. 다음으로 실제 물체와의 거리 Z를 반영해 주면 ((x-cx)/fx*Z, (y-cy)/fy*Z, Z)가 구하고자 하는 3차원 공간좌표가 됩니다(물론 거리 Z를 모른다면 3차원 좌표는 유일하게 결정되지 않습니다).


이상으로 설명한 2D-3D 변환 모델은 정말 이렇게 단순해? 할 수도 있겠지만 실제 카메라 영상에서 그대로 성립하는 관계입니다. 물론 보다 정확한 변환을 위해서는 렌즈계 왜곡모델이 반영되어야 하겠지만 영상왜곡이 심하지 않은 경우에는 위 변환모델을 그대로 사용해도 무방합니다.



3. 카메라의 3D 위치 및 자세 파악


원래의 주제로 돌아가서 카메라 영상을 보고 이 영상을 획득할 당시의 카메라의 3차원 위치 및 자세정보(팬, 틸트, ...)를 추출하는 문제를 살펴보겠습니다. 단, 실제 계산은 opencv의 solvePnP 함수를 활용하는 것으로 하겠습니다(solvePnP 함수에 대한 예제코드는 solvePnP 함수 사용법 글 참조).


☞ 이미 예전에 solvePnP 함수 사용법에 대한 글을 올린 바가 있지만 해당 예제코드에는 자세정보를 추출하는 과정에 대한 내용이 없고 또한 수식에 대한 배경 설명이 없기 때문에 저조차도 해당 기능이 필요할 때마다 한참을 생각해야 겨우 정리가 되는 경우가 많았습니다. 그래서 여기에 다시 한번 관련 내용을 정리해 놓고 필요할 때마다 참조하고자 합니다.


먼저, 영상으로부터 카메라의 위치 및 자세를 계산하려면 다음과 같은 전제 조건이 필요합니다.

  • 해당 카메라에 대한 내부 파라미터(intrinsic parameters) 및 왜곡계수을 알고 있어야 함: fx, fy, cx, cy, k1, k2, p1, p2
  • 물체에 대한 최소 4개 이상의 3D 월드좌표와 이에 대응되는 2D 영상좌표 쌍


예를 들어, 아래 그림과 같이 한변의 길이가 1인 사각형 마크를 바닥에 놓고 카메라로 영상을 획득했을 때 각각의 사각형 꼭지점들에 대한 영상좌표를 구한 후, 사각형 꼭지점들의 3D 월드좌표와 2D 영상좌표 쌍들을 solvePnP 함수에 넣어주면 카메라의 위치 및 자세정보가 나옵니다.


<그림 3>


☞ 위 그림 3에서는 사각형 마크의 월드좌표를 (0,0,0), (1,0,0), (0,1,0), (1,1,0)로 설정해 주었지만 만일 마크를 기준으로 월드좌표계를 설정하지 않고 별도의 월드좌표계를 설정(예를 들어 방의 한쪽 모서리를 원점으로 설정)하고자 할 때에는 해당 좌표계를 기준으로 한 좌표를 마크의 월드좌표로 입력해 주면 됩니다. 그러면 solvePnP 함수에서는 설정한 월드좌표계를 기준으로 한 카메라의 위치 및 자세정보를 반환하게 됩니다.


solvePnP 함수는 기본적으로 3D 월드좌표를 3D 카메라좌표로 변환시키는 변환정보(rvec, tvec)을 반환하며 이로부터 회전변환 R과 평행이동 T를 아래와 같이 계산할 수 있습니다..

Mat rvec, tvec; // rotation & translation vectors

solvePnP(objectPoints, imagePoints, A, distCoeffs, rvec, tvec);

Mat R, T;

Rodrigues(rvec, R);

T = tvec;


☞ opencv의 solvePnP 함수가 반환하는 rvec은 회전변환에 대한 Rodrigues 표현이기 때문에 실제 회전변환 행렬 R은 Rodrigues() 함수를 통해 추출해야 합니다. Rodrigues 회전변환 표현법에 대해서는 solvePnP 함수 사용법과 Rodrigues 표현법 글을 참조하기 바랍니다.


즉, 3차원 공간상의 한점 P에 대한 월드좌표를 Pw = [xw, yw, zw]T, 카메라 좌표계에서 봤을 때의 좌표를 Pc = [xc, yc, zc]T, solvePnP 함수가 반환하는 회전변환 행렬을 R, 평행이동 벡터를 T라고 했을 때 다음과 같은 변환 관계식이 성립합니다.


 --- (1)


이 때, 카메라의 3D 위치(월드좌표)는 카메라 좌표계의 원점에 대응하는 월드좌표이므로 다음과 같이 계산됩니다.


 --- (2)


다음으로 카메라의 3D 자세정보를 계산해 보겠습니다.


먼저, 카메라의 팬(pan)과 틸트(tilt)는 카메라의 광학축에 대한 월드좌표를 구하면 됩니다. 자세정보를 구하는데 있어서 평행이동은 관계가 없는 요소이기 때문에 회전변환만을 고려하여 카메라 광학축 벡터 Zc = [0, 0, 1]T에 대한 월드좌표 Zw를 다음과 같이 계산합니다.


 --- (3)


이렇게 계산된 광학축에 대한 월드좌표를 Zw = [zx, zy, zz]T라 하면 카메라의 팬, 틸트는 다음과 같이 계산됩니다 (단, 팬, 틸트는3D 좌표계 변환 방법 (예: 월드좌표계 - 카메라 좌표계) 글에 설명된 정의를 따른다고 가정).


 --- (4)


pitch, roll, yaw 관점에서 보면 계산된 틸트(tilt)는 pitch, 팬(pan)은 yaw에 해당합니다.


다음으로, 카메라의 roll 각은 카메라 좌표계의 X축 벡터 Xc = [1, 0, 0]T에 대한 월드좌표 벡터 Xw = [xx, xy, xz]T와 월드좌표계의 X축을 Z축을 중심으로 θpan만큼 회전시킨 Xpan 사이의 회전각으로 계산됩니다 (단, roll은 카메라 광학축을 기존으로 한 회전각으로서, 카메라와 같은 방향을 바라볼 때 반시계 방향이 + 방향)


 --- (5)


단, sign() 함수는 () 안의 값이 양수면 1, 음수면 -1인 부호함수.


이상과 같이 어떤 물체에 대한 월드좌표-영상좌표 대응쌍을 4개만 알면 카메라에 대한 모든 위치 및 3D 자세정보를 파악할 수 있습니다.


이상의 내용을 코드로 정리하면 다음과 같습니다.

// matching pairs

vector<Point3f> objectPoints; // 3d world coordinates

vector<Point2f> imagePoints; // 2d image coordinates


// camera parameters

double m[] = {fx, 0, cx, 0, fy, cy, 0, 0, 1}; // intrinsic parameters

Mat A(3, 3, CV_64FC1, m); // camera matrix


double d[] = {k1, k2, p1, p2}; // k1,k2: radial distortion, p1,p2: tangential distortion

Mat distCoeffs(4, 1, CV_64FC1, d);


// estimate camera pose

Mat rvec, tvec; // rotation & translation

solvePnP(objectPoints, imagePoints, A, distCoeffs, rvec, tvec);


// extract rotation matrix

Mat R;

Rodrigues(rvec, R);

Mat R_inv = R.inv();


// camera position (X,Y,Z)

Mat Cam_pos = -R_inv*tvec;

double* p = (double *)Cam_pos.data;

X = p[0];

Y = p[1];

Z = p[2];


// pan(yaw) & tilt(pitch)

double unit_z[] = {0,0,1};

Mat Zc(3, 1, CV_64FC1, unit_z);

Mat Zw = R_inv*Zc; // world coordinate of optical axis

double* zw = (double *)Zw.data;


pan = atan2(zw[1], zw[0]) - CV_PI/2;

tilt = atan2(zw[2], sqrt(zw[0]*zw[0]+zw[1]*zw[1]));


// roll

double unit_x[] = {1,0,0};

Mat Xc(3, 1, CV_64FC1, unit_x);

Mat Xw = R_inv*Xc; // world coordinate of camera X axis

double* xw = (double *)Xw.data;

double xpan[] = {cos(pan), sin(pan), 0};


roll = acos(xw[0]*xpan[0] + xw[1]*xpan[1] + xw[2]*xpan[2]); // inner product

if(xw[2]<0) roll = -roll;



4. 참고사항: 호모그래피(Homography) (2014.4.22일 수정)


3차원 공간상에 한 평면형(planar) 물체가 있고 이 물체를 서로다른 두 위치 A, B에서 카메라로 찍은 두 영상이 있습니다. 이 때, 이 물체 상의 점 P를 A 영상 위치에서 바라본 3차원 카메라 좌표 X1과 B 영상 위치에서 바라본 카메라 좌표 X2 사이에는 어떤 선형변환관계 H가 성립하는데, 이 변환관계를 호모그래피(homography)라 부릅니다 (카메라 좌표계의 정의에 대해서는 [영상 Geometry #1] 좌표계 글 참조).


 --- (6)


이 때, 점 P를 A 카메라 위치에서 정규 이미지 평면에 투영시킨 이미지 좌표를 x1, B 위치에서 투영시킨 좌표를 x2, A 위치에서의 P의 depth를 d1, B 위치에서의 depth를 d2라 하면 X1 = d1x1, X2 = d2x2이므로 두 이미지 좌표 사이에도 다음과 같이 동일한 호모그래피 관계식이 성립합니다 (단, x1, x2는 (u, v, 1) 등과 같은 homogeneous 좌표 표현).


 --- (7)


단, ∼는 스케일(scale)을 무시했을 때 동일하다는 의미입니다 (equality up to scale).


즉, 호모그래피(homography)는 평면형(palanar) 물체에 대한 3D 카메라 좌표들 사이, 또는 2D 이미지 좌표들 사이에 성립하는 매핑관계 혹은 변환관계를 지칭하는 용어로서 보통 4개의 매칭쌍이 있으면 두 영상 사이의 호모그래피를 결정할 수 있습니다.


호모그래피(homography)에서 중요한 전제조건은 물체가 체스판 등과 같은 평면형(planar) 물체여야 한다는 점입니다. 만일 대상 물체가 주사위 등과 같이 3차원의 부피를 갖는 입체형 물체라면 이 물체에 대한 영상좌표들 사이에는 호모그래피(homography)가 성립하지 않습니다. 이러한 경우 즉, 평면형 물체가 아닌 경우의 영상좌표들 사이에는 호모그래피(homography) 대신 fundamental matrix나 essential matrix를 이용해야 합니다.


정리해 보면, '호모그래피(homography), fundamental matrix, essential matrix는 모두 2D 이미지 좌표 또는 3D 카메라 좌표 사이의 변환관계를 나타내는 용어이다. 단, 호모그래피는 물체가 평면형 물체일 경우에만 성립하고 일반적인 경우에는 fundamental matrix나 essential matrix를 사용해야 한다' 입니다.


☞ 기존 내용에서 호모그래피의 정의 부분에 오류가 있어서 4.22일자로 내용을 수정하였습니다.



by 다크 프로그래머


  • 이전 댓글 더보기
  • kamchol 2017.01.24 15:42 신고 ADDR 수정/삭제 답글

    안녕하세요 다크님 항상 다크님 블로그 다양한 비전을 공부 하고 있습니다. 감사합니다

    해당 글을 읽다 보니 궁금한점이 있는데요. 만약 카메라의 내부 파라미터를 모르고 제가

    카메라를 설치한 높이와 틸트각도를 알고 있다면. 그리고 해당 획득한 영상에서 기준 물체의 높이와

    그외 2개 정도의 물체 크기를 측정값을 알려주고 캘리브레이션을 진행 했다면 이것은 내부 파라미터

    구하기 위한 과정인것인가요?

    물체를 추척하기전 해당 과정을 통해 캘리브레이션을 맞춘다는것은 내부파라미터를 구하고, 이것을

    통해 2D 픽셀 정보 값을 정확하게 유추한다고 해석해도 되는것인가요?

    • BlogIcon 다크pgmr 2017.01.24 17:58 신고 수정/삭제

      네.. 자세한 것은 모르겠지만 그렇게 생각됩니다.

    • kamchol 2017.01.25 10:10 신고 수정/삭제

      감사합니다 !!

  • suljim 2017.01.31 18:02 신고 ADDR 수정/삭제 답글

    다크님 안녕하세요 졸업작품을 준비하면서 구글링 하다보면 항상 보이셔서 많이 도움 받고 있었습니다ㅎㅎ 이 분야에 너무 지식이 없어서 한 가지만 여쭤 보겠습니다ㅠㅠ
    저희가 만드는 작품이 피규어를 이용하는 것인데요. 피규어 여러 개를 임의로 배치한 후, 위에서 사진 또는 영상을 찍어 각 피규어들의 (x,y)좌표 값을 알고자 하는데 이런 기능이 open cv로 가능 할까요??

    • BlogIcon 다크pgmr 2017.02.01 07:46 신고 수정/삭제

      가능하리라 생각합니다만 구체적인 문제를 보기 전에는 가부를 말하긴 힘듭니다. 제약 조건 등에 따라서 문제가 달라질 수 있으니 가능하면 문제를 단순화시키는 것이 중요하겠죠.. http://darkpgmr.tistory.com/153 글의 내용이 관련이 될지 모르겠습니다.

  • 글적글적 2017.02.10 17:34 신고 ADDR 수정/삭제 답글

    안녕하세요 다크님~~ 항상 공부하며 많이 배우고있습니다. 햇갈리는 부분이 있어서요~~
    Cam_pos가 extrinsic에서 translation을 의미하는건가요??

    • BlogIcon 다크pgmr 2017.02.11 08:30 신고 수정/삭제

      그렇지 않습니다. Cam_pos는 카메라의 월드좌표를 의미합니다. 카메라의 extrinsic 자세는 [R|t]로 표현하는데 R은 rotation 파트, t는 translation 파트입니다. 여기서 t를 카메라의 월드좌표와 같은 것이라고 오해하는 경우가 많은데 그렇지 않습니다. 본문의 식(1), 식(2)에 설명하였듯이 [R|t]는 '카메라좌표 = R*월드좌표 + t'의 관계식을 만족하는 값이고, 카메라의 월드좌표는 -R^-1t로 계산됩니다.

  • 나그네 2017.05.15 20:03 신고 ADDR 수정/삭제 답글

    안녕하세요 잘보고 갑니다. 질문이 있어 글남깁니다.
    RGB_D 카메라가 어느 로봇에 위치해 있습니다. 로봇은 평면위를 움직입니다.
    이때, 카메라 extrinsic parameter를 구할려고 하는데, 제가 한 방법은 평면에 대한 정보(이미지상에서)를 직접 줘서 PCA를 통해 평면과 카메라의 R|t 를 구했습니다.
    하지만 이를 자동으로 하고자 하는데, 딱히 아이디어 떠오르지 않네요
    혹시 이와 관련한 아이디어 혹은 키워드 등을 알 수 있을까요?

    • BlogIcon 다크pgmr 2017.05.15 23:35 신고 수정/삭제

      SLAM 문제로 풀거나, 인위적인 표식을 이용하거나, DB를 만들어 놓고 매칭을 해야 할 것 같은데요.. 저도 딱히 아이디어는 없습니다.

  • mp 2017.05.19 11:03 신고 ADDR 수정/삭제 답글

    다크님 안녕하세요. 갓 대학원에 진학하여 영상쪽 공부를 하고 있는 학생입니다.
    요즘 캘리브레이션쪽 과제를 하여서 다크님 블로그를 보면서 많이 공부하고 있습니다.
    공부하다가 궁금증이 생겨서 질문 하나 하려고 글을 남깁니다.
    제가 지금 하고자 하는 과제는 visual tracking을 하고 난 후 최종 tracking된 물체의 이미지 좌표를 얻어와서 3d 좌표로 변환하는 일을 하고 있습니다. (wld좌표에서 img좌표로 옮기는 작업도 하고 있습니다.)
    블로그와 책등을 보며 공부한 결과 해야될 캘리브이션 순서가
    1. GML을 이용하여 intrinsic parameter matrix 를 구하기. (distortion도 반영)
    2. solvePnP 함수를 이용하여 extrinsic parameter (rvec, tvec)을 구하기.
    3. projectPoints를 이용하여 3d >> 2D 좌표 옮기기.
    이렇게 하는 것을 생각하고 있고, 실제 카메라로 실험을 해보니 약 2pixel정도의 오차를 가지고 되는것을 알 수 있었습니다.

    여기서 제가 궁금한점은 2가지 입니다.
    1. 처음 이론상 좌표값을 보면 imgpoint = A * [R|T] * wldpoint 인데, A는 처음 과정에서 알수 있는데 [R|T]를 직접 구할수는 없는건가요?? [R|T]는 3X4 matrix 가 나와야 할것 같은데 rvec, tvec를 모두 출력해봐도 3X1 matrix가 나오더라고요. 이렇게 하고 싶은 이유가 projectpoints 함수를 사용하지 않고, matrix를 wld2img 이런식으로 만들어놓고 자유롭게 사용하고 싶어서요.

    2. 그리고 궁금한점은 4개의 좌표쌍을 알고 있으니 총 8개의 좌표값들을 알고 있으므로
    imgpoint = A * [R|T] * wldpoint 에서 A*[R|T]를 직접 구할 수 있는 것 아닌가요?
    A*[R|T] 가 3X3 matrix에 총 8개의 변수가 들어가서 8개의 좌표값만으로도 구할 수 있는 것 같은데 왜 intrinsic parameter를 먼저 구하고, extrinsic parameter를 구해서 좌표값을 옮긴다던지 하는 일을 하는건지 알고 싶습니다. 개인적으로 고민해보면 방정식 형태로 정확한 값이 나오는게 아니라 오차를 줄여가며 대입해서 계산을 하기 때문에 정확한 matrix값이 나오지 않을수도 있겠다 라는 생각을 가지고는 있는데 혹시 여기에 특별한 이유가 있거나 제가 잘못 생각하고 있는것인지 알고 싶습니다.

    질문이 긴데 혹시 가능하시다면 답변 부탁드리겠습니다. 감사합니다.

    • BlogIcon 다크pgmr 2017.05.19 13:24 신고 수정/삭제

      안녕하세요. 먼저 질문 1은 opencv의 Rodrigues 함수를 이용하면 rvec을 3x3 rotation matrix로 변환할 수 있습니다 (http://darkpgmr.tistory.com/99) 글 참조.
      그리고 질문 2는 A*[R|t] 를 한꺼번에 구하는 것은 물론 가능합니다. 하지만 보다 정확한 추정을 위해서는 많은 포인트가 필요하고 또한 intrinsic은 변하는 값이 아니기 때문에 한번 잘 구해놓고 사용하는 것이 효과적이라 생각됩니다. 실제 intrinsic 캘리브레이션을 수행하는 도중에도 알고리즘 내부적으로는 A, R, t를 모두 구해서 계산합니다.

  • Totti 2017.06.06 00:14 신고 ADDR 수정/삭제 답글

    안녕하세요 다크 프로그래머님 항상 많은 도움을 받고 있습니다. 질문이 있는데요. 움직이는 CCTV의 경우 실시간으로 카메라 틸트를 계산할 수 있을까요?

    • BlogIcon 다크pgmr 2017.06.06 11:25 신고 수정/삭제

      상황에 따라 다르기 때문에 가능할 수도 있고 가능하지 않을수도 있습니다. 그리고 가능하다 할지라도 얼마나 정확한가 그리고 항상 계산이 가능한가는 또 다른 문제이구요.. 어쨌든 문제라는 것이 대부분 흑이다 백이다 하기는 힘듭니다.. 그렇기 때문에 어떤 문제를 판단하기 위해서는 최대한 구체적인 정보가 필요합니다.

  • 조성국 2017.08.25 12:17 신고 ADDR 수정/삭제 답글

    좋은 글 일단 먼저 감사드립니다. 예제에서 R,T로 P를 변환하는 식을 보여주셨는데요, 그렇다면 P로부터 R과 T를 변환해 낼 수도 있을까요? 현재 하고자 하는건 R의 X축 각도를 약간 변경 시키고자 합니다.

    • BlogIcon 다크pgmr 2017.08.25 14:46 신고 수정/삭제

      질문의 의도는 제가 잘 이해는 못했는데요, 어쨌든 회전변환을 직관적으로 조절하고자 할 때에는 rodrigue를 이용하면 좀더 편할 것 같습니다. rodrigue는 http://darkpgmr.tistory.com/99 글을 참조하시면 됩니다.

  • Hskim 2017.08.25 18:14 신고 ADDR 수정/삭제 답글

    안녕하세요. 블로그 내용 항상 감사히 잘보고 있습니다. 질문이 있어서 처음 댓글을 쓰게 되었습니다.
    제가 지금 하는 프로젝트는 solvepnp이용해서 카메라 위치를 알아내고 그 값들을 응용하려고 하고있습니다.
    가장 큰 문제는 카메라의 위치를 얻어내는 정밀도가 생각보다 너무 안나와서 고민하고 있습니다.
    오차가 적으면 0.5mm에서 많게는 2mm까지도 납니다.(최종 결과물의 목표 +-0.5mm)
    사용하고 있는 카메라는 바슬러 2048x2048입니다.
    테스트는 제가 v-rep이라는 로봇 시뮬레이션 프로그램으로 카메라 위치를 설정하고, 체스판을 가상으로 만들어서 테스트 해보았습니다.
    vrep에서 카메라로 촬영을 하고 opencv 캘리브레이션 과정을 거치고 solvepnp로 체스판 기준으로 해서 카메라의 위치를 계산하였습니다.
    이 카메라 위치에서 오차가 발생하고 최종 결과물의 오차에 영향을 주고 있습니다.
    질문1. 카메라 파라메터가 완벽히 이상적이다 라고 하면 그이후 solvepnp에서 오차는 발생할 가능성은 없어 보이시나요?

    질문2. (실제, 가상)카메라 캘리브레이션 과정을 거치면 카메라 파라메터 들이 영상 데이터에 따라서 많이 달라지는데요. 이 파라미터들이 solvepnp에서 나오는 카메라 위치에도 많은 영향을 주는거같습니다. 보다 정확한 카메라 파라메터 구하는 방법이 있을까요?

    긴글 읽어주셔서 감사합니다. 프로젝트를 하는데 주위에 영상을 전문적으로 하는 분들이 없고 마감시한은 가까워 지고있어서 답답한 나머지..글을 남기게 되었습니다. 다시 한번 감사합니다.

    • BlogIcon 다크pgmr 2017.08.28 15:47 신고 수정/삭제

      안녕하세요. 오차가 mm 단위라면 이미 꽤나 정밀하게 잘 나오는 것이라 생각되는데요.. 영상으로 그 이하까지 정밀하게 측정이 될지는 저도 잘 모르겠습니다. 일단 solvePnP에서 오차가 나올 부분은 없다고 생각됩니다. 그리고 카메라 파라미터를 정밀하게 측정하는 방법에 대해서는 저도 딱히 아는 바가 없습니다.. 별 도움이 못되었습니다.

  • 조성국 2017.08.29 23:08 신고 ADDR 수정/삭제 답글

    수렴형 카메라의 rectify를 연구하는데요.. 도움이 필요하여 메일 드렸는데 못보신 것 같습니다. ㅠ 혹시 가능하시면 메일 회신 요청드립니다. ㅠㅠ kookiedev@gmail.com 입니다. 감사합니다.

    • BlogIcon 다크pgmr 2017.08.30 11:55 신고 수정/삭제

      네 확인하였습니다. 블로그 소개글에도 밝혔듯이 구체적인 문제에 있어서는 도움을 드리기 힘든 점을 양해해 주시기 바랍니다.

  • jongmin 2017.11.21 16:00 신고 ADDR 수정/삭제 답글

    아마 제가 지속적으로 사소한 실수를 하고 있는 것 같은데, 질문 드립니다.
    제가 지금 코너 사이즈는 4*5, 한 변이 1cm인 체스판을 촬영하고 영상은 640 * 480 크기로 촬영하는데, 눈으로 대충 봐도 45도 이상 기울어진 걸 알 수 있을만한 영상에서 1도, 3도 기울었다는 식의 결과가 나옵니다.
    거의 정방향에서 보인 영상도 비슷한 결과값이 나옵니다.

    solvePnP 함수를 쓸 때 필요한 제약조건같은게 있나요??
    체스판이 너무 작게 보이면 안된다고 해서 상당히 가까이에서 찍었는데도 별다른 변화가 없습니다.

    • BlogIcon 다크pgmr 2017.11.21 16:43 신고 수정/삭제

      따로 그런 건 없습니다. 계산 과정의 오류는 다른 사람이 알기 어렵습니다. 그래도 돌다리도 두드린다고 생각나는 것들을 적어보면 혹시 단위의 문제는 아닌지 체크해 보시면 좋을 것 같습니다. 길이의 단위는 meter든 centimeter든 일관되게만 사용하면 됩니다. 혹은 radian을 degree로 해석한 것은 아닌지, 캘리브레이션이 정상적으로 된 것인지 등도 체크해봄직합니다. 디버깅은 자신이 할수 밖에 없는 것이라서 하나씩 원인을 찾아볼 수 밖에 없다고 생각합니다.

    • jongmin 2017.11.22 13:10 신고 수정/삭제

      음... 우선, 영상의 해상도가 높지 않은 환경에서 체스판이 너무 작게 보이면 안된다고 합니다.
      라디안 각의 문제도 아니고, 체스판을 꽤 크게 찍었는데도 안되는 중인데, 혹시 원인 찾아내면 공유 드리겠습니다.
      각도를 크게 틀어도 숫자가 계속 비슷하게만 나오네요 ㅠ

      혹시 다크프로그래머님 OpenCV 3.대 버전으로 써보신 적 있나요??

  • 감사합니다 2017.11.21 17:34 신고 ADDR 수정/삭제 답글

    감사히 잘 보고있습니다.
    월드 좌표를 정의할때 네점에대해 정의하는 값에 따라 roll, pitch, yaw도 다르게 나오나요?
    예를 들어 네 점을
    0,0,0 1,0,0
    0,1,0 1,1,0
    이렇게 정의한거랑 중앙을 0,0,0으로 정의하여 네점을 아래와 같이
    -0.5, -0.5, 0 0.5, -0.5, 0
    -0.5, 0.5, 0 0.5, 0.5, 0

    정의한거라 roll, pitch, yaw가 다르게 나올까요? 글에 따르면 월드 좌표기준으로 나온다고 하였으니 다르게 나올것 같기도 하고, 한평면에 있기에 전후가 같은값이 나올듯도 한데요.

    • BlogIcon 다크pgmr 2017.11.21 19:04 신고 수정/삭제

      월드좌표를 평행이동시키면 카메라의 위치는 같이 평행이동되겠지만 방향(roll, pitch,
      yaw)은 변함없이 같게 나올 것으로 생각됩니다.

  • BlogIcon DRAGONITE 2017.11.29 14:29 신고 ADDR 수정/삭제 답글

    안녕하세요. 좋은 글 감사합니다. 제가 구현을 직접 해보는 중인데, position 이 잘 나오지 않네요. 어느 부분이 틀렸는지 조언 부탁드리뎌 될까요?

    먼저 4개의 대칭쌍에 대해서 픽셀좌표와 3D데이터를 받았습니다
    그리고 캘리브레이션 행렬을 구하고, 대입하였습니다. 그리고 아래는 주어진 함수를 사용하여 구하였습니다.
    여기서 헷갈리는 부분이 disCoeffs 행렬은 모두 0 값으로 넣었는데, 이 값은 어떤 값을 넣어야 하나요?
    position(X, Y, Z) 값이 3D 데이터의 원점으로부터의 거리가 맞는 것인가요?

    • BlogIcon 다크pgmr 2017.11.29 15:34 신고 수정/삭제

      disCoeffs에는 카메라의 왜곡이 심하지 않은 경우에는 모두 0을 넣어줘도 큰 문제는 업습니다. 카메라의 영상왜곡이 심한 경우(광각 카메라)에는 왜곡계수 k1, k2, p1, p2를 넣어주면 됩니다. 카메라의 왜곡계수는 카메라 캘리브레이션 툴(tool)을 이용하면 손쉽게 구할 수 있습니다. 카메라 캘리브레이션에 대해서는 http://darkpgmr.tistory.com/32 글을 참조하세요.
      position X, Y, Z는 우리가 설정한 3D 좌표계에서의 카메라의 좌표(위치)입니다. 보통 월드좌표라고 부릅니다.

  • 나사 2017.12.21 15:09 신고 ADDR 수정/삭제 답글

    <그림2>의 P''과 투영된 2차원좌표 p와의 차이는 뭔가요?
    앞서 카메라좌표계의 글에서 투영된 이미지는 p로 표현한다했는데
    homogeneous의 차이같은데 표현식이 P''인 이유가 있나요?

    • BlogIcon 다크pgmr 2017.12.21 15:41 신고 수정/삭제

      블로그 글이다 보니.. 글들 사이의 기호 표현 등은 조금씩 차이가 있을 수 있습니다. 글에서 대문자 P로 쓴 것은 3차원 공간좌표임을 나타낸 것이고 소문자 p로 쓴 것은 2차원 영상좌표임을 구분한 것입니다.

  • BlogIcon DRAGONITE 2018.01.02 17:10 신고 ADDR 수정/삭제 답글

    안녕하세요. 다크님! 공부 중에 궁금한 것이 생겨 질문 남깁니다.
    2. 3D 공간좌표와 2D 영상 좌표 부분에서, 3D to 2D 로 가기 위해서, r, t를 구한 후, Proejction 을 성공하였습니다. 이제 역으로 2D to 3D 를 시도해보려고 합니다. 이 때, 거리 Z를 모르기에 3차원 좌표가 유일하지 않게게 되는데, 이 때 Z값을 위에서 3d to 2d 로 가기 위한 변수를 사용한다고 하더라도 알 수 없는 것 인가요?

    x = fx*X/Z + cx, y=fy*Y/Z +cy; 식에서 X, Y, Z를 미지수로 두면 방정식이 2개 뿐이라서... 알 수 없는게 맞나요?

    • BlogIcon 다크pgmr 2018.01.02 18:37 신고 수정/삭제

      네, 어떤 식이든 부가적 정보(거리, 사물의 크기정보 등) 없이 2D -> 3D는 구할 수 없습니다.

    • BlogIcon DRAGONITE 2018.01.03 10:03 신고 수정/삭제

      감사합니다! 거리에관한 것은 Z 값에 대입하면 되고, 사물의 크기 정보에 관한 것은 높이나 넓이 픽셀과 초점거리와 비례하는 식을 세워서 풀이 하는 것이 맞나요?

    • BlogIcon 다크pgmr 2018.01.03 13:14 신고 수정/삭제

      네, 그렇게 하시면 됩니다.

    • BlogIcon DRAGONITE 2018.01.03 13:59 신고 수정/삭제

      정말 감사드립니다. 새해 복 많이 받으세요!!!

  • 333 2018.02.01 16:54 신고 ADDR 수정/삭제 답글

    (3)식에서 (zx, zy, zz)만 전치되어있는데 이렇게 표기하려면
    '카메라 광학축 벡터 Zc = (0, 0, 1)에 대한 월드좌표 Zw를 다음과 같이 계산합니다.'
    에 적혀있는 Zc Zw나 식(3)의 Zc Zw도 전치표현으로 적어줘야되는거 아닌가요..?
    뭔가 헷갈려서 질문드립니다@_@;..

    • BlogIcon 다크pgmr 2018.02.02 10:17 신고 수정/삭제

      좋은 지적 감사합니다 ^^. 사실 편하게 때우려고 좌표는 (), 벡터는 []로 구분을 하긴 했었는데... [] 형태로 일관되게 표현하는게 좋을 것 같습니다. 말씀하신 의견대로 수정했습니다.

  • Jinger 2018.03.07 14:02 신고 ADDR 수정/삭제 답글

    fisheye의 경우에도 제대로 된 계산이 나오는지요? 넣어줄때 다운되는 경우도 있고 부정확한 경우도 있는거 같은데 혹시 추가 작업을 해줘야 하는지해서요,..!

    • BlogIcon 다크pgmr 2018.03.07 15:40 신고 수정/삭제

      카메라의 파라미터만 정확하게 입력해 주면 관계없이 잘 계산될 것으로 생각합니다만.. 만일 결과가 잘 안나온다면 카메라 캘리브레이션을 다시 해 보시면 어떨까 싶습니다.

  • 이유식 2018.03.29 21:56 신고 ADDR 수정/삭제 답글

    다크님 안녕하세요. 글 보고 질문사항이 있어서 글 남기게 되었습니다.
    만약 영상 촬영 카메라의 틸트, 높이등을 계산하는 과정에서 어떤 모형을 미리 놓는 게 아니라 임의의 특징점을 잡아서 카메라를 전/측면으로 이동시키며 계산할 수 있을까요?

    • BlogIcon 다크pgmr 2018.03.29 22:39 신고 수정/삭제

      글쎄요. 저도 잘 모르겠습니다. 될 수 있을 것 같기도 하고 아닐 것도 같고.. 구체적인 조건에 따라 달라질 것 같습니다. 아마도 자동차처럼 지면위에서 이동하는 카메라의 캘리브레이션을 하시는 것 같은데요, 틸트의 경우는 소실점을 이용하면 계산이 가능하구요(http://darkpgmr.tistory.com/154), 카메라 높이는 고정이라면 직접 측량하는 것도 괜찮을 것 같습니다. 만일 카메라가 얼마나 이동했는지를 알수 있다면(자동차 주행거리계 등을 이용) 측정이 가능할 것으로 생각되구요, 그렇지 않다면 안될 수 있을 것 같기도 하고.. 그렇습니다.

  • 2018.05.08 21:35 신고 ADDR 수정/삭제 답글

    안녕하세요 다크님 몇가지 질문드리려고요
    1. 월드 좌표와 이미지 좌표를 넣으면 rvec tvec
    가 나오는데 이게 월드 좌표에서 카메라 좌표계로 변하는 r t이 잖슴니까
    그려면 월드 좌표에 대응하는 월드의 카메라 위치는
    위에있는 mat Cam_pos =-R_inv*tvec;로 구하면 되는것인가요
    2.opencv에 보면calibrateCamera 함수가 있습니다
    Finds the camera intrinsic and extrinsic parameters from several views of a calibration pattern.
    여기서도 똑같이 글로벌 포인트랑 이미지 포인트를 넣어주는데요
    rvec tvec 모두 글로벌 좌표계에서 카메라 좌표계로 변하는 r t벡터인가요
    아니면 카메라에서 글로벌로 RT 인가요

    • BlogIcon 다크pgmr 2018.05.08 21:44 신고 수정/삭제

      네, 항상 R, t는 world->camera 입니다(pc = R*pw + t). 그리고 카메라의 월드좌표도 -Rinv*t가 맞습니다.

    • 2018.05.09 06:35 신고 수정/삭제

      답변감사합니다 다크님
      월드좌표에서 이미지 평면위로 가는 r t로 이해하면 맞는건가요?

    • BlogIcon 다크pgmr 2018.05.09 10:41 신고 수정/삭제

      월드좌표(3d)에서 카메라좌표(3d)로의 변환입니다. 카메라좌표는 카메라 위치를 중심(원점)으로 하는 좌표계입니다. http://darkpgmr.tistory.com/77 글 참조.

    • 2018.05.09 13:13 신고 수정/삭제

      질문1. 월드좌표(3d)에서 카메라좌표(3d) 변환이 월드 좌표계 -> 카메라 좌표계 R T를 준다는 말과 동일한 말인가요?

      질문2. 아래 opecv 함수 인데요
      solvepnp는 월드를 모델 좌표계로 놓는다면
      월드 좌표계-> 카메라 좌표계의 R T이고
      calibrateCamera 함수를 보면 모델 좌표계에서 월드 좌표계로 되어있는데요
      calibrateCamera 함수는
      카메라 좌표계-> 월드 좌표계인게 맞는 건가요? 둘 함수가 다른게 아닌가요?

      solvePnP
      brings points from the model coordinate system to the camera coordinate system.

      calibrateCamera
      from the model coordinate space (in which object points are specified) to the world coordinate space

    • BlogIcon 다크pgmr 2018.05.09 13:51 신고 수정/삭제

      저도 함수 설명을 읽어보니 충분히 혼동스러울 수 있겠네요. calibrateCamera 함수에 대한 opencv 설명은 오타(typing error)로 보입니다. 하지만, 설명이야 어떻든 항상 R, t는 pc = R*pw +t (pw: world coordinate, pc: camera coordinate)로 사용됩니다. calibrateCamera에서도 동일한 의미로 사용되고 있구요..

    • 2018.05.09 14:40 신고 수정/삭제

      답변 감사합니다.

      아직 헷갈려서 그러는데요
      제가 보고 있는 그림에서는
      카메라 원점에 좌표계 Xc Yc Zc가 그려져있습니다.
      또한 월드 좌표 Xw Yw Zw 가 그림으로 그려져있습니다.
      저 함수를 돌렸을 때 그 그림상에 화살표를 그리면 카메라 좌표계-> 월드 좌표계 RT로 그리는게 맞는가요 아니면 반대로 월드 좌표계-> 카메라 좌표계 가 맞을 까요?

    • BlogIcon 다크pgmr 2018.05.09 17:11 신고 수정/삭제

      그것은 상황에 따라 다릅니다. 좌표축 변환과 좌표변환은 서로 다르고 역변환 관계라는 것을 주의해야 합니다. 카메라좌표축 자체를 R|t 하면 월드 좌표축이 나옵니다. 그리고, 월드좌표에 R|t를 적용하면 카메라 좌표가 나오구요. 따라서, 그림에서 축의 변환을 표현하는 것이라면 카메라좌표축 -> 월드좌표축으로 화살표를 그리면서 R|t를 표기해야 하고, 좌표의 변화를 표현하는 것이 목적이라면 월드좌표->카메라좌표로 화살표 방향을 해야겠지요.

    • 2018.05.09 19:47 신고 수정/삭제

      !!이해가 됬습니다 다크님
      항상 블로그 좋은 글 감사합니다.
      좋은하루 보내세요.

  • 토이 2018.05.31 13:08 신고 ADDR 수정/삭제 답글

    다크님 카메라 켈리브레이션 보드가 있고
    평면으로 카메라가 위를 찍었다고 할 때 카메라와 켈리브레이션 보드를 실측으로 거리를 측정한 상태에서 그 거리를 유지한채
    빙글빙글 돌면서 체커보드가 다나오도록 카메라로 사진을 취득 하는 알고리즘을 혹시 아시나요?

    • BlogIcon 다크pgmr 2018.05.31 19:34 신고 수정/삭제

      도형의 닮은비를 이용해서 "보드에서의 실제 크기 : 영상에서의 크기 = 카메라-보드 측정거리 : 초점거리"를 이용하면 카메라 초점거리가 나오고, 빙글 빙글 돌리면 영상에서 원을 그리게 되는데, 그 센터( center)로 주점(principal point)을 구하는 방식입니다.

    • 토이 2018.06.06 14:37 신고 수정/삭제

      오 감사합니다 한번 구현해봐야겠어요!

  • PRXZM 2018.08.25 17:36 신고 ADDR 수정/삭제 답글

    안녕하세요.
    카메라 외부 파라미터가 roll, pitch, yaw 값에 대해 0.213877, 0.003699, 0.000555 이렇게 표기되어 있는데, 혹시 이 값들로 Rotation matrix는 어떻게 계산하나요?

    • BlogIcon 다크pgmr 2018.08.27 09:35 신고 수정/삭제

      오일러 각(Euler angle)을 이용해서 회전변환을 구하는 방법을 찾아보시면 좋을 것 같습니다.