CG: Perspective Projection

HCI 과제 덕에 심심찮게 프로그래밍을 하게 되네요. 첫 과제 였던 3D rotation 관련을 구현하는 것도 상당히 흥미로웠지만, 두번째 과제인 Perspective Projection 를 구현하는 것은 정말 멋진 경험이었다고 생각합니다.

지난 며칠간 꽤나 재밌게 프로그래밍을 했던 관계로 블로그에도 살짝 정리해보는게 어떨까 하는 생각이 들었는데, 막상 쓸려니 내용이 잘 전해질지 의문이네요.

What is the Perspective Projection?

Perspective Projection 이란 아래의 왼쪽 이미지를 오른쪽 이미지 처럼 변화시키는 것을 얘기합니다. 꼭 저렇게 비뚜러진 이미지를 바로잡는것은 아니고, 이미지가 투영되는 면을 변화시키는 것이라고 생각하시면 됩니다.

이해를 돕기 위해 wikipedia 에서 이미지를 하나 가져왔습니다. 아래 이미지의 연보라색 면이 상이 맺히는 곳이라고 할 때, perspective transform 은 그 보라색 면을 이동시킨 것 같은 효과를 주기 위해 사용합니다.

How to get a projection matrix.

기본 적으로 Perspective Transform 을 위한 식은 다음과 같습니다.

homogenious coordinate 를 사용하고 있으니 x’ 와 y’ 에 관한 식은 아래와 같이 바꿔쓸 수 있습니다.

이를 정리하면 다음과 같은 꼴로 만들 수 있고,

우리가 값을 알고 싶은 변수들은 a, b, c, d, e, f, g, h 이렇게 8 개이므로, (x, y) 와 그에 대응되는 (x’, y’) 쌍을 4개만 알고 있으면 projection matrix 를 구할 수 있습니다. 이를 구하기 위한 매트릭스는 아래와 같습니다.

남은 건 8×8 matrix 의 inverse matrix 를 구한 뒤 뒤 쪽의 매트릭스에 곱해주는 것 뿐이군요.

Implementation of Perspective projection

이제까지 Perspective Transform 을 위한 매트릭스에 대해 알아봤습니다. 이제는 실제 구현을 해보는 것만 남았네요. 위에서 알아봤듯이 Perspective matrix 를 구하려면 matrix multiplication 과 inverse 를 위한 인터페이스가 필요합니다.

matrix multiplication 의 경우 서로 곱할 수 있는 형식인지를 체크한 뒤 단순한 계산을 하면 되고, inverse 는 gauss elimination 을 이용 reduced row echelon form 으로 만들어주는 것을 통해 쉽게(?) 구해낼 수 있습니다.

위의 두 가지까지 구현했다면, 이제 warping 만을 구현하면 되겠습니다. 이 warping 은 크게 두가지 방법을 통해 구현할 수 있습니다.

forward mapping

forward mapping 은 말 그대로 src 의 x, y 좌표에 대하 dst 의 x’, y’ 를 계산 한 뒤 값을 채워주는 방식입니다. 간단히 pseudo code 로 표현하면 다음과 같이 표현할 수 있겠네요.

근데 막상 구현을 해놓고 보면 pixel 이 정수단위이기 때문에 아래와 같이 hole 이 발생하는 것을 확인할 수 있습니다.

backward mapping

위에서 얘기한 hole 을 방지하기 위한 방법 중 하나로 backward warping 이란 것이 있습니다. forward warping 에서 src 의 좌표를 기준으로 dst 의 좌표를 계산했다면, backward warping 에서는 dst 의 좌표를 기준으로 src 의 좌표를 계산하게 됩니다.
간단하게 pseudo code 로 표현하면 아래와 같이 되겠습니다.

간단히 코드만 봐도 예상할 수 있겠지만 backward_warping 을 해주게 되면 hole 은 확실하게 없앨 수 있습니다. 결과 이미지는 아래와 같은데, 아주 깔끔한 결과가 나오지는 않았습니다.

forward (or backward) warping with interpolation

forward warping 을 하게 되면 hole 이 생기게 되고, 단순한 backward warping 을 하게 되면 이미지의 화질 저하가 발생하게 되는데, interpolation 을 사용하게 되면 이를 조금 더 개선할 수 있습니다.

전 linear-interpolation 을 사용해보았는데, 설명하기는 복잡하니 관심있으신 분은 저 아래 첨부할 소스를 참고해보시면 좋겠습니다. 결과는 아래와 같이 나옵니다.

우선 interpolation 을 이용한 forward warping 입니다. 복잡하게 하기는 귀찮고 해서 대강 구현했더니, hole 이 줄기는 했지만 여전히 존재하고 있습니다.

다음은 backward warping 에 linear interpolation 을 적용한 결과입니다. hole 도 없고, 보기에 상당히 괜찮아진 것을 확인할 수 있습니다.

소스코드:
https://github.com/Tee0125/snippet/tree/master/perspective_projection
참고자료:
http://en.wikipedia.org/wiki/Perspective_%28graphical%29
http://en.wikipedia.org/wiki/Gaussian_elimination
p.s) 부동 소숫점 연산에서 x – x/x*x = 0 이라는 것이 보장되질 않더군요. 코드 한 줄 줄일려다가 디버깅을 30분동안 해야했습니다. -_ㅜ

Similar Posts:

Facebooktwitterlinkedinmail

25 thoughts on “CG: Perspective Projection”

  1. 오! 멋있기는 한데,
    How to get a projection matrix. 이거 나오는 순간부터 스크롤이 주우욱;
    그나저나, 대체 제게 맞겨둔 소스는 언제 찾아가시렵니까아아아?(제목을 보니, 이거 구현소스 인듯 한데..)

  2. 어제 치과 갔다와서 밤늦게까지 뻗어잤더니 새벽에 일어났는데, 안보이시길래 그냥 학교 컴퓨터에 접속해서 메일로 쐈어요~ 키킥

  3. 안녕하세요! 좋은 글 잘 보았습니다.
    제가, 저 소스를 자바로 포팅해보았는데, 이것을 다시 제 블로그에 포스팅 해도 될까요??

  4. 어… 백워드 와핑할때 역행렬 구해서 해야되지 않나요? 그냥 포워드 와핑에서 썼던 행렬 똑같이 써도 되요?? 안될것 같은데?

    1. 앗 맞습니다. 지적해주신 것처럼 inverse matrix를 계산해서 사용해야 하는 것이 맞습니다. 소스를 보면 해당 사항이 반영되어 있는데… 본문 상에는 해당 내용이 제대로 반영되어 있지 않네요. 언제 시간나면 수정해두도록 하겠습니다. 🙂

  5. 문의 드리고 싶은것이 있는데요. 사용하신 예제를 돌려보면 문 손잡이가 이상하게 표현이 되는데요, 그정도로 회전히키면 제대로 표현되어야 될것 같은데.안되있어서요. 어떻게 이해를 해야 잘 모르겠습니다.

    1. 어떤 이미지를 이용해서 테스트하셨는지 모르기 때문에 어떤 상황인지 전혀 감을 잡을 수가 없네요.
      예측해보자면 depth(z축 정보)를 무시하고 있기 때문에 왜곡되는 상황이 아닐까 싶습니다.

      1. 사용한 예제는 정태영님이 링크를 해놓으시은 파일을 이용하였고 다른부분은 전혀건들이지 않고 진행했는데요 무고리 손잡이부분이 이해가 안가서요 ~.^ z축이 문제라면 다른 부분도 영상이 이상해야 하는것 아닌가요?

      2. 아 한가지 더 궁금한것은 만약 z축이 왜곡이 있다고 가정이되면 z축 변환은 어떻게 적용을 해야 할까요?

        1. 대게 z-축에 대한 정보를 depth information이라고 부르는데요.
          우선 소스 이미지도 intensity(x,y) 외에 depth(x,y) 정보를 함께 가지고 있어야 왜곡 없는 변환이 가능하고, 이 때는 homogenous 좌표계를 (x, y, 1)이 아니라 (x, y, z, 1)로 써서 수식을 풀면 됩니다.
          C’ = P C, where C’ = (wx’, wy’, wz’, w), P = (perspective matrix), C = (x, y, z, 1)
          perspective matrix는 4×4 matrix로 확장하면 되고, 결과를 2d로 보여주기 위해서 wz’를 target depth 값으로 고정시킨 다음 위에서 했던 것을 응용해보시면 되는데요.
          이 경우 (손잡이에 의해 가려져 있던 영역처럼) 소스 이미지에서는 가려져 있던 위치를 타겟 이미지에서는 보여줘야 할 수 있는 상황이 있을 수 있고, 흔히 이로 인한 artifact를 hole이라고 부릅니다.

          1. 답변 감사드립니다.
            마지막으로 하나더 여쭈어보고 싶은것이 있습니다.
            코드에서 Gaussian Elimination을 하실때 이해가 가지 않는 부분이 있는데요.
            Inverse matrix를 진행하면 upper triangle 쪽에 값들은 0이 안되도 상관이 없는건가요?
            기본적으로 I를 곱해서 역행렬을 얻는 방식을 사용하셨는데요 실제 돌려보면 low쪽은 0가 되지만 upper쪽은 0가 아닌 값들로 가득 차있어서요.
            예를들자면..
            1 8 4
            0 1 7
            0 0 1
            이와같이 메모리에 저장이되는것 같은데요 일부러 이렇게 하신건지. 아니면 오류인지 의도를 파악 못하겠습니다.

  6. 안녕하세요 워핑 공부중인데
    혹시 코드좀 구할수 있을까요?
    감사합니다.

  7. backward mapping에서
    (ax’+by’+c) / (gx’+hy’+1); 인가요?
    (ax’+by’+c) / (gx’+hy’+i); 인가요?

    1. 코멘트가 스팸으로 빠져있는걸 이제 봤군요. ㅠ.ㅠ 죄송합니다.

      (x, y, scale) 식으로 표현하는걸 homogeneous coordinate라고 부르는데요. scale이 1인 상태라서 1이 맞습니다.

  8. Perspective transform을 개발하고 debugging 진행 중인데 이 post를 보고 많은 도움이 되었습니다.
    같은 input image를 사용하여 테스트 해보고 싶은데 혹시 실례가 안된다면 input image도 공유가 가능할지 문의드립니다.
    source code 상에 define 된 raw 파일을 찾을수가 없네요.
    감사합니다.

  9. 감사합니다. 4점 보정 공식 찾다가 왔는데 너무 깔끔하게 잘 되어 있네요.
    소스 코드도 있고 감사합니다.

Leave a Reply