solvePnP 함수 사용법과 Rodrigues 표현법

영상처리 2013.09.25 12:43

opencv의 solvePnP 함수 사용법과 3차원 회전변환을 표현하는 한 방법인 Rodrigues' rotation formula에 대한 내용입니다.



1. solvePnP 사용법


solvePnP 함수는 영상을 획득한 카메라의 위치 및 방향 (camera pose)을 알아낼 때 유용하게 사용할 수 있습니다만, 인터넷에 사용법 정보가 잘 없는 것 같아 여기에 적어봅니다.


[solvePnP 사용예제]


// 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 vectors

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


// extract rotation & translation matrix

Mat R;

Rodrigues(rvec, R);

Mat R_inv = R.inv();


Mat P = -R_inv*tvec;

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


// camera position

printf("x=%lf, y=%lf, z=%lf", p[0], p[1], p[2]);



위에서 구한 P는 카메라의 위치를 나타내고, 회전변환(월드좌표->카메라좌표) 행렬 R로부터는 카메라의 자세(방향) 정보를 추출할 수 있습니다.



2. Rodrigues' rotation formula (이하 2014.4.22 추가된 내용)


opencv의 solvePnP 함수에서 반환되는 rvec는 Rodrigues를 컴팩트(compact)하게 표현한 벡터입니다. 먼저, Rodrigues가 무엇인지 살펴본 후 opencv에서 사용하는 Rodrigues 표현법에 대해 살펴보겠습니다.


3차원에서 회전변환은 보통 3 × 3 행렬로 표현됩니다. 그런데, Rodrigues를 사용하면 임의의 3차원 회전변환을 4개의 값(회전축 벡터 + 회전각) 만으로 표현할 수 있습니다. 3차원 공간에서 점 p를 회전축 v에 대하여 θ만큼 회전시킨 값은 다음 식에 의해 계산될 수 있는데, 이 식을 Rodrigues' rotation formula라고 부릅니다 (Rodrigues는 이 식을 만든 프랑스 수학자의 이름).


 --- (1)


이 때, v는 단위벡터(unit vector)이어야 하고 회전방향은 오른손 법칙을 따릅니다 (엄지를 펴고 오른손을 쥐었을 때 엄지의 방향이 회전축 방향, 쥔 손가락의 방향이 + 회전방향).


식 (1)을 행렬 형태로 표현하면 다음과 같습니다.


 --- (2)


식 (2)로부터 Rodrigues v = (vx,vy,vz), θ에 대응하는 회전변환 행렬 R이 다음과 같음을 알 수 있습니다.


 --- (3)


식 (3)은 우리가 임의의 회전축에 대한 회전을 회전변환 행렬로 표현할 수 있음을 나타냅니다.


반대의 경우로, 임의의 회전변환 행렬에 대한 Rodrigues 표현은 다음 수식을 이용하여 구할 수 있다고 합니다 (참조: 위키피디아).


 --- (4)



3. opencv에서의 Rodrigues 표현


opencv에서는 회전변환행렬 표현과 Rodrigues 표현 사이의 상호 변환을 위해 Rodrigues()란 함수를 제공합니다. 그런데, opencv에서 사용하는 Rodrigues 표현은 보다 컴팩트(compact)한 형태로서 단 3개의 값만으로 회전변환을 표현합니다.


opencv API 설명문서에 따르면 원래 회전변환은 3 자유도이기 때문에 opencv에서는 회전변환을 rod2 = [a, b, c]의 3차원 벡터로 컴팩트하게 표현하고 이로부터 회전각(θ) 및 회전축 벡터(v)는 다음과 같이 추출합니다.


 --- (5)


 --- (6)


이와같이 solvePnP 함수에서 반환되는 rvec는 Rodrigues에 대한 3차원의 컴팩트한 표현법이므로 회전각 및 회전축을 알기 위해서는 식(5), 식(6)을 이용해야 합니다.



by 다크 프로그래머


  • 이전 댓글 더보기
  • 김경민_군산대학교 2014.04.23 02:13 신고 ADDR 수정/삭제 답글

    이론쪽으로 알고싶습니다.

  • 김경민_군산대학교 2014.04.23 02:21 신고 ADDR 수정/삭제 답글

    알아냈네요

    • 설마.. 2017.08.09 15:46 신고 수정/삭제

      설마 전주교대 부속초등학교?

  • 왜곡 2014.06.21 15:52 신고 ADDR 수정/삭제 답글

    안녕하세요 다크님. 궁금한게 있어서 이렇게 글을 올립니다. 아무래도 연관된 게시판이 여긴 것 같아서 여기에 올리게되네요.
    카메라 캘리브레이션을 수행하면 왜곡계수(p1,p2,k1,k2)가 나오는데요,
    이것을 활용하여 화면을 출력하기 전에 사전왜곡(pre-distortion)을 하는 방법이 참 궁금합니다ㅜㅜ
    이 사전왜곡을 하는데는 intrinsic parameter는 들어가질 않습니다..

    왜 이런 질문을 드리는지는 아래와 같습니다.
    extrinsic parameter를 구할 때 이미지상의 2D와 3D객체와의 대응점을 알아내서 camera matrix를 decomposition을 하는데요
    여기서 2D이미지를 활용하여 3D객체와의 대응점을 손수 찾을 때 (패턴판 말고 실제 3D 물체입니다)
    사전 왜곡 된 이미지를 출력하면서 대응점을 찾아야합니다(그래야지 정확한 EXTRINSIC PARAMETER를 찾을 수 있습니다.) 아무리 찾아봐도...
    사전왜곡에 관련 된 내용은 없네요...
    그냥 이미지를 intrinsic parameter, distortion coefficient를 적용해서 왜곡보정한 건 쉽게 찾을 수 있는데... 화면 자체를 출력하기 전에 사전왜곡하는건 정말 없습니다ㅜ
    검색 하다보니 이것이 pixel shader에서 가능한 작업이라하는데...
    구글검색하나, 네이버 검색하나 정말 찾을 길이 없네요...

    직접 풀어야 할 문제지만 ㅜㅜ
    정말 궁금해서 여쭤봅니다.. 감사합니다.

    • BlogIcon 다크pgmr 2014.06.22 10:55 신고 수정/삭제

      안녕하세요. 사전왜곡이라는게 어떤 것인지.. 이미지의 왜곡을 펴듯이 카메라에서 들어오는 영상의 왜곡을 편 후에 화면에 출력하면 될 것 같은데요. 카메라에서 들어오는 영상도 기본적으로는 이미지이기 때문에 왜곡보정을 적용하는 것은 아무런 차이가 없는데.. 왜 그러한 고민을 하시는 건지 사실 저는 잘 이해가 안갑니다. 제가 질문 내용을 잘 파악하지 못한 것일수도..

  • 마자용 2014.08.26 05:10 신고 ADDR 수정/삭제 답글

    안녕하세요. 컴싸를 공부하는 한 학생입니다. 위에 글 정말 잘 읽었습니다. 좋은 정보 감사합니다.
    식(5), (6)번에 관해서 궁금한 점이 있어서 질문 올립니다.
    제가 OpenCV calibrateCamera를 사용해서 rvec과 tvec을 구해서 물체에 대한 카메라의 위치를 OpenGL 3D로 구현하려는데 tvec을 glTranslatef(x,y,z)에 변수로 지정하는데 까지는 성공했는데(tvec.at<double>(0,1) 이런식으로요) OpenGL glRotatef(angle, x, y, z)함수를 쓸차레가 오자 막막하네요;; OpenCV 공홈에 가봐도 Rotation Vector에 관한 설명은 그냥 Compact 한 Rotation Matrix의 저장방법이라고 밖에 써있지 않은데, 다크님께서 쓰신 식(5)와 식(6)을 사용하면
    double a = rvec.at(0,0) (Rodrigues를 사용하기 전 3x1벡터입니다)
    double b = rvec.at(0,1)
    double c = rvec.at(0,2)
    double theta = sqrt(pow(a)+pow(b)+pow(c)) * (180/3.141592)
    glRotatef(theta, a/theta, b/theta, c/theta)
    이런식으로 바로 한번에 회전시킬수 있는건가요??

    아니면 Rodrigues함수로 Rotation vector(3x1)를 Rotation Matrix(3x3)으로 변환해서
    Euler's angle을 추출해서
    glRotate(xAngle, 1.0f, 0.0f, 0.0f)
    glRotate(yAngle, 0.0f, 1.0f, 0.0f)
    glRotate(zAngle, 0.0f, 0.0f, 1.0f)
    이런식으로 따로따로 해야하나요?

    Rotation vector라는 걸 처음 접하니 너무 어렵네요 ㅜㅜ
    감사합니다.

    • BlogIcon 다크pgmr 2014.08.26 11:42 신고 수정/삭제

      안녕하세요. 둘다 모두 타당한 방법으로 생각됩니다만 제가 OpenGL과 같은 그래픽스 쪽은 잘 몰라서 곧바로 적용될지는 잘 모르겠습니다. 제가 알기로 컴퓨터 비전에서 사용하는 rotation 행렬과 그래픽스에서 사용하는 rotation 행렬 사이에는 차이가 있어서 약간의 변환작업이 필요한 것으로 알고 있습니다. 컴퓨터 비전(opencv 등)에서는 카메라 좌표계가 카메라가 보는 방향이 z축 +, 오른쪽이 x축 +, 아래쪽이 y축 +이지만 그래픽스 쪽에서는 카메라가 보는 방향이 z축 -, 오른쪽이 x축 +, 위쪽이 y축 +라서 z축과 y축 방향이 서로 반대인 것으로 알고 있습니다. 이러한 변환 이슈에 대해서는 인터넷 검색을 활용해 보시기 바랍니다.

    • BlogIcon 너부리이놈 2016.09.19 22:46 신고 수정/삭제

      opencv를 opengl로 옮기는거 성공하셨나요?
      ar구현중인데 어렵네요

  • 마자용 2014.08.26 11:44 신고 ADDR 수정/삭제 답글

    네 감사합니다 ^^

  • 체스보드 2015.04.09 16:02 신고 ADDR 수정/삭제 답글

    혹시..solvepnp의 pnp중 p3p에 대한 자료가 있는 링크를 알고계시면 혹시 알려주실수 있으신가요?
    그리고 간단하게나마 시간이 나신다면 p3p에 대해 설명해주실수 있으신가요? 생각만큼 자료가 많지 않은것 같아서요...아니면..검색 키워드라도...ㅠ

    • BlogIcon 다크pgmr 2015.04.11 04:52 신고 수정/삭제

      저도 p3p에 대해서 잘 알지 못합니다만 p3p pose estimation으로 검색해 보시면 좋을 것 같습니다.

  • Astroboy 2015.07.07 17:00 신고 ADDR 수정/삭제 답글

    안녕하세요, Camera Calibration 프로그램 글에서 질문을 드렸는데,
    이번에는 이 글에서 또 질문을 드리게 되었네요.
    제가 지금 하려고 하는 것이, 다크프로그래머 님께서 이 글에서 올려주신 코드로 회전행렬 R과 평행이동 tvec을 이용해, 영상에서의 좌표를 가지고 월드 좌표계에서의 실제 좌표를 찾으려고 하고 있습니다. A의 값은 다크프로그래머님이 올려주신 프로그램을 이용해 구했구요.
    <타겟 추적을 위한 카메라의 팬,틸트 제어>와 <Extrinsic Camera Calibration - 카메라의 위치 및 자세 파악>에 올려주신 방법을 사용해서, 영상에서 점의 좌표 (x,y)에 대해서 test_point = [x;y;1] 의 matrix를 만들어 R_inv*(A_inv*test_point - tvec) 과 같은 식으로 구했습니다.(A_inv는 intrinsic parameter를 나타내는 행렬 A의 역행렬입니다.)
    그런데 말도 안되는 값이 계속 나오네요, 위 코드를 이용해서 구한 카메라의 위치와 거의 비슷한 값이 나옵니다.
    제가 잘못한 점이 무엇일까요?

    • BlogIcon 다크pgmr 2015.07.07 17:33 신고 수정/삭제

      안녕하세요. 최근에 다른 분의 비슷한 질문에 대해서 답변을 드렸던 기억이 납니다. 먼저, http://darkpgmr.tistory.com/82#comment10908438 코멘트를 참조하시기 바랍니다.

      가장 큰 문제점은 2D 영상좌표에서 3D 월드좌표를 복원할 수 없는데, 구하고자 하신 점입니다. 사용하신 수식에서 구한 값은 카메라좌표계상의 좌표 A_inv*test_point에 대응하는 월드좌표입니다. A_inv*test_point가 카메라좌표계에서 카메라 원점에서 멀리 떨어져 있는 점이 아니라면 이로부터 구한 월드좌표는 당연히 카메라 원점에 대한 월드좌표(카메라 위치)와 유사하게 나올 것입니다.

    • Astroboy 2015.07.09 00:15 신고 수정/삭제

      답변 감사합니다. 결국에 안되는 이유가 카메라좌표계상에서의 Z값이 없는 상태에서 3D 복원을 하려고 해서 그런 것이군요.
      만약 어떠한 정해진 평면(plane) 위에서 움직이는 점을 카메라가 정면이 아니라 비스듬하게 바라보고 있는 상황이라면, 2D to 2D에 관한 관계이니까 충분히 서로 복원할 수 있을 것 같은데요.
      직접 기울어져 있는 상황의 각도를 재서 projection되는 식으로 하면 될 것 이라고 생각이 되는데, 그 각도를 정확히 재는게 잘되지 않아서 다른 방법을 찾아보고 있는 중입니다.
      이러한 경우에는 2D-2D 변환이니 homography 변환을 구해서 (아는 기준점을 이용해 findHomography()를 사용) 하는 것이 현명한 방법일까요? 아니면 다크프로그래머 님께서 알려주신 extrinsic parameter R,t를 이용해 정해진 2D로 변환하는 방법이 있을까요?
      조언 부탁드립니다. 감사합니다.

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

      네, 두 방법 모두 가능합니다. homography를 이용한 방법이 좀더 간편할 것 같습니다.

  • 2015.08.08 16:30 ADDR 수정/삭제 답글

    비밀댓글입니다

    • BlogIcon 다크pgmr 2015.08.08 23:27 신고 수정/삭제

      제가 볼땐 문제가 없습니다.. 제 PC에서는 오류없이 잘 동작합니다. 그리고 댓글은 가급적 공개로 부탁드립니다.

    • 영상처리초보 2015.08.12 02:38 신고 수정/삭제

      답변감사합니다^^

  • 월플라워 2015.09.10 20:29 신고 ADDR 수정/삭제 답글

    안녕하세요~
    카메라에서 인식한 마커의 네 개의 꼭짓점을 이용해 카메라의 위치와 방향을 알고자 하는데요,
    제가 지금 카메라 영상을 이미 calibration을 통해 왜곡을 보정했고,
    왜곡이 펴진 이미지 프레임을 영상 처리하고 있습니다.
    보니까 solvePnP에서 camera parameter를 사용하는데 이건 왜곡이 보정되기 전의 이미지 프레임으로 꼭짓점을 구해야 하는건가요?

    • 월플라워 2015.09.10 20:46 신고 수정/삭제

      아, 제가 solvePnP함수에 대해 이해를 잘못했던 것 같네요..
      미리 샘플로 뽑아둔 매칭으로 그 시점에서의 카메라의 position을 구하는 건가요?
      실시간으로 카메라의 위치를 구하는 방법은 없을까요...?

    • BlogIcon 다크pgmr 2015.09.14 22:57 신고 수정/삭제

      안녕하세요. 질문의 내용을 정확히 이해는 못하겠습니다만, 마커를 영상에서 인식할 수 있다면 실시간으로 카메라의 위치를 추적하는 것은 가능합니다. 마커의 공간좌표는 고정이지만 영상좌표는 카메라 위치에 따라서 달라지기 때문에 공간좌표-영상좌표 대응쌍을 이용해서 solvePnP를 적용하면 실시간으로 카메라 위치를 산출할 수 있습니다.

    • 월플라워 2015.10.29 02:55 신고 수정/삭제

      아... 그동안 다른 일이 있어서 못봤는데 답변 감사합니다!
      이제 이해가 잘 됩니다!^^

  • 무코포 2015.10.06 15:23 신고 ADDR 수정/삭제 답글

    좋은글 너무 감사합니다.
    extrinsic parameter 추정을 해야하는 상황인데요 지식이 부족하여 몇가지 질문을 드리고자 합니다.
    위에서 tvec와 camera position을 구하였는데 어째서 두 값이 다른건가요?
    tvec은 이동행렬이기 때문에 월드좌표계의 원점을 중심으로 하는 카메라의 위치를 의미하는것이 아닌가요? 어째서 둘이 구분되는지 아직 저의 능력으로는 어렵네요
    테스트 해본 결과 camera position이 제가 이해한 쪽으로 올바른 결과가 나오는것 같네요
    저의 목적은 단순히 3x4의 변환행렬을 구하는 것인데 (실제 공간에서 물리적 좌표를 측정하였고, 이미지로부터 좌표값을 얻어서 solvePnP에 입력값으로 넣어주었습니다.)
    이를 위해서는 rodriguez 출력 R과 tvec을 합치면 되는것인지 궁금합니다.

    • BlogIcon 다크pgmr 2015.10.06 17:27 신고 수정/삭제

      안녕하세요. OpenCV의 solvePnP로 구한 R, t는 월드좌표 W를 카메라 좌표 C로 변환시키는 것으로서 그 관계는 C = R*W + t입니다. 이 변환에 의해서 카메라의 위치에 대한 월드좌표 P가 카메라 좌표계에서는 0으로 이동해야 하므로 0 = R*P + t를 만족해야 합니다. 따라서, P = -R^-1*t 가 카메라 원점의 월드좌표가 됩니다.
      언뜻 생각하면 t가 카메라의 월드좌표라고 생각하기 쉽습니다. 하지만 월드좌표를 카메라 좌표로 바꾸기 위해서는 회전시킨후 이동시키는 것이 아니라 먼저 평행이동을 시킨 후에 회전을 시켜야 합니다. 즉 C = R(W - p) = RW - Rp가 되어야 합니다. 그런데 solvePnP가 반환하는 R, t는 C=RW+t인 R, t이므로 위와 같은 변형이 필요합니다.

  • 신입생 2016.02.26 10:39 신고 ADDR 수정/삭제 답글

    안녕하세요! 좋은글 감사합니다.
    궁금한게 있는데 저는 체스보드와 cvFindExtrinsicCameraParams2 함수를 이용하여 rvec, tvec를 뽑아냈는데 저는 여기서 나오는 rvec값이 라디안 값인줄 알았는데 그럼 이것도 다크님이 설명하신 것처럼 로드리게스의 컴팩트한 값으로 봐야하는 것인가요?

    • BlogIcon 다크pgmr 2016.02.26 13:21 신고 수정/삭제

      그러리라 생각합니다. 확실히 하기 위해서 반환된 rvec의 차원이 3 x 1인지 확인해 보시면 좋을 것 같습니다.

  • 끄적끄적 2016.03.05 18:35 신고 ADDR 수정/삭제 답글

    안녕하세요.
    혹시 solvePnP 함수 내에서 어떤 수식을 수행하는지 알 수 있나요??
    특정점에 대한 2차원 3차원 정보를 집어넣고, 내부 파라미터, 왜곡계수를 집어넣으면
    rvec,tvec이 출력이 되는 것 같은데 solvePnP 함수 내에서 무슨 연산이 일어나는지 궁금합니다.

    • BlogIcon 다크pgmr 2016.03.05 22:37 신고 수정/삭제

      그건 공부가 필요합니다. PnP 알고리즘에 대해서는 Perspective n point로 검색해 보시기 바랍니다.

  • 초보자 2016.06.02 14:16 신고 ADDR 수정/삭제 답글

    안녕하세요. 카메라 기하에 대해서 공부중인 학생입니다. 질문드리고 싶은것이 있습니다.
    solvepnp를 통해 얻은 R,t를 이용하면 (월드좌표계 기준 카메라의 좌표:tc) = -R.inv()*t로 표현된다면
    월드좌표계에서 현재 카메라의 포즈로가는 변환 관계는 [R.inv()|tc]로 표현될거라고 생각하는데 잘 이해한 것인지 궁금합니다. 즉 solvepnp로 얻은 R의 역행렬은 월드좌표 기준 카메라의 로테이션이 되는것이 맞나요??

    • BlogIcon 다크pgmr 2016.06.02 23:16 신고 수정/삭제

      안녕하세요. 질문이 조금 애매한데요 카메라의 포즈로 간다는 말이 어떤 의미인가요? 카메라의 포즈(pose)는 따로 변환이라 하지 않고 R, t 자체를 그대로 카메라의 포즈로 사용합니다. 그리고 월드좌표 p에서 카메라 좌표 p'로의 변환은 p' = R*p + t로 구해집니다.

  • pearl 2016.07.13 15:27 신고 ADDR 수정/삭제 답글

    안녕하세요. 글 잘보고있습니다.
    혹시 solvePnP해서 rvec를 구하고, Rodrigues한 R값을 RQDecomp3x3함수적용후
    world의 object 회전을 구하려고 합니다.
    RQDecomp3x3에 의해 pitch, yaw, roll값을 구했는데...
    pitch각의 오차가 너무 크네요. 관련해서 조언 받을수 있을까요?

    • BlogIcon 다크pgmr 2016.07.13 21:47 신고 수정/삭제

      저는 RQDecomp3x3 함수를 써보지 않아서 잘 모릅니다만, RQDecomp3x3은 OpenGL에 사용되는 오일러 각을 반환한다고 설명되어 있습니다. 그래픽스(OpenGL 등)에서 사용하는 각의 축과 비전(computer vision)에서 사용하는 각의 축에 차이가 있는데 혹시 그 문제가 아닌지 조심스레 추측해 봅니다..

  • VO 2016.07.20 11:24 신고 ADDR 수정/삭제 답글

    안녕하세요! 글들과 댓글을 보면서 궁금증이 생겨서 질문드립니다.
    남기신 댓글중에 '그리고 월드좌표 p에서 카메라 좌표 p'로의 변환은 p' = R*p + t로 구해집니다.'
    라는 댓글에서 t와 R이 solvepnp로 구한 r,t를 그대로 사용하는 것인가요??
    아니면 t의 경우 글의 내용처럼 T = -R.inv()*t 와 같은 변환과정을 수행한 T를 적용해서 변환하여야 하는 것인가요? R의 경우도 마찬가지로 따로 변환과정을 수행해서 사용하는지 궁금합니다.

    • BlogIcon 다크pgmr 2016.07.20 11:37 신고 수정/삭제

      네.. 혼동스러울 수 있겠네요. 월드좌표(pw)에서 카메라좌표(pc)로의 변환은 pc = R*pw + t 식으로 주어지며 여기서 R, t는 solvePnP로 구한 값을 그대로 이용합니다 (단, R은 Rodrigues(rvec, R)로 변환해서 얻은 값). http://darkpgmr.tistory.com/122 글도 한번 읽어보시면 도움이 될 것 같습니다.

    • VO 2016.07.20 11:42 신고 수정/삭제

      헉..그렇다면 게시된 글에 있는 반환하는 x,y,z는 solvepnp로 얻은 t를 -r.inv와 곱하여 얻어내었는데 카메라 위치의 개념(게시된 글내용)과 카메라 좌표로의 변환(남겨주신 댓글의 내용)이 다른 것인가요??? 제가 아직 공부가 미흡해서 수준이 낮은 질문일지도 모르겠습니다.ㅜㅜ

    • BlogIcon 다크pgmr 2016.07.20 11:49 신고 수정/삭제

      글쎄요.. 어떤 부분이 내용이 다르다는 것인지는 잘 모르겠습니다만 우리가 카메라의 위치를 말할 때는 월드좌표를 기준으로 합니다. 카메라의 위치(원점)은 카메라좌표계로는 Oc = (0,0,0)입니다. 이걸 월드좌표로 변환하면 Oc = R*Ow + t에서 R*Ow = Oc - t. 즉, Ow = R^-1*(Oc - t)인데 Oc가 영벡터이므로 Ow = -R^-1*t 가 됩니다.

    • VO 2016.07.20 13:00 신고 수정/삭제

      아..solvepnp로 나온 r,t에 대해서 카메라 좌표 = r*월드좌표+t이고,
      월드좌표계를 기준으로 하는 카메라의 현재 좌표는 -r^-1*t가 된다. 제대로 이해한 것이 맞는지요??

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

      네 맞습니다.

    • VO 2016.07.20 14:52 신고 수정/삭제

      작성하신 글들을 보며 많이 배우는것 같습니다. 정말 감사드립니다.

  • 무림의 초수 2016.08.04 00:02 신고 ADDR 수정/삭제 답글

    안녕하세요. 비전에 입문하여 하나하나 배워가던 중 이곳을 알게 되었습니다.
    고수님의 친절한 답글 보고 감동받았습니다.

    질문이 있는데요,
    위에 SolvePnP에서 구해진 rvec,tvec 을 가지고,
    Ow = R^-1*(Oc - t) 에 rvec,tvec 및 Oc=(0,0,0)으로 놓으면,
    Ow값이 픽셀단위인가요, 실제 거리(mm or ??) 인가요?

    다른 글에 정규평면 관련한 내용이 있었는데,
    여전히 이해가 잘 안되어서요.
    말씀 부탁드리겠습니다.

    • BlogIcon 다크pgmr 2016.08.05 18:15 신고 수정/삭제

      월드좌표(Ow)와 카메라좌표(Oc) 모두 실제 거리를 단위로 합니다. http://darkpgmr.tistory.com/122 글의 2016.3.3일자 끄적끄적님 댓글에 대한 답변을 참고하시기 바랍니다.

  • 안녕하세요! 2016.10.17 22:40 신고 ADDR 수정/삭제 답글

    안녕하세요 다크프로그래머님. 저는 대학교에 진학중인 학생입니다.
    요즘 관심이 영상처리에 생겨서 혼자 공부를 진행하고 있습니다.
    아직 대학생이다보니 배운것도 적고 혼자 공부하기엔 많이 어렵지만 항상 배우는 자세로 열심히 공부중에 있습니다. 요즘은 켈리브레이션을 직접 만들어보고 싶어서 얕은 지식으로 opencv를 사용하여 제작중인데. 몇가지 궁금증이 생겨서 ㅎㅎ..질문을 드립니다.. 사실 인터넷에서 많은 코드를 접하면서 한줄한줄 이해를 하면서 진행중에 있습니다. 대학교 수준의 질문이라 ㅠㅠ 너무 죄송합니다.
    켈리브레이션중 내부 파라미터를 구하는 것은 이해가 되었으나 외부 파라미터를 구하기 위해선 월드 좌표계가 정의되어야 하잖아요? 카메라는 고정인 상태에서 월드 좌표계의 Z축은 외부 파라미터에 아무 관련이 없는건가요? 인터넷의 다양한 분들이 올린 글에 보면
    for (int i = 0 ; i < image_num; i++) { //이미지수 5
    for (int j = 0 ; j < patten_row ; j++) { // 행수
    for (int k = 0 ; k < patten_col ; k++) { //열수
    object_points[ i * patten_size + j * patten_col + k ].x = j * chess_size; //26mm
    object_points[ i * patten_size + j * patten_col+ k ].y = k * chess_size;
    object_points[ i * patten_size + j * patten_col + k ].z = 0.0 ; }}}
    이렇게 3차원 공간 좌표를 cvInitMatHeader 통해 Mat 으로 행렬을 만들더군요. 그렇담 이게 월드 좌표계가 되는게 아닌가요? 월드 좌표계가 되는거라면 모든 z값을 0으로 두는데.. 외부파라미터와 상관이 없는건가요..? 죄송합니다. 이해가 잘안되서 이렇게 질문드립니다 ㅠㅠ.

    • BlogIcon 다크pgmr 2016.10.19 15:00 신고 수정/삭제

      네, 체스판을 월드좌표계로 가정하고 문제를 푸는 것입니다. 그리고 외부파라미터는 체스판을 기준으로 한 값이 계산될 것입니다.

    • 안녕하세요! 2016.10.19 19:50 신고 수정/삭제

      아 그렇게되면 그렇다면 카메라 고정 상태에서 켈리브레이션을 진행하면 한쪽 벽면에 체스보드판을 붙이고 찍고 다른곳에 붙이면서 찍어야 되겟네요? 들고 다양한 각도로 촬영하면 안되지않나요? z=0이면 x,y의 평면에서 존재하는 것인데 체스보드판을 들고 왼쪽을 좀더 뒤로 하고 오른쪽을 좀 더 앞으로 하면서 찍으면안되겠네요?

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

      체스판을 가지고 카메라 캘리브레이션을 하는 목적은 카메라의 외부 파라미터가 아닌 내부 파라미터를 구하기 위함입니다. 체스판을 기준으로 월드좌표계를 설정하면 카메라 영상을 획득할 때마다 카메라의 자세(R, t)가 바뀌게 됩니다. 즉, 체스판 영상마다 서로 다른 외부 파라미터 값을 가집니다. 하지만 카메라의 내부 파라미터는 카메라의 자세와는 무관한 값이기 때문에 카메라 외부 파라미터가 다른 상황에서도 수학적 제약식을 이용하여 내부 파라미터를 구하게 됩니다. 자세한 수식적 내용에 대해서는 원 논문을 참조하시기 바랍니다 (Z. Zhang. “A Flexible New Technique for Camera Calibration”, TPAMI 2000)

    • 안녕하세요! 2016.10.20 15:52 신고 수정/삭제

      크 정말 감사합니다.....

  • vision공부 2017.07.17 14:13 신고 ADDR 수정/삭제 답글

    질문이 있습니다.
    opencv 3.0에 fisheye모델 캘을 하면, instrinsic과 distortion파라미트거 k1, k2, k3, k4가 나오는데,
    p1, p2를 나오지가 않습니다.
    도저히 이해가 가지가 않아 질문남깁니다. ㅠ

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

      먼저 알아두셔야 할 것은 카메라 렌즈왜곡모델이 한가지가 아니라는 점입니다. 여러 모델이 존재하며 fisheye는 그 중의 한가지입니다. opencv에 새로 추가된 fisheye 모델은 저도 사용하는 모델이 아니라서 자세한 것은 모릅니다. 하지만 어쨌든 k1, k2, k3, k4의 의미를 알기 위해서는 opencv::fisheye 모델이 어떤 모델인지 공부해야 합니다. 어쨌든 기존의 opencv에 존재하던 기본 모델의 k1, k2, p1, p2와 같은 의미인지는 확인이 필요합니다. 글자가 같다고 무조건 같은 의미라고 생각하면 안됩니다 (저도 실제 같은지 다른지는 모릅니다).
      그런데 문제는 solvePnP에서 파라미터로 받는 distCoeffs는 기존의 기본 카메라모델의 k1,k2,p1,p2이어야 한다는 점입니다. 해결책은 2가지입니다. 첫째는, fisheye 모델을 사용하지 말고 기존의 일반적인 카메라모델을 사용해서 k1,k2,p1,p2를 구하는 것입니다 (기본 카메라 모델로 캘리브레이션 해주는 툴은 GML Calibration toolbox 등 좋은 프로그램이 많이 있습니다). 두번째 방법은, solvePnP의 입력으로 픽셀좌표를 사용하지 않고 왜곡 보정된 정규좌표(normalized image coordinate)를 사용하는 것입니다. 그러면 사용한 렌즈왜곡모델에 영향을 받지 않고 카메라의 자세를 추정할 수 있습니다. 단, 이 경우에는 distCoeffs에 k1=k2=p1=p2=0와 같이 왜곡계수를 전부 0으로 해 주면 됩니다.

  • visin공부 2017.07.25 14:44 신고 ADDR 수정/삭제 답글

    위에 답변 감사합니다 ㅎ 많은 도움이 되었습니다.
    제가 알고자 하는건 내부와 여기서 구한 외부 파라미터를 가자고 0 0 0월드좌표가 영상상에서 어디인지 찾고 싶습니다.
    내부파라미터와 여기서 구한 R 그리고 tvec을 이용하고 내가 알고자 하는 3d 포인트가 2d영상에서 어디인지 알고싶습니다. 그렇다면
    rt메트릭스를 3 x 4행렬로 R과 tvec으로 만들고 K*rt*0 0 0 1을 했은데 픽셀좌표가 즉 결과값이 예측이 안되네요.

    • BlogIcon 다크pgmr 2017.07.25 17:25 신고 수정/삭제

      식에는 틀린 부분이 없습니다. 문제의 원인은 사실 다른 사람이 알기 어렵습니다.. 다만 렌즈의 왜곡이 심한 경우에는 rt*0 0 0 1의 결과에 왜곡을 보정한 후 K를 곱해야 합니다. 즉, K*rt*0 0 0 1에는 영상 왜곡보정 과정이 누락되어 있습니다.

  • 333 2018.02.01 17:26 신고 ADDR 수정/삭제 답글

    좋은 글들 잘 보고 있습니다( _ _)꾸벅
    댓글에서 보면 2차례 OpenCV calibrateCamera 함수 보다 GML캘리브레이션 툴을 추천하시는데
    어떤 이유인가요?

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

      제가 추천을 했었나요.. 사실 오래전 글들이라 잘 기억이 안나서.. ^^
      calibrateCamera()는 함수이고, GML은 툴(tool)이니 당연히 툴을 사용하는 것이 편할 것이구요, 그리고 GML의 옵션에 보면 opencv 방법도 캘리브레이션 방법중 하나로 선택할 수 있습니다. 거기에 자신들(GML)이 개발한 캘리브레이션 방법도 선택할 수 있습니다. 그 정도이고 특별한 이유는 없습니다.