임시 블로그 이름

이미지 워핑 (Image Warping) 본문

엔지니어링

이미지 워핑 (Image Warping)

paeton 2012. 4. 26. 19:49

서론



이미지 워핑이라는것은 쉽게 말해, 영상을 이렇게 찌그러트리는 기술이다.





[그림 1] (좌) 원본 이미지 256x256 격자 이미지, (우) 워핑을 통해서 찌그러진 이미지




이쪽으로 유명한 책은 Randy Crane의 책이다. 워낙 유명한 책이다보니 한국어 번역판도 있다. C로 짜여진 소스코드를 공개 해서, 어떻게 실제로 구현해야 하는지 잘 설명하고 있다.

영문판: A Simplified Approach to Image Processing: Classical and Modern Techniques in C

한글판: 영상처리 이론과 실제


또, 이미지 워핑/몰핑의 대가인 Wolberg의 Digital Image Warping이란 책도 매우 유명하다. 다양한 예시와 함께, 실제로 영화나 공학쪽에서 어떠한 상황에 이런 워핑/몰핑이 적용되었는지 알 수 있다. 

영문판: Digital Image Warping


프린스턴 대학교의 Thomas Funkhouser가 만든 PDF자료도 있다. 공개된 자료이니 차근차근 읽어보자.

주로 그림으로 매우 쉽게 설명해 놓았다.

PDF: Image Warping - Thomas Funkhouser, Princeton University.





위의 자료들을 참고하면서 이 글을 읽으면 좀 더 쉽게 이해할 수 있을것이다.

(왜냐하면 나는 짧은 지식으로 두서 없이 막 쓰니까 ㅠㅠ)





원래 이미지 워핑은, 우주 망원경에서 나타나는 영상 외곡을 해결하기 위해서 개발되었다가, 영화에 특수효과로 쓰이면서 많이 알려지게 되었다..... 고 어디서 들은것 같다. (확실하지 않다 ㅋㅋㅋ)


이미지 워핑과 몰핑(Morphing)이 있는데 두 차이는 다음과 같다.


워핑은 원래 이미지의 픽셀의 위치만 바꿔주는거다. 즉 이미지의 형태만 바뀌는거다.


몰핑은 워핑효과와 함께, 한 이미지에서 다른 이미지로 변하는거다. 옛날 괴수 영화, 특히 구미호 영화를 보면 자주 나온다. 여자의 얼굴이 점점점 코가 길어지면서 여우로 변한다던가 하는게 몰핑이다.







조지부시에서 오바마로 변하는 이미지 몰핑의 한 예.

출처는 여기 -> http://paulbakaus.com/wp-content/uploads/2009/10/bush-obama-morphing.jpg




일단 몰핑은 제쳐두고, 워핑에 대해서만 이야기 해 보자. 어차피 몰핑은 워핑에다가 몇가지를 더한것이다.




본 포스트에서는 최대한 쉽고 간단하게 원리를 설명하고, MATLAB을 이용해서 가장 쉽고 간단한 방법으로 구현하는 방법에 대해서 이야기 하겠다. (복잡한 내용은 내가 잘 알지도 못할 뿐 더러, 잘 설명할 자신이 없다 ㅠㅠ)




원리


최대한 수식을 안쓰고 쉽게 이야기하고 싶은데, 우짤 수 없이 써야 한다. 최대한 쉽게 써보겠다.




어떤 이미지, I가 있다고 할때, 이 I안에 (x,y) 좌표에 있는 픽셀을


I(x,y)


라고 하자. 그러면 이 픽셀을 미리 지정된 위치변환함수 Ux(x,y)와, Uy(x,y)의해서 옮겨주면 그 결과는


I( Ux(x,y), Uy(x,y) )


가 된다. Ux(x,y)는 x방향의 위치변환을 나타내고, Uy(x,y)는 y방향의 위치변환을 나타낸다.


이러한 작업을 모든 픽셀에 대해서 해 주면, 이게 워핑이다.



한마디로 말해서, 한 이미지의 픽셀들을, 미리 사용자가 정한 위치변환 규칙에 의해서 다른 위치로 옮겨주는것이다.




위의 내용에 따라 이미지 워핑을 구현하려면 두가지 단계가 필요하다.


1. 위치변환함수 Ux(x,y)와, Uy(x,y)를 만든다.

2. 1에서 만든 위치변환함수를 이용해서 실제로 픽셀을 옮긴다.




* 단순한 Affine Transform (새로운 개념을 꺼내서 설명해서 미안하다. Affine Transform은 쉽게 말해 단순한 변환이다. 상하좌우 이동, 확대, 축소, 기울이기, 회전하기 등이다. 쉽게 말해, 위의 위치변환함수를 매우 단순한 행렬로 표시할 수 있는 위치변환이다.)이라면 변환함수를 간단하게 만들어낼 수 있겠지만, 맨 위에 있는 여자의 그림처럼 영상의 각 부분이 서로 다르게 축소되고 확대 되고 이동하는 이러한 움직임은 단순한 행렬로 나타낼수 없다.

(내가 써놓고도 어렵다.... 미안 ㅠㅠ)





1) 위치 변환함수 만들기


위치변환함수를 만드는데는 언제나 그렇듯 여러가지 방법이 있으나, 여기서는 콘트롤 포인트 (control point)들을 움직여서 위치변환 함수를 만드는 방법에 대해서 이야기 해 보겠다.


다시 아래 아까 격자 이미지를 보자


녹색 원형 점들을 볼 수 있는데 이것이 콘트롤 포인트 이다. 왼쪽 이미지에 있는 콘트롤 포인트들은 일정한 간격으로 배열되어 있고, 오른쪽 영상에 있는 콘트롤 포인트 들은 이리저리 옮겨져 있는걸 알수 있다.


자세히 두 영상을 비교해 보면, 오늘쪽에 찌그러진 영상의 형태가 콘트롤 포인트들의 위치와 관련이 있다는 것을 알 수 있다.


쉽게 말하면, 사람이 일일이 모든 픽셀에 대해서 위치 변환함수를 만들려면 엄청난 노가다이므로, 각 구역별로 대표 포인트를 정해서, 그 포인트의 움직임을 이용해서 나머지 픽셀들의 위치 변환함수를 만드는 것이 이 콘트롤 포인트를 이용한 위치변환함수 만들기의 기본 아이디어이다.




[그림 1]


콘트롤 포인트의 개수와 위치는 제한이 없으나, 그 개수와 위치에 따라서 최종 결과 이미지에 영향을 준다.


일단 이 글에서는 저렇게 영상에 일정한 간격으로 콘트롤 포인트를 설정한 것을 전제로 하겠다.


또, 콘트롤 포인트를 몇개 설정하는지는 전적으로 사람 마음이고, 언제나 그렇듯이 다른 요소들과 tradeoff 관계(어느 한쪽을 좋게 하면 다른 한쪽, 또는 여럿이 안좋아지는 관계. 예)... 적절한 예시는 나중에 업데이트 )에 있다.


예를 들면, 콘트롤 포인트가 많아진다는 것은 그만큼 세밀하게 워핑의 방향과 정도를 조절할 수 있다는 뜻이기도 하지만, 그만큼 조절해야될 변수들이 많아진다는 것을 의미하고, 이것은 그 프로그램의 복잡성(complexity)가 높아진다는 뜻이기도 하다.


또한, 알고리즘의 안정성(stability)에도 영향을 준다.


반대로, 콘트롤 포인트의 개수가 적다면, 조절해야 될 변수도 적어지지만, 세밀한 워핑 정도의 콘트롤은 되지 않는다.



그러면 어떻게 설정해야 하나?


적.당.히. 하면 된다. (이게 젤 어렵고, 그래서 공돌이든 누구든 철학이 필요한것 같다. 하나를 선택하면 다른 하나를 포기해 하는 상황, 이런 상황의 선택에 영향을 미치는것이 가치관/철학/등등등 이 아닐까?  ㅋㅋㅋ)






위의 [그림 1] 에서 따로 녹색 원으로 표시된 콘트롤 포인트만 빼내서 그림을 그리고, 그 위치의 차이를 표시하면 다음과 같다. 그냥 내 마음대로 가로 5 세로 5개씩 잡았다. 더 많이 잡아도, 더 적게 잡아도 상관 없다.


[그림 2] (왼쪽) 초기 콘트롤 포인트, (가운데) 움직임에 의해서 위치가 변경된 콘트롤 포인트 , (오른쪽) 움직임을 벡터로 표현 함(파란색 화살표)



위치의 차이를 벡터로 나타는 것을 모션 벡터 (Motion Vector)라고 하자. 2차원 영역에서 벡터는 모두 x축과 y축 성분 두가지로 분리가 가능하다.


x축 방향의 성분을 Vx라고 하고 y축 방향의 성분을 Vy라고 하자. 그러면 Vx와 Vy는 각각 5x5 행렬이 된다. 위의 그림에 나와있는 Vx와 Vy는 매틀랩의 randn 함수를 이용해서 임의로 만든 것이다. 맨 바깥에 있는 콘트롤 포인트 들은 움직이지 않고 안쪽에 있는 포인트 들만 옮겼다. Vx와 Vy는 다음과 같이 만들 수 있다.


Vx = padarray( randn([3 3]), [1, 1]);

Vy = padarray( randn([3 3]), [1, 1]);



이 Vx와 Vy를 이용해서 위에 수식에 있는 Ux와 Uy를 만들어주면 된다. 위의 수식을 보면 알겠지만, Ux와 Uy는 모든 이미지의 위치에 대해서 값을 가져야 한다. 즉, 5x5행렬인 Vx, Vy를 이용해서, 위의 이미지 사이즈와 같은 256x256 행렬인 Ux와 Uy를 만들어 주는 것이다.


여기에는 원래 아주 심오하고 복잡한 수학적인 백그라운드가 있지만, 이 글에서는 단순한 워핑의 원리를 말하고자 하는것이므로, 매우 간단한 방법을 쓰도록 하겠다. 보간(Interpolation)이다. 위의 Vx, Vy를 보간을 이용해서 크기만 256x256으로 만들어 주자.


매틀랩으로는 interp2 함수를 써서 다음과 같이 표현하면 된다.


[x1, y1] = meshgrid( linspace(1,256,5), linspace(1,256,5));

[x2, y2] = meshgrid( linspace(1,256,256), linspace(1,256,256));

Ux = interp2( x1, y1, Vx, x2, y2 );

Uy = interp2( x1, y1, Vy, x2, y2 );


이렇게 해서, 256x256 행렬들인 Ux와 Uy가 만들 수 있다. interp2 함수는 저렇게 기본적으로 사용하면 Vx와 Vy를 선형 보간 (linear interpolation)해서 Ux와 Uy를 만들어준다.




2) 위치 변환함수를 이용해서 실제로 픽셀 옮기기


이것도, 우의 Ux와 Uy를 만든것 처럼, 원래는 매우 심오하고 복잡한 수학적 백그라운드가 있다. 하지만, 마찬가지로 여기서는 기본적인 원리를 말하고자 하는것이기 때문에 복잡한 이야기는 하지 않겠다. 복잡한 이야기는 위의 참고문헌들을 읽어보면 좋겠다. 


실제로 픽셀을 옮기는 것 역시 보간을 이용해서 수행되어야 하고, 이것은 마찬가지로 위의 interp2 함수를 이용해서 수행 가능하다.



매우 간단하다 코드 한줄로 끝난다.



Iwarped = interp2( x2, y2, I, x2 - Ux, y2 - Uy );


위의 코드도 역시 선형보간을 이용한다. 좀더 부드러운 영상을 얻고 싶다면 끝에 'spline'옵션을 주면 된다. 스플라인 보간을 이용하기 때문에 더 부드러운 영상이 나오게 된다.






마지막으로 매틀랩 코드를 첨부한다. 분석해 보고, 요리조리 바꿔보고 자기것으로 만들고, 그리고 관심이 있으면 더 파보자.



imagewarping.m






위의 내용은 정말 이것저것 다 빼고 매우 간단하게, 이미지 위핑이라는 것이 어떤것인지 설명하고, 대강 어떻게 구현하는지에 대해서 쓴 것이다.


이 글을 읽고 '아 대강 이게 이런거구나~' 해준다면 매우 고맙겠다.


이 내용을 주제로 연구를 한다거나, 연구에 사용한다거나 한다면, 위의 참고 서적들을 꼭 보기를 추천한다. 군데군데 수학적인 이야기들을 안하고 그냥 넘어갔는데, 사실 이것들은 이렇게 코드로 짜는 것 보다도 매우 중요한 내용들이 있다.


퐈이튕 하자.






Comments