소스 뷰어

양선형 보간법 (bilinear interpolation)

  • 영상을 확대할 때 확대비율이 커지면, 최근접 이웃 보간법은 모자이크 현상 혹은 경계부분에서 계단 현상이 나타나게 된다. 이러한 문제를 보완하는 방법이 양선형 보간법 이다.
  • 여기서 선형(linear)의 의미는 쉽게 표현하자면 직선의 특징을 가진 것이라 할 수 있는데, 직선의 방정식을 예로 들 수 있다. 두 개 화소의 값을 알고 있을 때 그 값을 직선으로 그려보면 이때 직선 위에 위치한 화소들의 값은 직선의 쉭을 이용해서 쉽게 게산할 수 있다.
  • 각 수식은 블로그를 참고

보간 방법 옵션 상수

옵션 상수 설명
cv2.INTER_NEAREST 0 최근접 이웃 보간
cv2.INTER_LINEAR 1 양선형 보간(기본값)
cv2.INTER_CUBIC 2 바이큐빅 보간 - 4x4 이웃 화소 이용
cv2.INTER_AREA 3 픽셀 영역의 관계로 리샘플링
cv2.INTER_LANCZOS4 4 Lanczos 보간 - 8x8 이웃 화소 이용
import numpy as np, cv2
def scaling_nearest(img, size):                                # 크기 변경 함수
    dst = np.zeros(size[::-1], img.dtype)                      # 행렬과 크기는 원소가 역순
    ratioY, ratioX = np.divide(size[::-1], img.shape[:2])
    i = np.arange(0, size[1], 1)
    j = np.arange(0, size[0], 1)
    i, j = np.meshgrid(i, j)
    y, x = np.int32(i / ratioY), np.int32(j / ratioX)
    dst[i,j] = img[y,x]

    return dst
# 단일 화소 양선형 보간 수행 함수 
def bilinear_value(img, pt):                         
    x, y = np.int32(pt)
    if x >= img.shape[1]-1: x = x -1 # 영상 범위 벗어남을 처리
    if y >= img.shape[0]-1: y = y - 1

    P1, P3, P2, P4 = np.float32(img[y:y+2,x:x+2].flatten())
   ## 4개의 화소 가져옴 – 화소 직접 접근
   #  P1 = float(img[y, x] )                         # 상단 왼쪽 화소
   #  P3 = float(img[y + 0, x + 1])                  # 상단 오른쪽 화소
   #  P2 = float(img[y + 1, x + 0])                  # 하단 왼쪽 화소
   #  P4 = float(img[y + 1, x + 1])                  # 하단 오른쪽 화소

    alpha, beta = pt[1] - y,  pt[0] - x              # 거리 비율
    M1 = P1 + alpha * (P3 - P1)                      # 1차 보간
    M2 = P2 + alpha * (P4 - P2)
    P  = M1 + beta  * (M2 - M1)                      # 2차 보간
    return  np.clip(P, 0, 255)                       # 화소값 saturation후 반환
def scaling_bilinear(img, size):                        	# 양선형 보간
    ratioY, ratioX = np.divide(size[::-1], img.shape[:2])  # 변경 크기 비율

    dst = [[ bilinear_value(img, (j/ratioX, i/ratioY))     # for문 이용한 리스트 생성
             for j in range(size[0])]
           for i in range(size[1])]
    return np.array(dst, img.dtype)
image = cv2.imread('img/interpolation.jpg', cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상 파일 읽기 에러")
size = (350, 400)
dst1 = scaling_bilinear(image, size)                # 크기 변경 - 양선형 보간
dst2 = scaling_nearest(image, size)                 # 크기 변경 - 최근접 이웃 보간
dst3 = cv2.resize(image, size, 0, 0, cv2.INTER_LINEAR)  # OpenCV 함수 적용
dst4 = cv2.resize(image, size, 0, 0, cv2.INTER_NEAREST)
cv2.imshow("image", image)
cv2.imshow("User_bilinear", dst1)
cv2.imshow("User_Nearest", dst2)
cv2.imshow("OpenCV_bilinear", dst3)
cv2.imshow("OpenCV_Nearest", dst4)
cv2.waitKey(0)
-1

result