728x90

보간법 Interpolation 은 영상처리에서 자주 활용됩니다. 이미지 확대나 변환 시 원본 이미지의 특성을 보전하고자 하는 해상도 개선 기법의 기본 입니다. 양선형 보간법 Bilinear Interpolation은 단어에서 같이 선형 보간법을 두번 반복하는 방법이며, 양선형 필터링 또는 양선형 맵핑 등으로도 언급됩니다. 현 블로그에서는 보간법의 이론적인 부분을 간략 다뤄보겠습니다.

 

양선형 보간 과정을 살펴보면, 그림에서 우리가 알고 싶은 점은 실수 좌표 (x, y)에 위치한 픽셀 값입니다. 이 실수 좌표는 정수 좌표 A, B, C, D의 픽셀 사이에 있으며, 이 정수 좌표의 픽셀 값을 이용하여 보간 할 수 있습니다.

 

 

 

4개의 좌표의 픽셀 값을 식으로 표현하면,

 

A = f(x1, y1), B = f(x2, y1), C = f(x1, y2), D = f(x2, y2)

보간 위치: (x, y), 여기서 x1 ≤ x ≤ x2, y1 ≤ y ≤ y2

 

계산 과정을 단계로 보면,

1) X 방향 보간

(A와 B 사이) R1=(x2−x)/(x2−x1)∗A+(x−x1)/(x2−x1)∗B

(C와 D 사이) R2=(x2−x)/(x2−x1)∗C+(x−x1)/(x2−x1)∗D

 

2) Y 방향 보간

(R1과 R2를 이용) P(x,y)=(y2−y)/(y2−y1)∗R1+(y−y1)/(y2−y1)∗R2

 

3) 하나의 공식으로 표현하면,

P(x,y)=A∗(x2−x)∗(y2−y)+B∗(x−x1)∗(y2−y)+C∗(x2−x)∗(y−y1)+D∗(x−x1)∗(y−y1)

여기서, 픽셀 간격이 “1”이라고 가정합니다. 참고로 “1”이 아닌 경우 (x2-x1)*(y2-y1)으로 정규화해주는 것이 일반적입니다.

 

단계별 공식 변환에서처럼 X축 방향과 Y축 방향으로 각각 적용한 방법이 양선형 보간법 입니다. 더 확장해보면 위 식은 다선형 다항식 Multilinear Polynomial 형태로 변환하여 문제를 풀 수 있습니다. 양선형 보간은 이차 다항식이 아니라 두 변수 일차 다항식으로 생각할 수 있으며, 어떤점 (x, y)에서의 값을 2차원이 아닌 일차 다항식 형태로 근사합니다.

 

하나의 공식으로 합쳐진 P(x, y)를 아래와 같이 좌표 (x, y) 기준 다항식으로 변환 할 수 있습니다.

f(x,y)=a0​+a1​x+a2​y+a3​xy

a0​=Ax2​y2​−Bx1​y2​−Cx2​y1​+Dx1​y1

a1​=−Ay2​+By2​−Cy1​+Dy1​

a2​=−Ax2​+Bx1​+Cx2​−Dx1​

a3=A+D−B−C

 

따라서 위 f(x,y) 식을 선형시스템으로 가정하여 우리가 알고 있는 4개의 위치 A, B, C, D를 행렬식으로 정리하여 선형대수로 계수 a0, a1, a2, a3를 구할 수 있습니다. 간략히 Ax=b 형태의 Matrix 계산으로 변환할 수 있으며, 주변 4개의 좌표를 이용한 양선형 보간법의 예를 파이썬 코드로 확인 할 수 있습니다. 계수 계산 시 np.lianlg,solve 함수를 사용합니다.

 

| 1 x1 y1 x1y1 |  |a0|      |f1|

| 1 x2 y1 x2y1 |  |a1|  =  |f2|

| 1 x1 y2 x1y2 |  |a2|      |f3|

| 1 x2 y2 x2y2 |  |a3|      |f4|

 

# Linear System Solution Ax=b
import numpy as np

# 4개 점의 좌표와 픽셀값
x1, x2 = 0, 1
y1, y2 = 0, 1
f1, f2, f3, f4 = A, B, C, D

# 계수 행렬 A
M = np.array([
    [1, x1, y1, x1*y1],
    [1, x2, y1, x2*y1],
    [1, x1, y2, x1*y2],
    [1, x2, y2, x2*y2],
])

# 함수값 벡터
f = np.array([f1, f2, f3, f4])

# 계수 a0, a1, a2, a3 계산
a = np.linalg.solve(M, f)

# 양선형 보간 함수
def bilinear_interp(x, y):
    return a[0] + a[1]*x + a[2]*y + a[3]*x*y
728x90
728x90

영상처리 기술에서 보간법은 이미지 확대나 회전, 좌표 변환 기술 Affine Transform 등 알고리즘 구현 시 빈번히 사용됩니다. 머신 러닝 Machine Learning 및 딥러닝 Deep Learning 등 특히 CNN 계열에 Coarse Map을 Dense Map으로 Up-Sampling시 활용되는 기술이기도 합니다. 이미지를 두 배로 확대할 때 보간법은 새로운 픽셀 Pixel 값을 그럴듯하게 예측하는 기술로 볼 수 있습니다. 이론적인 부분은 영상처리 기술에서 다루도록 하겠습니다.

 

기본적인 보간법 세가지는 아래와 같습니다.

 

1. 최근접 이웃 보간법 Nearest Neighbor Interpolation

- 소수점 좌표에서 가장 가까운 정수 좌표 픽셀 사용, 수행속도가 가장 빠르지만 계단 현상 및 깨짐 현상 발생

 

2. 양선형 보간법 Bilinear Interpolation

- 주변 4개 픽셀을 사용해 선형 평균을 이용, 최근접 보다 자연스러운 결과를 보이고 일반적으로 많이 활용되는 기술

 

3. 양큐빅 보간법 Bicubic Interpolation

- 주변 16개 픽셀을 활용하며 앞에 두 기술보다 자연스러우며, Super Resolution 기술들에서 비교 결과로 많이 사용, 고화질 이미지 편집에 사용되는 기술이며 처리속도는 느림

 

이미지 회전 시 보간법이 사용되는 이유는 회전은 수학적으로 기존 픽셀 좌표를 회전 행렬로 이동시키는 과정입니다. 회전 시 생성되는 좌표는 보통 소수점 좌표가 되며, 새로운 평면에 매칭 시 좌표는 소수점이 아닌 정수이기때문에 빈공간이 생기게 됩니다. 그 빈공간을 채워주기 위해 보간법이 활용됩니다. 예를 들어 좌표 (5, 5)를 30도 회전하면 (5.3, 3.9) 되므로 실제 좌표 매칭을 위해서는 주변 픽셀 (5, 3), (6, 3), (5, 4), (6, 4)를 이용하여 추정해야 합니다.

 

OpenCV에서 이미지 회전 및 확대 시 보간법을 지정할 수 있습니다. 아래는 파이썬 활용시 CV 상수 입니다. 첫번째 예제는 회전시 파이썬 코드이며, 이전 블로그에서 설명한 “cv2.warpAffine” 함수를 사용합니다. 두번째 예제는 “cv2.resize” 함수를 활용한 보간법 사용 예입니다. 

 

1. 최근접 이웃 보간법 - cv2.INTER_NEAREST

2. 양선형 보간법 - cv2.INTER_LINEAR

3. 양큐빅 보간법 - cv2.INTER_CUBIC

4. Lanczos 보간법 - cv2.INTER_LANCZOS4

 

# 이미지 회전 예제
import cv2
import numpy as np

# 이미지 로드
img = cv2.imread('lena.jpg')

# 회전 중심, 각도, 스케일
center = (img.shape[1] // 2, img.shape[0] // 2)
angle = 50
scale = 1.0

# 회전 행렬 생성
M = cv2.getRotationMatrix2D(center, angle, scale)

# 양큐빅 보간법 사용예
rotated = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_CUBIC)

# 결과 보기
cv2.imshow('Rotated Image', rotat_result)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

# 이미지 확대 예제
img = cv2.imread('lena.jpg')

# 2배 확대, 선형 보간법
resized = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)

# 결과 보기
cv2.imshow('Resized Image', resiz_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
728x90

+ Recent posts