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

영상처리 2014. 1. 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 다크 프로그래머


  • 이전 댓글 더보기
  • BlogIcon OKOK 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 OKOK 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 OKOK 2018.01.03 10:03 신고 수정/삭제

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

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

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

    • BlogIcon OKOK 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)을 이용해서 회전변환을 구하는 방법을 찾아보시면 좋을 것 같습니다.

  • 왕초보 2018.12.15 20:23 ADDR 수정/삭제 답글

    calibration하기 위해서 제가 이미징 장치(board) 등에서 정보를 opencv 쪽으로 넘겨줘야 하는것도 잇나요??
    또한 테스트를 하기 위해서 조건을 좀 알려주시겠어요? 예를 들어 인터넷에서 인물+배경 사진은 안되고 직접 카메라에서 나온 바이트로만 calibration이 가능한지 ...

    • BlogIcon 다크pgmr 2018.12.17 17:34 신고 수정/삭제

      질문하신 내용은 제가 이해하기 어렵습니다. 조금 더 표현을 정리하여 문의해 주시면 좋을 것 같습니다.

  • 비전초보 2019.06.04 09:30 ADDR 수정/삭제 답글

    다크님. 좋은 글 항상 감사드립니다. 한 가지 궁금한 점이 있어서 댓글 남깁니다.

    본문 중 카메라의 3D 위치 (월드좌표)는 카메라 좌표계의 원점에 대응하는 월드좌표이므로
    camera_pos = - R^-1 T 로 계산된다고 하셨는데요.

    이 월드좌표계의 원점이 어딘지가 궁금합니다.

    이 값을 영상의 중심 (principal points)에 해당하는 점의 3D 좌표를 원점으로 잡고 여기에서부터의 상대적인 거리라고 생각하면 되는건가요?

    • BlogIcon 다크pgmr 2019.06.04 14:24 신고 수정/삭제

      안녕하세요. 월드좌표계의 원점은 사람이 정하기 나름입니다. 어디가 되었든 어느 한 지점을 월드좌표계 원점으로 정한 후에 공통으로 사용하는 것입니다.

    • 비전초보 2019.06.04 16:01 수정/삭제

      그렇다면 camera_pos의 좌표계는 본문에서 코드로 정리된 부분인
      vector<Point3f> objectPoints; // 3d world coordinates
      와 동일한 좌표계를 공유한다고 보면 되는건가요?

    • BlogIcon 다크pgmr 2019.06.04 17:55 신고 수정/삭제

      네 그렇습니다.

  • 부발 2019.06.12 16:59 ADDR 수정/삭제 답글

    안녕하세요 정말 감사히 잘 보고 있습니다.
    지식이 미천하여 이해하지 못해
    한가지 궁금한게 있어서 여쭤 봅니다.
    아래의 Zc인 기저벡터를 회전벡터 R과 곱을 하였을때 기하학적인 의미를 매칭할 수가 없습니다.
    왜 Zc과 R을 곱하면 어떻게 월드좌표로 변하길래 피치와 틸트를 구할 수 있나요?
    ///
    카메라 광학축 벡터 Zc = [0, 0, 1]T에 대한 월드좌표 Zw를 다음과 같이 계산합니다.
    --- (3)식
    이렇게 계산된 광학축에 대한 월드좌표를 Zw = [zx, zy, zz]T라 하면 카메라의 팬, 틸트는 다음과 같이 계산됩니다
    ///

    • BlogIcon 다크pgmr 2019.06.13 16:38 신고 수정/삭제

      Zw 뿐만 아니라 어떤 좌표이든 식 (1)을 적용하면 월드좌표 -> 카메라좌표로 변환됩니다. 그리고 이러한 R, t는 solvePnP 함수를 통해 얻어집니다.

  • 우디 2019.07.19 15:34 ADDR 수정/삭제 답글

    안녕하세요. 항상 너무 감사히 잘 보고 있습니다.
    이번 글에서 질문이 있습니다.
    Q1. P(X,Y,Z)는 "카메라로부터 (수직방향으로) Z만큼 떨어진 거리에 있는 점"이라고 설명해주셨습니다.
    제가 픽셀 좌표계 값과 카메라 내부 파라미터 값을 사용해서 X= ((x-cx)/fx*Z), Y=((y-cy)/fy*Z)를 구해보려고 하는데, 여기서 Z의 단위는 meter, pixel 어떤걸로 변환해서 넣어야할지 잘 모르겠습니다. 카메라로부터 물체의 거리를 안다면 pixel로 변환해서 넣어야 하는게 맞나요? 혹시 맞다면.. 다크 프로그래머님 블로그에서 어떤 포스팅 글을 참고하면 pixel로 변환하는 방법을 참고할 수 있을지 궁금합니다.
    Q. 그리고 본 글에서 나오는 P(X,Y,Z)를 공간 좌표라고 하셨는데 공간 좌표가 월드 좌표계와 같은 말인지 궁금합니다.

    • BlogIcon 다크pgmr 2019.07.22 10:04 신고 수정/삭제

      안녕하세요. Q1. 일단, X= ((x-cx)/fx*Z), Y=((y-cy)/fy*Z)로 계산한 X, Y는 Z의 단위와 동일합니다. 그리고 Z의 단위는 meter, centimeter 등 원하는 단위를 사용하면 됩니다. 하지만 Z의 단위로 pixel을 사용하는 것은 조금 이상합니다. pixel은 이미지 센서의 셀(cell)에 대응되는 개념이니 굳이 하자면 물체까지의 거리(Z)가 셀 크기의 몇 배인지를 계산해서 pixel로 표현할 수도 있겠지만 3D 좌표를 그렇게 표현할 필요는 없을 것 같습니다.
      Q2. 그리고, 공간좌표는 3차원 공간에 대한 좌표임을 나타내기 위해서 그러한 용어를 사용했습니다. 월드 좌표계가 될 수도 있고 카메라 좌표계가 될 수도 있습니다 (모두 공간에 대한 좌표입니다...)

  • 파랭이 2019.09.05 15:40 ADDR 수정/삭제 답글

    덕분에 큰 도움이 되었습니다^^
    감사하고 존경합니다.

  • 뚜기 2020.06.02 17:35 ADDR 수정/삭제 답글

    안녕하세요 라이다 (X,Y,Z) 형식으로 데이터를 받고 있습니다. PTZ 카메라는 같은 위치에 달려 있습니다 이럴경우 라이다에서 제공하는 탐지를 PTZ 카메라로 오토 트레킹 하고 싶은데 거리가 멀어질 경우 Zoom in을 하게 될경우 다시 Pan/Tilt를 조절해줘야 하는데 방법이 잘 떠오르지가 않아서 문의 드립니다. 혹시 아이디어 있으실까요 ?

  • 안세안세 2020.08.08 03:16 ADDR 수정/삭제 답글

    좋은글 잘읽었습니다. 궁금한 점이 있는데 solvePnP함수에 넣는 4개의 월드 좌표 매칭쌍의 경우 평면상의 매칭쌍이여야 하는것인가요? 아니면 임의 4개 월드좌표(입체)여도 가능한 것인가요? homogenos변환 기반의 함수라면 평면상의 좌표여야 할 것이고 essential matrix기반 함수라면 후자도 가능할것 같은데요

    • BlogIcon 다크pgmr 2020.08.08 21:34 신고 수정/삭제

      평면에 있을 필요는 없으며 임의의 4개 월드좌표면 됩니다.

  • SilentEVE 2020.09.16 14:42 ADDR 수정/삭제 답글

    안녕하세요 궁금한 부분이 있어 댓글로 질문드리게 되었습니다.
    카메라 내부 파라메터를 구하기 위해 calibrateCamera() 함수를 사용하게 되면
    체스보드를 찍은 장수만큼 world -> camera 로 가는 RT를 반환하는것으로 알고있습니다.
    만약 카메라 캘에 사용한 체스보드 이미지(첫번째 이미지)를 가지고 SolvePnP 를 사용했을 경우
    SolvePnP에서 반환하는 RT와 calibrateCamera()에서 나온 첫번째 RT와 완전 동일한 RT인지 알고싶습니다.

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

      기본적으로는 같습니다만 solvePnP 함수를 어떻게 사용했느냐에 따라 달라질 수 있습니다. sovePnP 함수를 호출할 때 인자로 주는, 월드좌표-영상좌표 쌍, 카메라 파라미터 등을 동일하게 준다면 같은 결과가 나올 것입니다.
      중요한 것은 반환되는 RT가 월드좌표계를 기준으로 한 카메라 위치 및 자세라는 점입니다. 월드좌표계가 바뀌면 당연히 RT도 바뀝니다. 그리고 월드좌표계는 어디서 주어지는 것이 아니라 자신이 설정하는 것입니다. opencv에서는 내부적으로 체스코드의 한쪽 모서리 코너점을 월드좌표계 원점으로, 체스보드 평면을 월드좌표계 XY 평면으로 잡고 코너점들의 월드좌표를 자동으로 부여합니다. 동일한 규칙을 사용해서 월드좌표계를 설정하면 동일한 결과를 얻을 것입니다.

    • BlogIcon SilentEVE 2020.09.17 10:38 수정/삭제

      답변 감사합니다. 말씀하신대로 체스보드의 한쪽 모서리 코너점을 월드좌표 (0,0,0)으로 지정하는 규칙을 사용했습니다.
      만약 사용하는 2개의 카메라 내부파라미터와 왜곡계수를 캘리브레이션 과정없이 알고있다면,
      solvePnP를 이용해서 월드-각 카메라 간의 RT를 구한 뒤 두 카메라 사이의 RT를 계산할 수 있는 것인가요?

    • BlogIcon 다크pgmr 2020.09.17 11:31 신고 수정/삭제

      네 가능합니다.
      c1 = R1w+t1, c2 = R2w+t2라면
      w = R1^T(c1-t1), w = R2^T(c2-t2) 이므로
      c2 = R2R1^T(c1-t1)+t2 이겠습니다.
      따라서, c1 -> c2로의 R, t는
      R = R2R1^T, t = t2 - R2R1^Tt1 이겠네요

    • BlogIcon SilentEVE 2020.09.17 14:05 수정/삭제

      감사합니다, 덕분에 이해 안됐던 부분이 해결되었습니다!

  • 2ID 2020.12.23 14:31 ADDR 수정/삭제 답글

    좋은 설명 감사드립니다. 궁금한게있습니다.

    카메라의 roll 각을 젤때,
    Xpan 과 Xw(카매라 좌표계의 Xc 벡터의 월드좌표 벡터)사이의 각이 roll 각이라고 하셨는데, 이 부분이 오류가 있는것 같습니다.

    만약 카메라의 tilt 각도가 0도이면
    Xpan 과 Xw 는 항상 90도가 아닌가요?

    그리고 tilt 각도가 90도 여야지만
    비로소 Xpan과 Xw 사이의 각이 Roll 각 아닌가요?

    • BlogIcon 다크pgmr 2021.01.13 13:20 신고 수정/삭제

      3D 쪽은 복잡해서 따져보기가 쉽지 않은데요, 저는 실제로 구현해서 잘 사용하고 있는 코드라서.. 사실 생각하신 의도(방식?)를 잘 파악하지 못해서 답변을 못드리고 있습니다. tilt가 0이면 카메라가 지면과 수평일 때인데요, Xpan은 roll이 없을 경우 현재 pan, tilt 위치에서의 월드 X축 벡터이고, Xw는 현재 roll이 있는 상태에서의 월드 X축 벡터이니 두 벡터의 사이각을 구하면 roll각이 나올 것 같습니다만.

  • 2021.01.06 16:37 ADDR 수정/삭제 답글

    비밀댓글입니다

  • rustyant 2021.03.28 19:00 ADDR 수정/삭제 답글

    다크프로그래머님. 안녕하세요.
    저는 2대 이상의 카메라를 이용하여 2차원 영상 좌표를 3차원 좌표로 변환하는 작업을 하고 있습니다. (라즈베리파이4 module v2, Fixed Focus)
    그렇기 때문에 평소 많은 도움을 받고 있습니다. 감사합니다.

    갈피를 못 잡고 있는 일이 있어 여쭤보게 되었습니다.
    괜찮으시다면 방향성이라도 답변 주시길 부탁 드리겠습니다.

    1. 카메라 캘리브레이션
    cv::calibrateCameraRO 함수를 사용하여 캘리브레이션하고 있습니다.
    말씀해 주신 것처럼 근거리에서, 여러 각도로, 20장 이상의 영상을 사용하고 있습니다.

    같은 모델의 카메라인데도 캘리브레이션 값이 모두 다릅니다.
    H/W Spec.은 동일하게 만들려고 했지만 공정상의 문제로 이러한 격차가 발생하는 것일까요?
    카메라마다 fx, fy의 값이 최대 40~50 픽셀씩 차이가 있어, H/W Spec. 대로 아래의 식으로 계산할까 고민도 했습니다.
    fx(pixels) = FX(mm) * ImageWidth (pixel) / SensorWidth(mm)

    그럼에도 캘리브레이션의 결과 값을 사용하는 것이 맞겠죠?


    2. 3차원 좌표 계산
    2대의 카메라에서 임의로 위치를 지정한 7개의 3차원 좌표에 대해 Projection 결과로 이미지 좌표 값들 구하고, 각각의 값들과 실제 영상의 이미지 좌표와의 차이를 구했습니다.

    Projection한 결과와 실제 영상에서의 좌표 사이에 최대 35픽셀의 오차가 발생하고 있습니다.
    실제 영상에서의 좌표는 (65, 472)인데, cv::projectPoints 함수로 구해진 값은 (100.197, 461.748)입니다.

    제가 한 작업을 요약하면 이렇습니다.
    7개의 3차원 좌표를 미리 결정하고, calibrateCameraRO, solvePnp의 결과로 구해진 camera matrix, distortion coefficients, rotation vector, translation vector를 사용하여 7개의 3차원 좌표의 Projection 결과를 출력했습니다.
    그리고 실제 영상을 획득하여 영상에서의 좌표와 Projection 결과를 비교한 것입니다.
    아주 엉뚱한 값이 나온 것이 아니라서, Calibration과 Projection을 무한 반복하고 있습니다.
    이러한 오차의 원인은 어디에서 찾아야 할까요?

    감사합니다!

    • BlogIcon 다크pgmr 2021.03.30 19:44 신고 수정/삭제

      안녕하세요. 질문하신 내용에 대해 저라고 딱히 답을 알기는 어렵습니다. 다른 사람이 원인을 알기는 어려우니 스스로 하나씩 문제점을을 찾아낼 수 밖에 없는 것 같습니다. 보통 캘리브레이션을 하면 rms를 반환하는데, 1 pixel 이하여야 정상적으로 캘리브레이션이 되었다고 볼 수 있습니다. 35 pixel 에러는 너무 큰 것 같으니 일단은 캘리브레이션 rms부터 하나씩 체크해 보시면 좋을 듯 싶습니다.
      그리고, 캘리브레이션 결과가 할 때마다 달라지는 것은 캘리브레이션 알고리즘이 최적화 알고리즘을 통해 근사적으로 해를 찾기 때문입니다.

    • BlogIcon rustyant 2021.04.01 16:22 수정/삭제

      감사합니다!
      덕분에 제가 원하는 결과에 근접해 가고 있습니다.