[2회차] Computer Vision - Scaling
[Computer Vision]
Scaling
이미지의 크기를 늘리게 되면 기존 이미지의 각 픽셀 사이에 공백이 생긴다.
이 공백의 픽셀을 기존 이미지의 픽셀 밝기 값을 이용해 밝기 값을 지정해준다.
그런데 여기서 기존 이미지의 픽셀 밝기 값을 그대로 적용하게 된다면 이미지의 크기를 늘렸을 때 자연스럽지 않고, 뚝뚝 끊기서 이미지가 부자연스러워질 것이다.
그래서 픽셀 밝기 값과 공백 픽셀의 위치를 이용해 위치에 맞는 밝기 값을 계산하는 과정이 필요하다.
이 일련의 과정을 Scaling이라 한다.
위의 사진에서 a, b, c, d가 기존 이미지의 픽셀 위치이다. a, b, c, d의 밝기 값으로 m의 밝기 값을 지정한다.
m = (a+b+c+d) / 4
scaling할 픽셀의 좌표를 (x, y)라고 할 때, (x, y)가 △amb, △amc, △bmd, △cmd 중 어떤 삼각형에 위치하는지 구해야한다.
픽셀과 가장 가까운 픽셀의 밝기 값에 더 크게 영향을 받기 때문이다.
다음 과정은 예시를 통해서 설명하겠다.
a, b, c, d가 a = 10, b = 3, c = 5, d = 6 의 밝기 값을 가진다면 m = (10+3+5+6) / 4 = 6 으로 m은 밝기 값을 6으로 가진다.
여기서 scaling할 픽셀 좌표 (x, y)를 x=0.4, y=0.3이라고 하자. 그럼 이 점은 △amb에 위치한다.
△amb의 x좌표와 y좌표를 각각 X, Y 행렬로 만든다.
$$ X = \begin{bmatrix}0&0.5&1\\ \end{bmatrix} $$
$$ Y = \begin{bmatrix}0&0.5&0\\ \end{bmatrix} $$
$$ \begin{bmatrix}X&Y&{\begin{bmatrix}1&1&1\\ \end{bmatrix}}\\ \end{bmatrix}^T = \begin{bmatrix}0&0&1\\0.5&0.5&1\\1&0&1\\ \end{bmatrix} $$
$$ \begin{bmatrix}0&0&1\\0.5&0.5&1\\1&0&1\\ \end{bmatrix}\begin{bmatrix}\alpha&\beta&\gamma\\ \end{bmatrix} = \begin{bmatrix}10&6&3\\ \end{bmatrix} $$
$$ \begin{bmatrix}\alpha&\beta&\gamma\\ \end{bmatrix} = \begin{bmatrix}0&0&1\\0.5&0.5&1\\1&0&1\\ \end{bmatrix}^{-1} \begin{bmatrix}10&6&3\\ \end{bmatrix} $$
3x3 행렬의 역행렬은 아래와 같다.
$$ \begin{bmatrix}A_{11}&A_{12}&A_{13}\\A_{21}&A_{22}&A_{23}\\A_{31}&A_{32}&A_{33}\\ \end{bmatrix}^{-1} = \frac{1}{K}\begin{bmatrix}A_{22}A_{33}-A_{23}A_{32}&A_{13}A_{32}-A_{12}A_{33}&A_{12}A_{23}-A_{13}A_{22}\\A_{23}A_{31}-A_{21}A_{33}&A_{11}A_{33}-A_{13}A_{31}&A_{13}A_{21}-A_{11}A_{23}\\A_{21}A_{32}-A_{22}A_{31}&A_{12}A_{31}-A_{11}A_{32}&A_{11}A_{22}-A_{12}A_{21}\\ \end{bmatrix} $$
$$ K = A_{11}A_{22}A_{33}-A_{11}A_{23}A_{32}-A_{12}A_{21}A_{33}+A_{12}A_{23}A_{31}+A_{13}A_{21}A_{32}-A_{13}A_{22}A_{31} $$
위의 식에 행렬의 값을 대입하여 역행렬을 구하면 아래와 같다.
$$ \begin{bmatrix}A_{22}A_{33}-A_{23}A_{32}&A_{13}A_{32}-A_{12}A_{33}&A_{12}A_{23}-A_{13}A_{22}\\A_{23}A_{31}-A_{21}A_{33}&A_{11}A_{33}-A_{13}A_{31}&A_{13}A_{21}-A_{11}A_{23}\\A_{21}A_{32}-A_{22}A_{31}&A_{12}A_{31}-A_{11}A_{32}&A_{11}A_{22}-A_{12}A_{21}\\ \end{bmatrix} = \begin{bmatrix}0.5&0&-0.5\\0.5&-1&0.5\\-0.5&0&0.5\\ \end{bmatrix} $$
$$ K = 0-0-0+0+0-0.5 = -0.5 $$
$$ \frac{1}{-0.5}\begin{bmatrix}0.5&0&-0.5\\0.5&-1&0.5\\-0.5&0&0.5\\ \end{bmatrix} = \begin{bmatrix}-1&0&1\\-1&2&-1\\1&0&0\\ \end{bmatrix} $$
구한 행렬의 역하수를 대입하여 알파, 베타, 감마 값을 구하면 아래와 같다.
$$ \begin{bmatrix}\alpha&\beta&\gamma\\ \end{bmatrix} = \begin{bmatrix}-1&0&1\\-1&2&-1\\1&0&0\\ \end{bmatrix}\begin{bmatrix}10&6&3\\ \end{bmatrix} = \begin{bmatrix}-7&-1&10\\ \end{bmatrix} $$
구한 알파, 베타, 감마와 점의 좌표를 행렬곱 해주면 밝기값이 구해진다.
$$ \begin{bmatrix}-7&-1&10\\ \end{bmatrix}\begin{bmatrix}0.4\\0.3\\1\\ \end{bmatrix} = \begin{bmatrix}6.9\\ \end{bmatrix} $$
위의 과정을 4가지 함수를 이용해 구현하였다.
def dot_loc(x_loc, y_loc):
return [first_dot_loc, second_dot_loc]
def dot_coor(a_bri, b_bri, c_bri, d_bri, dot_loc_list):
return x,y,bri
def abr(dot_coor_list, i):
arr = np.array([dot_coor_list[0], dot_coor_list[1], [1,1,1]])
I = np.linalg.inv(arr.T)
return I@dot_coor_list[2]
def scale(img, s):
blank[i, j, k] = (abr_list@[[x%1], [y%1], [1]])
return blank
dot_loc 함수는 scaling할 픽셀의 좌표와 가장 가까운 두 점을 구한다.
dot_coor 함수는 dot_loc에서 구한 두 점과 점 m으로 이루어진 삼각형의 x좌표, y좌표, 각 점의 밝기 값의 행렬을 반환한다.
abr 함수는 dot_coor_list에서 구한 삼각형의 x좌표와 y좌표와 [1,1,1]로 이루어진 3x3 행렬을 만들어 이 행렬을 전치한 행렬의 역행렬을 구한다. 이 역행렬을 삼각형의 밝기 값과 행렬곱한 값을 반환한다.
마지막으로 scale 함수에서는 이미지를 scaling 했을 때의 크기로 빈 패드를 만들고 이 패드의 각 좌표에 대해 앞의 세 함수를 호출한다. 패드의 각 좌표에 abr에서 구한 행렬과 x,y 좌표값을 행렬곱하여 구한 밝기값을 넣는다.
앞의 함수를 사용한 scaling이 제대로 되는지 확인해보자.
랜덤함수와 for문을 이용하여 밝기 값을 랜덤으로 지정한 5x5 이미지를 만들자.
이 이미지를 각각 3, 5, 100으로 scling하면 아래와 같은 이미지가 출력된다. 각각의 이미지가 기존 이미지 크기의 3배, 5배, 100배가 된 것을 확인할 수 있다. 그리고 기존 이미지의 픽셀과 그 사이의 픽셀들이 자연스럽게 이어지는 것을 확인할 수 있다.
실제 이미지를 사용해서도 확인해보자.
사용할 이미지를 호출해 출력하면 아래와 같다. 이미지의 크기는 512x932이다.
이 이미지를 3으로 scaling하면 아래와 같은 결과가 나타난다. 기존 이미지와 거의 똑같게 출력되지만 이미지의 크기가 기존 이미지의 3배가 된 것을 확인할 수 있다.