프로그래밍/Python

[opencv] 종횡비 고정하여 이미지 크기 조정하기

채윤아빠 2024. 6. 1. 23:05
728x90
반응형

개요

이미지의 크기를 조정할 때 일반적으로 cv2.resize() 함수를 이용하게 됩니다.

이 때, 이미지의 종횡비를 왜곡하지 않고 테두리를 추가는 방법들을 살펴 보겠습니다.


일반적인 이미지 복사

무작위 이미지를 HD(1280 X 720)으로 크기를 조정할 때 다음과 같이 종횡비를 고정하여 만들 수 있습니다.

    target_height, target_width = 720, 1280
    img_org = cv2.imdecode(np.fromfile(full_image_filename, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
    img_height, img_width = img_org.shape[:2]
    height_scale, width_scale = (img_height / target_height), (img_width / target_width)
    img_scale = min(height_scale, width_scale)
    # 원본 이미지를 설정에 맞게 축소
    scaled_height, scaled_width = round(img_width * img_scale), round(img_height * img_scale)
    scaled_img = cv2.resize(img_org, (scaled_width, scaled_height), interpolation = cv2.INTER_CUBIC)
    img_new = np.full((target_height, target_width, 3), (127, 127, 127), dtype = np.uint8)
    img_new[0:scaled_height, 0:scaled_width] = scaled_img

np.full() 함수를 이용하여 미리 지정된 크기의 빈 이미지를 생성하고, 거기에 크기를 조정한 이미지를 붙여넣기 하는 방식입니다.


copyMakeBorder() 함수 이용

종횡비는 고정한 채 이미지의 크기를 조정할 때 copyMakeBorder() 함수를 이용하면 조금 더 간편하고 빠르게 동작합니다. copyMakeBorder() 함수 사용 예시입니다.

    target_height, target_width = 720, 1280
    img_org = cv2.imdecode(np.fromfile(full_image_filename, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
    img_height, img_width = img_org.shape[:2]
    height_scale, width_scale = (img_height / target_height), (img_width / target_width)
    img_scale = min(height_scale, width_scale)

    # 원본 이미지를 설정에 맞게 축소
    scaled_height, scaled_width = round(img_width * img_scale), round(img_height * img_scale)
    scaled_img = cv2.resize(img_org, (scaled_width, scaled_height), interpolation = cv2.INTER_CUBIC)
    img_new2 = cv2.copyMakeBorder(scaled_img, 0, target_height - scaled_height, 0, target_width - scaled_width, cv2.BORDER_CONSTANT, (127, 127, 127))

위 두 방식간의 성능 비교

위 두 방식간 성능을 다음과 같이 간단하게 비교해 보았습니다.

from timeit import timeit


def main() -> int:
    setup = """
import cv2
import numpy as np

target_height, target_width = 720, 1280
full_image_filename = 'D:/Temp/lpd/test/Red_Apple.jpg'
img_org = cv2.imdecode(np.fromfile(full_image_filename, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
img_height, img_width = img_org.shape[:2]
height_scale, width_scale = (target_height / img_height), (target_width / img_width)
img_scale = min(height_scale, width_scale)
# 원본 이미지를 설정에 맞게 축소
scaled_width, scaled_height = round(img_width * img_scale), round(img_height * img_scale)
"""
    result1 = timeit ("""
scaled_img = cv2.resize(img_org, (scaled_width, scaled_height), interpolation = cv2.INTER_CUBIC)
img_new = np.full((target_height, target_width, 3), (127, 127, 127), dtype = np.uint8)
img_new[0:scaled_height, 0:scaled_width] = scaled_img
""", setup = setup, number = 1000)

    print(f'result1 = {result1}')

    result2 = timeit ("""
scaled_img = cv2.resize(img_org, (scaled_width, scaled_height), interpolation = cv2.INTER_CUBIC)
cv2.copyMakeBorder(scaled_img, 0, target_height - scaled_height, 0, target_width - scaled_width, cv2.BORDER_CONSTANT, (127, 127, 127))
""", setup = setup, number = 1000)

    print(f'result2 = {result2}')


if (__name__ == '__main__'):

    main()


실행결과는 다음과 같이 copyMakeBorder() 함수를 이용했을 때가 약 2배 정도 성능이 좋게 나왔습니다.

result1 = 4.855554999783635
result2 = 2.5016783997416496