Sunday, March 13, 2011

Kinect Color - Detph Camera Calibration

Kinect has two cameras, one for capturing a color image and the other for capturing an IR image. Although real-time depth information is provided by IR camera, the depth map tells how far the IR camera's pixels are and we actually do not know the depth information of the color image because the two cameras have different characteristics. As we can see in the image below, the pixels do not match in the two images.  The locations of the hand and arm are completely different in the two images. 



If we use the Kinect device for HCI, it does not matter much because using depth information is enough in most cases. However, if we'd like to use it for 3D scene capture or to want to relate the RGB and depth images, we need to match the color image's pixels to the depth image's. Thus, we need to perform calibration. 

Kinect camera calibration is not different from the general camera calibration. We just need to capture images of a chessboard pattern from IR and RGB cameras. We need to capture several images of a chessboard pattern. When capturing images from the IR camera, we need to block the emitter with something for good corner detection in chessboard images. If not, the captured images will look like below and corner detection will fail.



If the lightings in your environment does not have enough IR rays, you need a light source that emits IR rays (Halogen lamp ?). It might be good to capture the same scenes with two cameras. The below images show two images captured from the IR and RGB cameras, respectively. 



Once images are taken, then we can perform calibration w.r.t each camera by using OpenCV API, MATLAB calibration toolbox, or GML calibration toolbox. After calibration, the intrinsic camera matrices, K_ir and K_rgb, and distortion parameters of the two cameras are obtained. 



To achieve our goal, we need one more information, the geometrical relationship between the two cameras expressed as a rotation matrix R and a translation vector t. To compute them, capture the same scene containing the chessboard pattern with the two cameras and compute extrinsic parameters. From two extrinsic parameters, the relative transformation can be computed easily. 

Now, we can compute the depth of the color image from the depth image provided by the IR camera. Let's consider a pixel p_ir in the IR image. The 3D point P_ir corresponding to the p_ir can be computed by back-projecting p_ir in the IR camera's coordinate system.


P_ir = inv(K) * p_ir 


P_ir can be transformed to the RGB camera's coordinate system through relative transformation R and t.


P_rgb = R * P_ir + t


Then, we project P_rgb onto the RGB camera image and we obtain a 2D point p_rgb.


p_rgb = K_rgb * P_rgb


Finally, the depth value corresponding to the location p_rgb in RGB image is P_rgb's Z axis value.


depth of p_rgb =  Z axis value of P_rgb 


P_ir : 3D point in the IR camera's coordinate system
R, t : Relative transformation between two cameras
P_rgb : 3D point in the RGB camera's coordinate system
p_rgb : The projection of P_rgb onto the RGB image

In the above, conversion to homogeneous coordinates are omitted. When two or more 3D points are projected to the same 2D location in the RGB image, the closest one is chosen. We can also compute the color values of the depth map pixels in the same way. p_ir's color  corresponds to the color of p_rgb.

Here is the resulting depth image of the RGB camera. Since the RGB camera sees wider region than the IR camera, not all pixels' depth information are available.


If we ovary the RGB image and the computed depth image, we can see that the two match well, while they do not before calibration as shown at the beginning of this post.


Here is a demo video showing the depth map of the RGB image and the color map of the depth image.


57 comments:

  1. Can you tell me if the resolution of the rgb image and the depth map have to be the same for the registration process? As I read in other sources the rgb cam has a 640x480 px res and the res of the IR cam is downsampled!

    ReplyDelete
  2. RGB and depth images can have different resolutions. Mapping depth from the IR camera to the RGB camera is not dependent of the resolution.

    ReplyDelete
  3. Are you planning on releasing any code? I'm not quite following everything you said since I have no experience with this kind of stuff. Some code to look at would be a huge help.

    Thanks!

    ReplyDelete
  4. What are you supposed to do with the distortion parameters? Also, even though it may seem easy to you, I have no idea how to get the relative transformation between the two cameras. Thanks a lot.

    ReplyDelete
  5. Well, usually distortion parameters are used to remove lens distortions from captured images.

    The relative transmation can be computed from the chessboard pattern.

    Assume you capture two images of the same scene (each from RGB, IR cameras), and their extrinsic parameters are M_rgb and M_ir.
    Then the relative transformation that maps a 3D point from the IR camera's coordinate frame to the RGB camera's coordinate frame will be :

    M_(ir -> rgb) = M_rgb * (M_ir)^-1

    ReplyDelete
  6. Hello,
    we are tring to calibrate the depth camera but we
    don't know how to get the IR image like you presented with the kinect? the only images we can see are the color and depth images

    Thanks!
    Haniel and Chen

    ReplyDelete
  7. @Haniel and Chen / Hello. IR image can be captured via libFreenect library. It provides a method to get IR images. But MS's Kinect SDK seems not to allow IR image capture...

    ReplyDelete
  8. Now we understand..

    Thanks for the fast replay!

    ReplyDelete
  9. In the ROS documentation (http://www.ros.org/wiki/kinect_calibration/technical, section 3) they speak about an offset in the IR image due to the correlation window. How do you deal with this issue?

    ReplyDelete
  10. My cousin recommended this blog and she was totally right keep up the fantastic work!

    ReplyDelete
  11. @Calibration: Thanks for your interest !!

    ReplyDelete
  12. Hi, thanks for your work! can you explain better this point of discussion:
    "To compute them, capture the same scene containing the chessboard pattern with the two cameras and compute extrinsic parameters. From two extrinsic parameters, the relative transformation can be computed easily." Many thanks

    ReplyDelete
  13. Hi,

    thanks for the howto. your video shows perfect coverage...i want to have that too :)
    could you provide a code snippet where you compute the matrices and the corresponding point? (also, which are your ex and intrinsic matrices?) I think i have done everything like described in your article, and i get values but unfortunately they don't make any sense.

    Many thanks in advance.

    Daniel

    ReplyDelete
    Replies
    1. hello Daniel, I am also working on this part and it is the final step in my project. Have you solved your problem? Because I also did everything but get a bad result now. Would you please give me some suggestion on my code below?

      Thank you very much!

      Delete
  14. Hello,

    I want to publish my code here because I don' t know which part goes wrong.

    Mat image;
    Mat gray_image;
    Mat dst_image;
    Mat P_ir( 3, 1, CV_64F );
    Mat P_rgb( 3, 1, CV_64F );
    Mat K_rgb( 3, 3, CV_64F );
    Mat K_ir( 3, 3, CV_64F );
    Mat invK_ir( 3, 3, CV_64F );
    Mat p_ir( 3, 1, CV_64F );
    Mat p_rgb( 3, 1, CV_64F );
    Mat R( 3, 3, CV_64F );
    Mat t( 3, 1, CV_64F );
    Mat temp( 3, 1, CV_64F );

    Mat dst;
    CvScalar pixel;

    K_rgb = Mat::zeros(3,3,CV_64F );

    K_rgb.at(0,0) = 529;
    K_rgb.at(0,2) = 328.94;
    K_rgb.at(1,1) = 525.5;
    K_rgb.at(1,2) = 267.48;
    K_rgb.at(2,2) = 1;

    K_ir = Mat::zeros(3,3,CV_64F );

    K_ir.at(0,0) = 594;
    K_ir.at(0,2) = 339;
    K_ir.at(1,1) = 591;
    K_ir.at(1,2) = 242;
    K_ir.at(2,2) = 1;

    image = cv::imread( "D:/456/IRImg_5.png", CV_LOAD_IMAGE_COLOR);
    dst_image.create( image.rows, image.cols, CV_8UC1 );
    R = Mat::eye(3, 3, CV_64F);
    t = Mat::zeros(3,1,CV_64F );
    t.at(0,0) = 0.025;

    invert( K_ir, invK_ir, 0 );

    for( int j = 0; j < image.rows; j++ )
    {
    for( int i = 0; i < image.cols; i++ )
    {
    p_ir.at(0,0) = i;
    p_ir.at(1,0) = j;
    p_ir.at(2,0) = image.at(j,i);

    gemm( invK_ir, p_ir, 1, NULL, NULL, P_ir, 0 );

    gemm( R, P_ir, 1, NULL, NULL, temp, 0 );
    P_rgb.at(0,0) = temp.at(0,0) + t.at(0,0);
    P_rgb.at(1,0) = temp.at(1,0) + t.at(1,0);
    P_rgb.at(2,0) = temp.at(2,0) + t.at(2,0);

    gemm( K_rgb, P_rgb, 1, NULL, NULL, p_rgb, 0 );

    dst_image.at(j,i) = (uchar) P_rgb.at(2,0);
    }
    }

    After this, I tried to show the final depth image, but the result is not good. The depth image I get can not match well with the original one. Would you please take a few seconds to see whether my code is good or not.
    Thank you.

    ReplyDelete
  15. And for the better result, I used the ideal data for K_rgb, K_ir, R and t. I think the circle in my code can correctly complete the 3 steps in your blog, but still I get a bad depth image. Is there any point that I deal in a wrong way? I' m looking forward to your reply.
    Thank you.

    ReplyDelete
  16. @ Jintao Lu / Hello. Judging from your codes, it seems that you are loading depth values from the depth image. However, the depth values in the image (intensities) is not real depth values (in meters or centimeters). Thus, using the intensities as depth for back-projecting pixels to 3D points may result in wrong 3D point clouds. You need to compute the real depth values from the intensities.

    ReplyDelete
  17. wow! Thank you for your detail explanation after 1 year's time of publishing of this blog! I have checked everything with my guider and finally we are focusing on the p_ir. I know something is wrong with this 3×1 matrix but I have no idea with it. But now, thank you again! I will try now!

    ReplyDelete
  18. @ Jintao Lu / You may get some idea about depth-intensity calibration from the paper 'Depth-assisted 3D object detection for augmented reality', which can be found here : http://sites.google.com/site/wleeprofile/research/detection_rgbd .

    ReplyDelete
  19. Hello, thank you for your explanation and I have successfully invert intensities to actual distance.
    Now I have a question about the Z axis value of P_rgb, is it also an actual distance? Because this value is similar to the actual distance of depth image.
    If yes, I wonder whether I need to invert again, from actual distance to intensity, to get the final depth image of rgb camera.

    ReplyDelete
    Replies
    1. @Jintao Lu / Hello. It seems that you are missing something.
      If you get 3D point data from an IR camera image, What you need to do in the next step is mapping the 3D points from the coordinate system of the IR camera to the one of the RGB camera. Finally, by projecting the transformed points onto the RGB image, you will be able to compute the depth of pixels of the RGB image.

      Delete
  20. Hi Wonwoo... I tried to use your formulae. But have not been able to successfully map the depth and rgb image. It would be really helpful, if you can provide some source code which can be used to map between depth and rgb image of Kinect..

    ReplyDelete
    Replies
    1. Hello, Subhasis.
      It has been a while since I wrote the code of the post.
      Unfortunately, I don't have the code now....

      Delete
  21. i have my problems with the extrinsic parameters.

    how have you computed them (with only ir and rgb pics)?

    i used the gml tool which works fine for the intrinsic but i don't know how to get the extrinsics..

    help would be very appreciated :)

    ReplyDelete
  22. @dd / Hello. I used the GML tool to get extrinsic parameters too.

    ReplyDelete
    Replies
    1. ok and how did you do that? (could you give me a little step-by-step plz?)

      i haven't find an option to say 'this is camera 1 and this 2'
      have you loaded the pics from 1 and calibrated then form 2 and calibrated again? oder alltogether and calibrated?
      (i tried.. get no results, only in the combined is a strange extrinsic matrix for every image i guess but the rotation and translation matrix is empty)

      thx

      Delete
    2. Hey, dd.
      I can't understand what problem you encountered.
      I just did a standard procedure of camera calibration with the GML toolbox.

      Delete
    3. the problem are the extrinsic parameters..
      i don't know how to get the translation and rotation matrix via GML.
      i have pictures of camera1 and camera 2 but how can i tell GML which is which etc. it alwas looks like GML is only made for a single camera.

      Delete
    4. Ok, you can compute extrinsic parameters by using :

      - Camera Calibration Toolbox for Matlab (http://www.vision.caltech.edu/bouguetj/calib_doc/), which requires handy work a little bit.

      - OpenCV camera calibration functions (http://docs.opencv.org/modules/calib3d/doc/calib3d.html)

      Actually, you can get both intrinsic/extrinsic parameters using OpenCV but you need to write some codes....

      Delete
    5. oh ok.. i was just wondering since you mentioned you have done it with GML.

      Delete
  23. Hello. You have a very precise alignment. Now I am working on this alignment. I want to ask you how to map the true color on the depth image like you did?

    ReplyDelete
    Replies
    1. Well the colored depth map is just for visualization, which is mapped from a grayscale depth map. So you need to retrieve real gray values from the IR image.

      Delete
  24. 안녕하세요 대학교에서 키넥트로 3d 스캐너를 만드는 중인 학생입니다

    지금까지 제가 진행한 정도가 kinect sdk에서 mm단위로 depth값을 받는것까지 했습니다

    이제 색깔값과 depth값을 이으려고 하는데 조금 차이가 나더군요 그래서 님의 방식을

    배워서 사용하고 싶은데요

    여기서 질문을 드리자면 저기 위에분이 짠 소스를 보니

    image = cv::imread( "D:/456/IRImg_5.png", CV_LOAD_IMAGE_COLOR);

    ==1.여기는 각 픽셀의 리얼뎁스값을 저장하는 용도인가요??



    dst_image.create( image.rows, image.cols, CV_8UC1 );
    R = Mat::eye(3, 3, CV_64F);
    t = Mat::zeros(3,1,CV_64F );
    t.at(0,0) = 0.025;

    invert( K_ir, invK_ir, 0 );

    for( int j = 0; j < image.rows; j++ )
    {
    for( int i = 0; i < image.cols; i++ )
    {
    p_ir.at(0,0) = i;
    p_ir.at(1,0) = j;
    p_ir.at(2,0) = image.at(j,i);
    ==2.여기는 p_ir에 픽셀좌표로 x,y,z값 넣어주는 용도인가요??



    아 그리고 동영상을 보니 opengl로 랜더링을 하셧다고 하셧는데 점으로 찍어서

    하셧는지 아니면 다른방법으로 하셧는지 궁금합니다 점으로 찍어보니 영 아니더라구요

    긴글 읽어 주셔서 감사합니다^^

    ReplyDelete
    Replies
    1. image = cv::imread( "D:/456/IRImg_5.png", CV_LOAD_IMAGE_COLOR);

      위 코드에서는 그냥 IR image 를 저장한 것을 읽어오는 것인데요, image 변수는 실제 depth 영상의 intensity 를 [0-255]로 스케일링한 값을 갖게 됩니다. 그러므로 실제 depth 값과는 약간 차이가 있겠죠.


      그리고, p_ir.at(2,0) = image.at(j,i);
      이 부분에서는 그냥 단순히 픽셀의 위치 (i,j)와 영상의 값을 복사하고 있는데, 앞서 camera matrix K의 inverse 를 게산한 것으로 보아 픽셀을 back-projection을 해서 3D 좌표를 얻으려고 하는 것으로 보입니다. --> P_3d = K_inv * (x,y,depth)

      동영상의 렌더링은 그냥 OpenCV로 4개의 영상을 하나의 영상으로 만들고 그 영상을 glDrawPixels 함수로 간단하게 그렸던 것으로 기억합니다.

      3D 스캐너를 개발하신다면 이미 알고계시겠지만, Kinect SDK 최신 버전에 KinectFusion 이 공개되었으니 한 번 참고하시기 바랍니다.



      Delete
    2. 덧붙여서, 보여주신 코드에서는 P_3d = K_inv * (x,y,depth)를 하기 위해서 0-255 로 스케일 된 Depth 값을 back-projection 에 사용하고 있으므로 아마 제대로 된 3D point 를 얻지 못할 것입니다.

      Delete
  25. 안녕하세요 저번질문에 이어 다시질문하네요 먼저 제가 구한 값들을보면
    (25)
    (0) =t,R은 단위행렬로 뒀는데 오차가클까요? R을 단위행렬로 두면 많이 문제가 될까요?
    (0)

    그리고 t를 25 mm 에서 단위를 mm로 하는게 맞는건지도 알고싶네요

    제가 구한 K_rgb,,,,,,,,K_ir,,,,,,,,,,,,invK_ir값이
    (528___0___326) , (594___0_____339) , (0.001684_____0_______-0.570707)
    (0___528___250) , (0____591____242), (0_______0.001692_____-0.409475)
    (0____0______1) , (0_____0_______1), (0_____________0______________1)

    p_ir은
    (x)
    (y)-----------(x,y는 각각열과 행,realdepth는 키넥트에서 나오는 mm단위 뎁스값)
    (realdepth)

    p_ir을 설정할때 저렇게 설정하면되나요??

    이후부터가 문제인데 P_ir = inv(K) * p_ir 을 저위에것을이용해서 연산을해보면 realdepth

    값에 아무런 영향을 못미칩니다.

    그 다음연산도 P_rgb = R * P_ir + t 이므로 realdepth는 바뀌지 않고,

    p_rgb = K_rgb * P_rgb 이것또한 realdepth는 바뀌지가 않네요

    결국 realdepth와 P_rgb, p_rgb 값이 모두 같아버리는결과를보이네요..,ㅜㅜ

    어디가 잘못됬을까요?? 그리고 P_rgb, p_rgb 값들의 의미가 무엇인지 알고싶습니다

    위에 글만봐서는 제가 이해를 못하겟네요..

    도움부탁드립니다!!!

    ReplyDelete
    Replies
    1. 위에 제글이 3개나더 있는데 장난한게아니라 글쓴거 보정하다

      지웟는데도 글이 남네요.. 죄송합니다ㅜㅜ

      Delete
    2. 그리고 혹시 R 과t 값을 어떤값을 쓰셧는지 알수있을까요??

      Delete
    3. 제가짠 코드의 일부분입니다
      자료형은 전부 더블형입니다 realdepth는 ushort
      *(ptrK_rgb)=510.276;//K_rgb입력
      *(ptrK_rgb+1)=0;
      *(ptrK_rgb+2)=314.504;
      *(ptrK_rgb+3)=0;
      *(ptrK_rgb+4)=510.906;
      *(ptrK_rgb+5)=254.760;
      *(ptrK_rgb+6)=0;
      *(ptrK_rgb+7)=0;
      *(ptrK_rgb+8)=1;


      *ptrK_ir=592.180;//K_ir입력
      *(ptrK_ir+1)=0;
      *(ptrK_ir+2)=305.497;
      *(ptrK_ir+3)=0;
      *(ptrK_ir+4)=586.853;
      *(ptrK_ir+5)=223.732;
      *(ptrK_ir+6)=0;
      *(ptrK_ir+7)=0;
      *(ptrK_ir+8)=1;

      *(ptrR+0)=0.967225;//R입력
      *(ptrR+1)=0.014286;
      *(ptrR+2)= -0.253519;
      *(ptrR+3)=-0.012946;
      *(ptrR+4)=0.999892;
      *(ptrR+5)=0.006953;
      *(ptrR+6)=0.253591;
      *(ptrR+7)=-0.003443;
      *(ptrR+8)=0.967306;

      *(ptrt)=14.282269;//t입력
      *(ptrt+1)=0.481456;
      *(ptrt+2)=1.980509;

      cvInvert( K_ir, invK_ir, 0 );//invK_ir 입력

      여기까지가 인자들 데이터 넣어주는곳이고요


      for(int y=0;yheight;y++)
      {

      unsigned short* ptrd= (unsigned short*)(Depth->imageData + y * Depth->widthStep);//realdepth값(mm단위)에 접근할 포인터 (4채널이나 첫번째꺼에접근)
      unsigned char* ptrc= (unsigned char*)(Color->imageData + y * Color->widthStep);//color값(uchar)에 접근할 포인터 (4채널)

      for(int x=0;xwidth;x++)
      {


      *ptrp_ir=x;//p_ir에 픽셀좌표 x,y와 realDepth(mm단위)
      *(ptrp_ir+1)=y;//넣어주는부분
      *(ptrp_ir+2)=ptrd[4*x];

      cvGEMM( invK_ir, p_ir, 1, NULL, NULL, P_ir, 0 );
      //위의곱은 P_ir = inv(K) * p_ir

      cvGEMM( R, P_ir, 1, NULL, NULL, temp, 0 );
      *(ptrP_rgb) = *(ptrtemp) + *(ptrt);
      *(ptrP_rgb+1) = *(ptrtemp+1) + *(ptrt+1);
      *(ptrP_rgb+2) = *(ptrtemp+2) + *(ptrt+2);
      //위의 연산은 P_rgb = R * P_ir + t


      cvGEMM( K_rgb, P_rgb, 1, NULL, NULL, p_rgb, 0 );
      //위의 연산은 p_rgb = K_rgb * P_rgb


      ptrd[x*4]=(unsigned short)*(ptrp_rgb+2);
      //위는 화면에 출력할 배열에 p_rgb값의 3번째인자 입력

      glColor3ub(ptrc[4*x+2],ptrc[4*x+1],ptrc[4*x]);
      glVertex3f(x,y,(ptrd[x*4]));
      //위에는 점을 찍는 opengl함수인데 여기에서 컬러와 뎁스모두 4채널로 저장해서 4를
      곱했고, x,y 각각에 해당하는 값들을 3차원으로 찍었습니다.
      위에서 넣어준 인자값이나 연산이 안틀렸다면 여기가 수상한데 컬러와 뎁스를 이어줄때
      픽셀을 컬러픽셀좌표(0,0)--뎁스픽셀좌표(0,0) 부터
      컬러픽셀좌표(640,480)--뎁스픽셀좌표(640,480) 까지 순서대로 이어주는게 맞나요?
      아니면 이어줄때 다른방법을써야되나요??
      안되는데 어디서 안되는지 너무답답하네요..

      Delete


    4. 일단 실제 키넥트 영상으로 실험이 잘 안되시면 RGB, IR 카메라의 K 행렬을 구할 때 사용했던 체스보드 패턴 이미지들의 점을 가지고 테스트해 보시기 바랍니다. 이 경우 패턴 위의 점들의 3차원 좌표와 각 영상으로 투영된 픽셀 좌표들(p_ir, p_rgb) 도 이미 알고 있으니 코드가 제대로 동작하고 있는지 정확하게 테스트해 볼 수 있습니다.

      IR 영상에서의 체스보드 패턴의 코너들 (p_ir)
      --> invK_ir 로 back-projection
      --> R,T 를 이용해 (IR 카메라 좌표계) 에서 (RGB 카메라 좌표계)로 변경
      --> K_rgb 로 RGB 영상 위로 투영
      --> RGB 영상의 체스보드 코너점 (p_rgb) 과 일치하는지 비교

      Delete
    5. 그리고 위 포스트에 적혀있진 않지만 키넥트 뎁스 영상의 intensity 값을 실제 거리 (예를 들면 mm) 로 변환하기 위해서는 depth intensity-to-distance 보정이 필요합니다.

      참고 :
      https://b244cc3e-a-62cb3a1a-s-sites.googlegroups.com/site/wleeprofile/research/detection_rgbd/126-Lee.pdf?attachauth=ANoY7colOfr5buUGEF-Pjk78PnWyCXRoD4FEOhaG_7sHyWnDnJ2gzbV9GY9sHnLpO-Ut0qM-E2vffQ4jgfJkSXVztj6M4gCubt_C7hLmc7IuE2UdXlMMYZPLHDQ3ILrLdVnZGKvt-sGConTGdXKuKhbwIo-EBpwcFnmVUQiwvHWft5JjHSTkAEbD7Rt23SvGNCftr5_ii4DSmCPwoO3SYXdfGxPPHdhpbEt2z1T0VbW_XctCXjbhVDivurca84CIM6tmCHxt_IVA&attredirects=0

      또는 해외 블로그들에 보면 변환식을 적어놓은 것들이 있으니 찾아보시기 바랍니다.

      Delete
  26. 제가 너무 답답한나머지 이론보다 코드부터 어떻게 해볼려고했네요.. 죄송합니다

    지금 opencv책을 보고 위에 수식을보니 어느정도 이해가 가는데요 제가 이해한게 맞는지 알수있을까요?
    소문자를 픽셀좌표, 대문자를 월드좌표계(mm)로 하면, x=f_x * (X/Z) + C_x 이므로,
    먼저 IR카메라의 픽셀좌표를 월드좌표계로 변환하기위해 위식을정리하면

    (x*Z)_(f_x,0,c_x)(X)가 되고,
    (y*Z)=(0,f_y,c_y)(Y)
    (Z)___(0,..0..,1)(Z)

    invK_ir을 사용하면,

    (X)..........(x*Z)
    (Y)=invK_ir*(y*Z) = P_rgb가 됩니다.
    (Z)..........(Z)

    그후에P_rgb = R * P_ir + t 을 연산하고, p_rgb = K_rgb * P_rgb 을연산하고 나온

    p_rgb는
    (x*Z)
    (y*Z)
    (Z)
    이므로 x,y에 Z로 나눠서 결과적으로 (x,y,realdepth)(realdepth는 rgb카메라의 z값(mm))
    구하게 되고, (x,y)로 컬러이미지에 접근해서 색깔값얻고, realdepth를 opengl로 찍으면
    될까요?? 지금해보니 매칭이 되는부분도 있고 안되는부분도 있고해서 질문드리네요..

    ReplyDelete
  27. 아 됬습니다!! 자료형설정을 실수로 잘못해서 매칭이 안됬엇네요

    OPENGL로 찍어보니 정렬이 예쁘게되서 나오네요 헤헤

    감사합니다!!~!~!

    아 궁금한점이 있는데 IR은 640*488이고 COLOR는 640*480인 경우에 매칭을 해줄경우 IR에서 오는
    데이터중에서 640*480이후의 값을 그냥 버려주면되는건가요?? 이 두가지가 다를경우 생길수 있는
    문제점이 뭐가있을까요 칼리브레이션할때 문제가되거나 그러나요?? 저는 사진을찍을때 640*480이후
    의 ir데이터값을 모두 버렷거든요
    그리고 카메라 칼리브레이션을 할때 gml툴킷을 썻습니다. 이보다 더좋은 칼리브레이션도구가 있을까요
    마지막으로 두카메라사이의 회전행렬과 이동행렬을 구해주는함수가 opencv에 있던데 쓰니 좀 값이
    잘안나오네요. 혹시 다른 방법은 없을까요??

    ReplyDelete
    Replies
    1. 두 카메라의 해상도 차이는 별 의미는 없습니다. 단지 화각이 다른 것 뿐입니다. IR 카메라가 640x488 이더라도 RGB 카메라가 더 넓은 영역을 보고 있기 때문에 굳이 640x480 외의 영역의 데이터를 버릴 필요는 없습니다. 동일하게 RGB 카메라로 매핑해서 사용하면 됩니다. 그리고 간혹 depth 영상에서 RGB 영상으로 projection 했을 때 서로 다른 두 depth 영상의 픽셀이 동일한 RGB 픽셀로 projection 되는 경우가 있는데 이 경우에는 카메라에 가까운 값을 취해서 사용하면 되구요.

      카메라 캘리브레이션은 GML이 가장 편리한 것 같습니다. MATLAB 툴박스도 있지만 자동화가 되어 있지 않아서 이미지를 여러 장 사용하려면 불편합니다.

      Delete
  28. 안녕하세요 다시질문드립니다.
    키넥트 퓨전에서 나온영상에서와같이 3차원값들을 이용해 이제 다른 위치와 각도에서

    찍은 영상들을 정합을 하려고하는데요

    여러가지 방식들이 있네요 이차원이미지를 이용하는것도 있고 삼차원정보로 이용하는것도 있던데

    정합하기에 가장적합한 방식의 논문을 알수있을까요?

    그리고 이번에 릴리즈된 키넥트 퓨전 툴킷을 사용하고싶은데 제가 아직은 초보라 코드를 봐도
    모르는 함수가 너무많더라구요 어떤 것들을 알아야 해석이 가능해질까요?
    d3d라고 써있던데 이것도 일종에 opengl같은 라이브러리인가요? 이것말고도 더알아야되는것이
    있으면 알려주시면 감사하겟습니다.

    ReplyDelete
    Replies
    1. 가장 적합한 방법이란게 어떤 결과를 원하느냐에 따라 달라지기 때문에 뭐라 말씀드리긴 어렵습니다. 키넥트 같은 카메라를 사용한다면 영상+깊이 정보를 함께 사용하는 게 일반적이지 않나 싶습니다.

      d3d 는 MS 의 DirectX 구성요소들 중 3D 렌더링을 담당하는 Direct3D 라이브러리에 쓰이는 접두어입니다. OpenGL 은 범용으로 맥/리눅스/윈도 등에 사용할 수 있기 때문에 학계에서 널리 쓰이고 있습니다. 반면 D3D 는 윈도에서만 사용이 가능하기 때문에 윈도 전용 애플리케이션이나 게임 등에 주로 쓰이고 있습니다.

      Delete
  29. Hi,
    I'm trying to test the calibration of my Kinect with the GML tool. What I do is repeat the calibration of the RGB cam with different images, taken from different positions. I'm obtaining different results of camera matrix and distortion.. is it correct? They shouldn't be equal? I don't understand if I'm making some mistake...
    Thanks

    ReplyDelete
  30. Hi, I'm trying to do kinect ir and color calibration also. How do you display the color-mapped depth image? Thank you.

    ReplyDelete
    Replies
    1. I just display color pixels from RGB image corresponding to the depth image pixels.

      Delete
    2. when you capture images for calibration do you save those images on a folder and then use those images for calibration?

      Delete
  31. 안녕하세요 영상공부를 하고있는 대학생입니다.
    우선 좋은 포스팅 감사드립니다.
    저는 RGB 와 Depth영상을 이용해서 영상처리를 하려고 하는데 여기에 alignment된 depth image가 필요해서 직접 구현을 해보려고합니다.
    그런데 막히는부분이 있어서 질문드립니다.
    현재 GML tool을 이용해서 kinect 각 카메라의 intrinsic parameter를 얻는데까지 진행했는데요.

    1. Extrinsic parameter를 그냥 R은 3x3 단위행렬, t는 [25 0 0]^T 로 가정해도 될까요??

    2. p_ir 값을 구할 때, x,y는 depth영상의 픽셀위치로 했는데 z값을 어떻게 해야할지 모르겠습니다. 그냥 0 이나 1로 줘도 될지 아니면 댓글에서 언급하신대로 depth intensity-to-distance 보정을 해서 distance 값을 넣어줘야 하나요??

    답변해주시면 정말 감사하겠습니다.

    ReplyDelete
    Replies
    1. 1. depth 카메라를 어떤 걸 사용하시는지 모르겠습니다만, 키넥트처럼 두 카메라가 평행하게 위치하고 있고 렌즈 사이의 거리가 25로 측정되었다면 캘리브레이션 한 것과 유사한 효과를 볼 수는 있겠지만 정확한 값이 아니니 사용하고 싶은 분야에 따라 가/부를 결정해야 합니다.

      2. p_ir 의 z 값은 depth 영상의 값을 어떻게 metric 단위로 변환하느냐에 달려있는 것입니다. 키넥트의 경우 개발자들이 변환식을 제공하는 것들이 있으니 찾아보시구요. 아니라면 depth intensity-to-distance 보정이 필요합니다. Depth 카메라에 따라서는 SDK 자체에서 변환식을 제공하는 것도 있고, 아니면 그냥 바로 metric 값을 float 타입으로 값을 제공하는 것도 있습니다.

      Delete
  32. Hi,

    I'm trying to calibrate both Kinect depth camera and colour camera. The problem is I'm not sure of the image acquisition for depth camera. Block the IR emitter and run following code still?
    capture.retrieve( depthMap, CAP_OPENNI_DEPTH_MAP );
    By doing blocking and so, the depth map is totally black. I think I misunderstand your idea.
    Could you help me to make it clear?

    ReplyDelete
  33. Thanks for your great work. Recently, I do a work about calibrating Kinect color-depth cameras. I have followed steps you wrote, unfortunately, I got a weird result. The result depth map in the RGB camera coordinate system is divided into two parts, the left half and the right half,and two parts are same. I have checked my code again and again, but I don't find where is wrong. Have you ever met such problem? I look forward to your reply, thanks again.

    ReplyDelete
  34. There is one question: how do you make sure that the calculated parameters p_rgb(x,y) do not go beyond the range[480,640]? I find there are some x axis p_rgb_x are greater than 480, so the operation result(p_rgb_x,p_rgb_y) = Z axis of P_rgb is wrong, The error message is : Microsoft C++ exception : cv::Exception at memory location 0x0089f860. Can you tell me why?

    ReplyDelete