Scaling, Re-sizing, Interpolations and Cropping

김성빈·2024년 4월 25일
0

Modern Computer Vision

목록 보기
9/117

저번에 이미지를 이동 과 회전을 했었는데, 이번 시간에는 스케일링, 크기 조정, 보간 및 자르기를 볼건데,

여기 이미지에서 스케일링과 크기 조정 두 가지는 다른 것 같은데 엄밀히 따지면 아니다.

하지만 기본적으로 이미지를 바꾼다는것은 동일하다.

이미지 크기를 조절하는 함수부터 알아보자.

cv2.resize(image, dsize(output image size), x scale, y scale, interpolation)

interpolation

마지막 인자인 interpolation 은 총 5가지의 종류가 있다.

아래로 내려갈수록 이미지의 크기가 커진다.
크기가 커진다는것 이미지의 넓이가 커지는게 아니라 용량이 늘어나는것 > 이미지의 크기가 크다 = 고화질 이미지

  • cv2.INTER_AREA - Good for shrinking or down sampling
  • cv2.INTER_NEAREST - Fastest
  • cv2.INTER_LINEAR - Good for zooming or up sampling (default)
  • cv2.INTER_CUBIC - Better
  • cv2.INTER_LANCZOS4 - Best

CV2 - Resize 참고 자료

라이브러리 및 함수 선언

기존과 똑같이 새로운 프로젝트 맨 위에 OpenCV,matplotlib를 사용하기 위해 가져오고, imshow라는 이미지를 우리 눈으로 출력할수있는 함수를 만든다.

# Our Setup, Import Libaries, Create our Imshow Function and Download our Images
# 설정, 라이브러리 가져오기, Imshow 기능 만들기 및 이미지 다운로드
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Define our imshow function 
# 우리의 imshow 함수를 정의합니다
def imshow(title = "Image", image = None, size = 10):
    w, h = image.shape[0], image.shape[1]
    aspect_ratio = w/h
    plt.figure(figsize=(size * aspect_ratio,size))
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    plt.title(title)
    plt.show()

Resize - Interpolation

Interpolation을 이해하기 위해 컴파일 해보자.

image = cv2.imread('images/oxfordlibrary.jpeg')
imshow("Scaling - Linear Interpolation", image)

# 보간이 지정되지 않은 경우 cv.INTER_LINE이 기본값으로 사용됩니다
# 이미지를 원래 크기의 3/4로 만들어 보겠습니다
image_scaled = cv2.resize(image, None, fx=0.75, fy=0.75)
imshow("0.75x Scaling - Linear Interpolation", image_scaled)

# 이미지의 크기를 두 배로 늘리겠습니다
img_scaled2 = cv2.resize(image, None, fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
imshow("2x Scaling - Inter Cubic", img_scaled2)

# inter_nearest 보간을 사용하여 이미지의 크기를 두 배로 늘리겠습니다
img_scaled3 = cv2.resize(image, None, fx=2, fy=2, interpolation = cv2.INTER_NEAREST)
imshow("2x Scaling - Inter Nearest", img_scaled3)

# 정확한 치수를 설정하여 크기를 조정합니다
img_scaled4 = cv2.resize(image, (900, 400), interpolation = cv2.INTER_AREA)
imshow("Scaling - Inter Area", img_scaled4)

Resize 할 이미지를 불러온다.

기본 이미지

image = cv2.imread('images/oxfordlibrary.jpeg')
imshow("Scaling - Linear Interpolation", image)


이미지 크기 : 1000x1300

Resize x0.75 기본값( cv.INTER_LINE)

image_scaled = cv2.resize(image, None, fx=0.75, fy=0.75)
imshow("0.75x Scaling - Linear Interpolation", image_scaled)


720x900
이 부분에서 resize 함수 인자의 x,y scale의 사용법을 확인할수있다.

원본 이미지의 0.75배씩 곱한값 즉 25% 작아진 이미지를 만들어내는 것

추가로 resize 마지막 인자에 아무값도 입력하지 않았는데 그럴땐 기본값으로 INTER_LINE이 적용

Resize x2 cv2.INTER_CUBIC

img_scaled2 = cv2.resize(image, None, fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
imshow("2x Scaling - Inter Cubic", img_scaled2)


2000x2520

Resize x2 cv2.INTER_NEAREST

img_scaled3 = cv2.resize(image, None, fx=2, fy=2, interpolation = cv2.INTER_NEAREST)
imshow("2x Scaling - Inter Nearest", img_scaled3)

위의 Interpolation한 이미지와 별 차이 없지만 더용량이 큰 방식의 Interpolation을 사용했으니 현재의 이미지가 더 화질이 좋아보여야하는데

글자가 좀더 선명하게, 인식되게 보인다 뿐이지 크게 차이는 못느끼겠다.

그럼 실제 용량을 봐보자.

이미지 크기 출력

각이미지의 크기를 보기위해 os라이브러리를 사용해야하므로 import os와 os를 이용한 이미지 크기를 출력해주는 함수를 만들어준다.

import os

# 이미지를 디스크에 쓰고 파일 크기 출력 함수
def print_image_size(image, filename):
    cv2.imwrite(filename, image)
    size = os.path.getsize(filename)
    print(f"파일 '{filename}'의 크기: {size} bytes")


print_image_size(img_scaled2, "scaled_2x_cubic.jpg")
print_image_size(img_scaled3, "scaled_2x_nearest.jpg")
  • 파일 'scaled_2x_cubic.jpg'의 크기: 1323552 bytes
  • 파일 'scaled_2x_nearest.jpg'의 크기: 1459237 bytes

1.32Mb, 1.46Mb 로 0.14Mb정도 차이가 난다.

사람의 눈으로 잘 봐야 느껴지는 차이점를 수치화하면 0.14Mb의 차이인것이다.

(900, 400) cv2.INTER_AREA

cv2.resize(image, (900, 400), interpolation = cv2.INTER_AREA


이건 이미지의 크기를 정해두고 resize한 이미지

INTER_NEARST – 가장 가까운 이웃 보간
INTER_LINE – 2선형 보간(기본적으로 사용)
INTER_AREA – 픽셀 영역 관계를 사용한 리샘플링. 무아레프리 결과를 제공하기 때문에 이미지 데시메이션에 선호되는 방법일 수 있습니다. 그러나 이미지가 확대되면 INTER_NEAREAST 방법과 유사합니다.
INTER_CUBIC – 4×4 픽셀 이웃에 대한 바이큐빅 보간
INTER_LANCZOS4 – 8×8 픽셀 이웃에서의 Lanczos 보간

interpolation 인터폴레이션

그래서 인터폴레이션이 뭘까?
정의는 두 지점 사이에서 값을 찾는 알고리즘이다.

그럼 인터폴레이션이 어디에 사용되는지 보자

아래는 GPS 기록에 대한 내용이다.

빨-노-..-초-..노 이런식으로 연결이 돼있는데

빨간점은 가야할 경로
초록색점은 실제 가야할 경로였지만 가지 않은 경로(기록에 없는 경로)
노란점은 두점 사이의 추측

즉 인터폴레이션은 노란점을 찾는 알고리즘이며, 두 빨간 점 사이의 한 점(노란점)을 추측한 것이다.

다시 돌아와서 Resize를 할때 선택하는 인터폴레이션을 할때 두가지 질문이 생긴다,

  1. 현재 있는 픽셀
  2. 현재 없는 픽셀

그렇다면 Resize를 하면서 사용할 인터폴레이션을 사용하는데 바뀌는 옵션을 질문식으로 바꿔보면

"현존하는 픽셀들(빨간점)로 현재 없는 픽셀들(노란점)을 만들어내는 작업을 할건데 여기에 사용되는 알고리즘을 골라" 라고 풀수있고

이 질문을 보니까 뜬금없지만 NVIDIA 제어판 설정이 떠올랐다.

Pyraminds image 피라미드 이미지

Pyraminds는 훨씬 더 빠르게 동작하고 이미지를 2배로 축소할 수 있는 빠른 방법

함수로는
pyrDown,pyrUp 이 있다.
사용하는건
pyrDown을 여러번하거나 pyrUp을 여러번 하는 식으로 사용한다.

image = cv2.imread('images/oxfordlibrary.jpeg')

smaller = cv2.pyrDown(image)
larger = cv2.pyrUp(smaller)

imshow("Original", image)
imshow('Smaller', smaller)
imshow('Larger', larger)

even_smaller = cv2.pyrDown(smaller)
imshow('Even Smaller', even_smaller)

결론부터 보면 이미지의 크기는 아래와 같다.

이미지 'Original'의 크기: 444642 bytes
이미지 'Smaller'의 크기: 130199 bytes
이미지 'Larger'의 크기: 281861 bytes
이미지 'Even Smaller'의 크기: 34170 bytes

제일 작게 만든 Even Smaller의 이미지만 보여주면


인식이 불가능할정도로 뿌옇다.

Cropping 자르기

image = cv2.imread('images/oxfordlibrary.jpeg')

height, width = image.shape[:2]
start_row, start_col = int(height * .25), int(width * .25)
end_row, end_col = int(height * .75), int(width * .75)
cropped = image[start_row:end_row , start_col:end_col]
imshow("Original Image", image)

copy = image.copy()
cv2.rectangle(copy, (start_col,start_row), (end_col,end_row), (0,255,255), 10)

imshow("Area we are cropping", copy)
imshow("Cropped Image", cropped) 

저번 시간에 봤던 Shape[:2]를 이용해 높이 너비를 가져오고,

crop 할 부분을 지정하고 어떤 부분이 crop 되는지 출력하기 위한 cv2.rectangle을 이용해서 노란색 박스로 표시한다.

cropping 할 범위

cropped 이미지

profile
감사합니다. https://www.youtube.com/channel/UCxlkiu9_aWijoD7BannNM7w

0개의 댓글