Script / CSS

G1sUtil.js

G1sBlogger.js

G1sNavigationList.js

G1sCode

G1sTagList

Posts List

2012년 3월 21일 수요일

[잉여모드] 단순 Image Blending 실험.

검색 중에 우연히 발견한 블로그에서 Image Blending에 관한 글을 보고는 한번 재미삼아 HTML5 Canvas를 이용해 구현해 봤습니다.
따로 논문을 읽고 한 것은 아니고, 어떻게 하면 마스크 이미지 없이 자연스러운 합성 효과를 얻을 수 있는 편법이 없을까... 라는 것이 주요 고민.
가장 기본이 되는 법칙은 위 블로그에도 나와 있듯이

1. 배경과 만나는 부분은 배경과 같은 색을 사용한다.
2. 배경과 만나지 않은 부분은 최대한 색상차가 나지 않도록 메운다.


입니다.
사용한 이미지는 Image Blending에서 자주 사용하는 아래 두 이미지.


가장 먼저 사용한 편법은 정직하게, 외곽은 배경이미지 그대로 칠하고, 그 안쪽은 외곽색과의 차이를 얻어서 이전 색에 더해주는 방법.
dx = src[i][j] - src[i][j-1];
dy = src[i][j] - src[i-1][j];

result[i][j] = ((result[i][j-1] * dx) + (result[i-1][j] * dy))/2;
간단하게 좌측 상단에서 시작하는 것만 해 봤는데 보는데로 자연스러운 효과는 좋은 것 같으나 시작부분이 잘못되면 엉뚱한 결과가 나오는 것을 발견.
거기다 가운데 어두운 부분을 통과하면 잘 나오던 부분도 엉뚱한 결과가 나오는 군요.
탐색 시작을 사각 네 귀퉁이에서 시작하면 좀 더 나은 결과가 나올 수도 있지만 일단 이 방법은 보류.


다음 방법은 같은 x,y외곽 점을 기준으로 기준점과 현재 점의 차이를 얻어, 그 차이를 배경에 더해주는 방법.
top = src[i][0] - src[i][j];
bottom = src[i][h] - src[i][j];
left = src[0][j] - src[i][j];
right = src[w][j] - src[i][j];

result[i][j] = back[i][j] + (top*((h-j)/h) + bottom*(j/h))/2 + (left*((w-i)/w) + right*(i/w))/2;
외곽색의 차이에 따라 새로 붙인 이미지에 가로 혹은 세로의 줄이 가고, 외곽부분이 매끄럽지 않은 현상이 발견되네요.


다음 방법은 아예 고정점을 기준으로 잡고 해당 고정점과의 차이를 얻어, 그 차이를 배경에 더해주는 방법입니다.
tl = src[0][0] - src[i][j];
tr = src[w][0] - src[i][j];
bl = src[0][h] - src[i][j];
br = src[w][h] - src[i][j];

result[i][j] = back[i][j] + (tl*((h-j)/h)*((w-i)/w) + tr*((h-j)/h)*(i/w) + bl*(j/h)*((w-i)/w) + br*(j/h)*(i/w));
확실히 2번째보다 줄무늬도 없고 자연스러워졌지만 기준점으로 잡은 고정점과 차이가 많이나는 외곽부분의 매끄럽지 않은 현상이 더욱 두드러지는 군요.


다음 방법은 단순히 외곽일수록 배경색을 칠하고 내부일 수록 소스이미지의 색을 칠하는 방법.
a = ((h-i)/h)*(i/h)*((w-j)/w)*(j/w) * 16;

result[i][j] = back[i][j]*(1-a) + src[i][j]*a;
연결은 자연스럽지만 물색이 티가 나게 바뀌는 것을 알 수 있습니다.


간단히 생각나는 것은 모두 해봤는데요. 만족할 만한 성과는 없군요.
그렇다면 이게 끝이냐... 하면. 그것은 아니죠.
성질이 약간 다른 1번을 제외한 2,3,4번을 간단하게 혼합해 봅니다.
top = src[i][0] - src[i][j];
bottom = src[i][h] - src[i][j];
left = src[0][j] - src[i][j];
right = src[w][j] - src[i][j];

tl = src[0][0] - src[i][j];
tr = src[w][0] - src[i][j];
bl = src[0][h] - src[i][j];
br = src[w][h] - src[i][j];

result[i][j] = back[i][j] 
    + ((top*((h-j)/h) + bottom*(j/h))/2 + (left*((w-i)/w) + right*(i/w))/2
    +  (tl*((h-j)/h)*((w-i)/w) + tr*((h-j)/h)*(i/w) + bl*(j/h)*((w-i)/w) + br*(j/h)*(i/w)))/2;

a = ((h-i)/h)*(i/h)*((w-j)/w)*(j/w) * 16;

result[i][j] = back[i][j]*(1-a) + result[i][j]*a;
100%라고는 못하겠지만 꽤 만족스러운 결과가 나왔습니다.


어느정도 효과는 얻었지만 완벽한 것은 아니겠죠. 자세히 보면 부자연스러운 부분도 보이고, 합성하고자하는 물체가 외곽으로 접해있다면 지워지는 결과가 나올 수도 있을 것입니다.
2,3,4번 외에 1번은 효율적으로 적용하면 더욱 뛰어난 결과가 나올 수도 있을 것 같구요.
아무튼 이번 시도는 여기까지.
다음에 기회가 닿는다면 논문도 살펴보고 좀더 전문적으로 접근 해 봐야겠습니다.

2012.4.3. updated
이전에 결과가 만족스럽지 않아 다른 방법을 생각해 보던 중 이번에는 좀 더 만족스러울만한 방법을 찾아 냈습니다.
방법은 1번 방법을 응요한 것이구요. 이때 모든 값을 이전 점을 기준으로 해서 변환하는 것이 아닌 배경과 일정 값 이상이 차이 날때만 주변 점들과의 차이만큼 더해주도록 하였습니다.
top = src[i][0] - src[i][j];
if(Math.abc(src[i][0]-src[i][j])< criterion) {
    result[i][j] = back[i][j];
}
else {
    dx = src[i][j] - src[i][j-1];
    dy = src[i][j] - src[i-1][j];

    result[i][j] = ((result[i][j-1] * dx) + (result[i-1][j] * dy))/2;
}
결과는 꽤 만족스럽습니다. 따로 논문등은 찾아보지 않았지만 생각나는 대로 간단히 구현한 것에서는 꽤 괜찮게 나온걸로 보입니다.

결과를 확인하고 싶으신 분은 아래서 TEST가 가능합니다.

이곳에 소스 파일을 드랍해 주세요...

이곳에 배경 파일을 드랍해 주세요...

아래 Canvas에서 Mouse Click & Drag로 소스 이미지의 위치를 조정 할 수 있습니다.

1. 인접한 점과의 색 차이

2. 가로세로 외곽 점과의 색 차이

3. 고정 점과의 색 차이.

4. 외부와 내부의 정도

5. 2,3,4 혼합

6. 배경과 값 차이에 따른 분기

댓글 없음:

댓글 쓰기