구가 2D Image에 프로젝션 됬을때 반지름 픽셀.

조회수 537회

3차원 구가 2D Image에서는 원으로 투영되는 것으로 알고 있습니다. 물론 완전한 원은 아니고 카메라의 성능에 따라 원에 가까워지는 것으로 알고 있습니다.

그래서 원의 반지름 픽셀을 가지고 카메라와 상대적인 Z좌표를 구할수 있지 않을까라는 생각이 들어 확인해보고 있었는데 실제 실행해본 결과가 이론과 대치되서 질문드립니다.

ios Scenekit에서 Sphere와 Camera를 만들어 Test 하였습니다.

  • Sphere World Coordinate : (0, 0, 0)
  • Sphere Radius : 0.1
  • Camera World Position : (0, 0, 0.3)
  • Camera Fovy : 45 degree
  • 2D Image 해상도 : 2224 * 1668

기준이고 공식은 stack overflow를 참고하였습니다.

// Z  : Camera Coordinate Z Distance
// Clip Space 기준 아마 Pixel = clip radius * Resolution.y
approximate radius on screen[CLIP SPACE] = world radius * cot(fov / 2) / Z

그런데 계산한 픽셀과 실제 이미지에서의 원의 픽셀이 다른 현상이 있습니다.

계산한 픽셀은 약 671 pixel이나오고 실제 이미지에서의 원 반지름 픽셀은 약 712 pixel 정도 나오고 있습니다. 이 상황에서 Z 값을 0.3이라고 생각하고 계산하였는데 그게 잘못인건지 아니면 뭔가 놓치고 있는 부분이 있는건지 모르겠습니다.

카메라쪽 수학 전문가이신분들이 보기에 제가 뭔가 빠뜨린 부분이 있나요??

이미지

심지어 저는 Scenekit에서 제공하는 3d point가 image에 어느 2d point에 맻히는지 계산해주는 함수를 사용하여 (0, 0, 0) 그리고 보이는 원의 끝 (0, 0.1, 0)이 2d의 어느 점에 맻히는지 두 차이를 계산한 픽셀수가 저 위에 계산식으로 계산한 픽셀수와 같은 것을 확인하였습니다. 하지만 실제 이미지에서의 원의 픽셀수와 차이가 나니 너무 의문입니다...

1 답변

  • 좋아요

    3

    싫어요
    채택 취소하기

    일단 fov가 있다는건 원근 투영인거고, view frustum이 어떤지, viewport와 near z값 혹은 focal length 등등이 있어야 정확한 계산이 가능할듯 싶지만... 일단 기본값을 대충 유추해 보고 오류를 잡아 보자면,

    현재 구한 671은 뷰포트에 맺힌 상(원)의 반지름이 아닙니다.

    링크주신 스택오버플로의 답변중에 나와 있는 그림에서 이미지

    빨간 선에 해당하는 부분(구의 반지름에 해당)의 길이를 구한것처럼 보입니다.

    (정확한건 아닙니다만, 그래 보입니다.)

    실제로 상은 z가 0인 평면에 맺힌다고 가정했을 때, 이미지

    위의 그림 처럼 평면에 맺힌 상의 길이를 구해야 합니다.

    카메라와 뷰포트의 모든 factor를 알 수 없고 뭔가 애매하게 알려주신 부분이 있기에 처음부터 구할 수는 없지만,

    671이란 값이 첫 번째 그림의 길이를 구한게 맞다는 가정 하에 검증을 해 볼 수 있습니다.

    계산의 편의를 위해 아래 그림처럼 기호를 매겨볼게요. 이미지

    상의 반지름의 길이는 삼각형의 닮음과 위대한 피타고라스 정리 및 삼각함수를 통해 구할 수 있습니다.

    OC = 0.3
    OH = 0.1
    CH = (0.3 ^ 2 - 0.1 ^ 2) ^ 0.5 = 0.282842712
    
    angle = OCH
    cos(angle) = CH / OC = 0.94280904
    

    닮음에 의해서

    OH / OR' = cos(angle)
    OR' = 0.1 / 0.94280904 = 0.106066017
    

    월드 좌표계상으로 0.106066017 위치의 점에 있는 값을 구해야 합니다.

    위에서 말한 Scenekit의 함수를 적용하려면 (0, 0.1, 0) 이 아닌 (0, 0.106066017, 0)을 넣어야 하는 것이죠.

    아무튼 검증을 위해서 계속 계산을 해보면,

    위의 값에 비례식을 적용할 수 있습니다.

    0.1 위치인 경우의 반지름 값이 671이라면, 0.106066017 위치인 경우의 반지름 값 X는?

    0.1: 671 = 0.106066017: X
    X = 671 * 0.106066017 / 0.1 = 711.70297407 = 약 712
    

    대략 712가 나옵니다. 이게 계산으로 구한 값이고 실제 보이는 원의 반지름과 거의 맞아 떨어지죠.

    이걸로 잘못된 값을 지정하여 구했다는 것이 확인 되었습니다.

    투영에 의해 2차원에 맺히는 상은 3차원 세계의 물체에 생기는 그림자를 생각해 보시면 됩니다. 점광원으로 부터 나온 빛이 구의 그림자를 어떻게 만들지 상상해 보시면 이해하기 좀 더 수월할거에요.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)