IMPLEMENT POISSON BLENDING

Toy problem

본 과제를 본격적으로 시작하기에 앞서 간단하게 이미지를 poisson blending을 활용하여 재구축하는 toy problem이다. 시작코드는 과제에서 주어진 starter.m을 사용하였으며 toy_reconstruct.m 파일에 toy problem 코드를 작성하였다.

여러개의 식을 single least square problem으로 풀기 위하여 아래 식을 생각하며 진행하였다.

(Avb)2...(5)(Av-b)^2 ...(5)

A는 sparse matrix, v는 결과 이미지 그리고 b는 known vector이다.

먼저 과제에서 주어진 힌트대로 im2var matrix과 앞선 식의 A와 b는 정의해준다.

im2var = zeros(imh, imw);
im2var(1:imh*imw) = 1:imh*imw;

A = sparse(imh*(imw-1)+imw*(imh-1)+1, imh*imw);
b = zeros(imh*(imw-1)+imw*(imh-1)+1, nn);
e = 1

과제에서 주어진 식 (2)에 맞게 식(4)의 형태로 구현해준다. 식 (3)도 마찬가지이다.

((v(x+1,y)v(x,y))(s(x+1,y)s(x,y)))2...(2)((v(x+1, y)-v(x,y))-(s(x+1,y)-s(x,y)))^2 ...(2)
for x = 1:imw-1
    for y = 1:imh
        A(e, im2var(y, x+1)) = 1;
        A(e, im2var(y, x)) = -1;
        b(e) = img(y, x+1) - img(y, x);
        e = e+1;
    end
end
((v(x,y+1)v(x,y))(s(x,y+1)s(x,y)))2...(3)((v(x, y+1)-v(x,y))-(s(x,y+1)-s(x,y)))^2 ...(3)
for x = 1:imw
    for y = 1:imh-1
        A(e, im2var(y+1, x)) =1;
        A(e, im2var(y, x)) = -1;
        b(e) = img(y+1, x) - img(y, x);
        e = e+1;
    end
end

마지막으로 과제에서 주어진 대로 식 (4)를 통해서 오리지널 이미지의 intensity 정보를 준다.

\ 연산자를 통해서 v를 구할 수 있다.

(v(1,1)s(1,1))2...(4)(v(1,1)-s(1,1))^2 ...(4)
A(e, im2var(1, 1)) = 1;
b(e) = img(1, 1);

v = A\b;
result = reshape(v, [imh, imw]);
Original image

Reconstructed image

Toy problem의 결과를 얼핏 보면 매우 원본 이미지와 매우 비슷하다.

하지만 이미지의 크기를 확대해보면 이미지의 경계가 약간 뭉게진 것을 확인할 수 있다.

다음은 starter.m 파일에서 이미지간의 차이를 확인하는 코드의 결과이다.

disp(['Error: ' num2str(sqrt(sum(toyim(:)-im_out(:))))])
% output : Error: 0+1.9223e-06i

Possion blending

Toy problem과 마찬가지로 starter.m을 사용하였으며 possion blending과 관련된 코드는 poissonBlend.m에 작성하였다. 2D descrete image에 적용하기 위하여 Laplace filter를 사용하였다. 여기서 Laplace filter가 주변값을 사용하여 blending하기 때문에 for 문의 범위를 background의 이미지의 크기보다 한 픽셀식 작게 잡아주었다. 또한 펭귄 두마리를 한 이미지에 합성할때 구현의 편의성을 위하여 각각의 펭귄 이미지가 겹치지 않는다고 가정하고 구현을 진행하였다.

v=arg max((vivj)(sisj))2+((viti)(sisj))2...(1)v = \argmax\sum((v_i-v_j)-(s_i-s_j))^2 + \sum((v_i-t_i)-(s_i-s_j))^2 ...(1)
for x = 2:imw-1
    for y = 2:imh-1
        if mask_s(y,x) == 1 % 첫번째 팽귄 mask
            A(e, im2var(y, x)) = 4;
            A(e, im2var(y, x+1)) = -1;
            A(e, im2var(y, x-1)) = -1;
            A(e, im2var(y-1, x)) = -1;
            A(e, im2var(y+1, x)) = -1;
            b(e, :) = im_s(y, x, :)*4 - im_s(y, x+1, :)- im_s(y, x-1, :)- im_s(y-1, x, :)- im_s(y+1, x, :);
        elseif mask_s2(y, x) == 1 % 두번째 팽귄 mask
            A(e, im2var(y, x)) = 4;
            A(e, im2var(y, x+1)) = -1;
            A(e, im2var(y, x-1)) = -1;
            A(e, im2var(y-1, x)) = -1;
            A(e, im2var(y+1, x)) = -1;
            b(e, :) = im_s2(y, x, :)*4 - im_s2(y, x+1, :)- im_s2(y, x-1, :)- im_s2(y-1, x, :)- im_s2(y+1, x, :);
        else
            A(e, im2var(y, x)) = 1;
            b(e, :) = im_background(y, x, :);
        end
        e = e+1;
    end
end

이에 대한 결과는 다음과 같다. Poisson blending을 진행하기 전보다 주변과 자연스럽게 어우러지는 것을 확인할 수 있다.

After Poisson blending

Blending with mixed gradients

v=arg min((vivj)dij)2+((viti)dij)2...(6)v = \argmin\sum((v_i-v_j)-d_{ij})^2 + \sum((v_i-t_i)-d_{ij})^2 ...(6)
dij={sisj,ifsi>sj>titjtitj,otherwised_{ij}= \begin{cases} s_i-s_j, if |s_i>s_j|>|t_i-t_j|\\t_i-t_j,\text{otherwise}\end{cases}

Mixed gradient의 경우에는 known vector의 값을 배경 이미지와 타겟 이미지 중 더 절댓값이 큰 gradient로 둔다.

이에 대한 코드는 아래와 같이 함수로 구현하였다.

function g = getGradients(im_s, im_bg, x, y)
bg_g = im_bg(y, x, :)*4 - im_bg(y, x+1, :) - im_bg(y, x-1, :) - im_bg(y+1, x, :) - im_bg(y-1, x, :);
s_g = im_s(y, x, :)*4 - im_s(y, x+1, :)- im_s(y, x-1, :)- im_s(y+1, x, :)- im_s(y-1, x, :);
if abs(bg_g) > abs(s_g)
    g = bg_g;
else
    g = s_g;
end

Mixed gradient를 사용하기 위해서 getGradients함수를 앞선 poisson blending에 known vector값으로 사용한다.

for x = 2:imw-1
    for y = 2:imh-1
        if mask_s(y,x) == 1
            A(e, im2var(y, x)) = 4;
            A(e, im2var(y, x+1)) = -1;
            A(e, im2var(y, x-1)) = -1;
            A(e, im2var(y-1, x)) = -1;
            A(e, im2var(y+1, x)) = -1;
            b(e, :) = getGradients(im_s, im_bg, x, y);
        else
            A(e, im2var(y, x)) = 1;
            b(e, :) = im_bg(y, x, :);
        end
        e = e+1;
    end
end

이에 대한 결과는 다음과 같다. 팽귄의 몸에 뒤의 배경 패턴이 얼핏 비치는 것을 확인할 수 있다.

mixed blending

Your own examples

Sample #1

첫번째 sample에는 불꽃놀이의 안개가 낀 하늘 이미지를 배경이미지로 타겟이미지로는 고양이 사진을 사용해보았다.

mixed blending을 할 경우 고양이의 색이 너무 어두워져 possion blending이 더 자연스럽게 합성되었다.

possion blending
mixed blending

Sample #2

두번째 sample로는 공원에서 채스하는 이미지를 배경으로 해리포터 체스말을 타겟이미지로 사용하였다.

Poisson blending을 적용했을때의 결과가 다음과 같다. 배경 이미지의 톤과 그림자의 경계는 합성이 된거 같지만 object 이미지의 배경이 복잡함에도 배경 이미지와 어우러지지 않아서 자연스럽지 않은 것 같다. mixed blending의 경우 복잡한 배경이 자연스럽게 합성되지만 체스말 자체의 색상 변화가 커진다.

poisson blending
mixed blending

Sample #3

마지막 세번째 sample로는 분홍빛 하늘 이미지를 배경으로 파란색 달을 타겟이미지로 사용하였다.

poisson blending과 mixed blending의 결과가 매우 유사하다.

poisson blending
mixed blending

Poisson blending과 mixed blending을 적용했을때 모두 배경은 잘 어울려졌지만 object 이미지가 너무 밝아져서 달의 무늬가 보이지 않게 되었다.