이미지 변형
파일 불러오기
image = cv.imread("balls.png")
이미지 크기 변경
cv.resize()는 이미지를 지정한 크기나 비율로 확대·축소함. OpenCV 배열의 shape는 (높이, 너비, 채널) 순서.
height, width = image.shape[:2]
height, width
(816, 1456)
결과 크기 지정
dsize에는 배열의 shape와 반대로 (너비, 높이)를 전달.
half_by_size = cv.resize(
image,
(width // 2, height // 2), # dsize는 (너비, 높이) 순서
interpolation=cv.INTER_AREA,
)
half_by_size.shape
(408, 728, 3)
interpolation은 크기가 달라질 때 픽셀값을 계산하는 방법.- 축소에는
cv.INTER_AREA가 적합하며, 자세한 내용은 아래 보간 절에서 다룸.
확대·축소 비율 지정
dsize를 None으로 두고 fx, fy로 가로와 세로의 배율을 지정 가능.
half_by_ratio = cv.resize(
image,
None,
fx=0.5,
fy=0.5,
interpolation=cv.INTER_AREA,
)
half_by_ratio.shape
(408, 728, 3)
-
fx=0.5,fy=0.5는 가로와 세로를 각각 절반으로 줄임. -
채널 수는 변하지 않음. 크기를 직접 지정한 방식과 결과가 같음.
-
cv.resize()는 원본 배열을 바꾸지 않고 새 배열을 반환. -
원본이 필요하면 그대로 두고 반환값을 다른 이름에 저장.
종횡비 유지
종횡비(aspect ratio)는 이미지의 너비와 높이의 비율임.
aspect ratio=heightwidth너비만 정하고 원본과 같은 비율을 유지하려면 같은 배율로 높이를 계산함.
target_width = 480
scale = target_width / width
target_height = round(height * scale) # 같은 배율을 높이에도 적용
resized = cv.resize(
image,
(target_width, target_height),
interpolation=cv.INTER_AREA,
)
resized.shape
(269, 480, 3)
축소한 이미지에서 찾은 좌표는 원본 좌표와 다름. 원본 기준 위치가 필요하면 좌표를 scale로 나누어 되돌림.
보간
- 크기가 달라지면 출력 픽셀의 위치가 원본 픽셀과 정확히 일치하지 않을 수 있음.
- 보간(interpolation)은 주변 픽셀을 이용해 출력 픽셀값을 계산하는 방법.
| 보간 방법 | 특징 | 주요 용도 |
|---|---|---|
cv.INTER_NEAREST |
가장 가까운 픽셀 사용, 빠르지만 계단 현상이 잘 보임 | 픽셀값을 그대로 유지해야 하는 마스크 |
cv.INTER_LINEAR |
주변 2×2 픽셀 사용, OpenCV 기본값 | 일반적인 확대 |
cv.INTER_CUBIC |
주변 4×4 픽셀 사용, 비교적 부드러움 | 고품질 확대 |
cv.INTER_LANCZOS4 |
주변 8×8 픽셀 사용, 계산량이 큼 | 고품질 확대 |
cv.INTER_AREA |
픽셀 영역 관계를 반영 | 일반적인 축소 |
cv.INTER_AREA는 여러 원본 픽셀이 출력 픽셀 하나에 대응하는 축소 상황을 전제.- 확대에 사용하면
cv.INTER_NEAREST와 비슷하게 동작하여 계단 현상이 나타남. 확대에는cv.INTER_LINEAR나cv.INTER_CUBIC을 사용함.
보간 방법 비교
- 원본의 가로와 세로를 각각 1/32로 줄인 뒤 원본 크기로 확대하여 보간 방법을 비교.
- 낮아진 해상도를 크게 확대하면 픽셀 경계와 보간 방식의 차이가 더 뚜렷하게 나타남.
small = cv.resize(
image,
None,
fx=1/32, # 해상도를 크게 낮춰 보간 차이를 부각
fy=1/32,
interpolation=cv.INTER_AREA,
)
nearest = cv.resize(
small,
(width, height),
interpolation=cv.INTER_NEAREST,
)
linear = cv.resize(
small,
(width, height),
interpolation=cv.INTER_LINEAR,
)
cubic = cv.resize(
small,
(width, height),
interpolation=cv.INTER_CUBIC,
)
lanczos = cv.resize(
small,
(width, height),
interpolation=cv.INTER_LANCZOS4,
)
to_pil(cv.hconcat([nearest, linear, cubic, lanczos]))
INTER_NEAREST는 픽셀 경계가 뚜렷하고, 더 넓은 이웃을 사용하는 방법은 경계가 상대적으로 부드러움. 보간으로 확대해도 원본에 없던 실제 세부 정보가 복원되는 것은 아님.

이미지 뒤집기
cv.flip()은 지정한 축을 기준으로 이미지를 반전.
flipCode |
결과 |
|---|---|
0 |
상하 반전 |
| 양수 | 좌우 반전 |
| 음수 | 상하좌우 반전 |
vertical = cv.flip(image, 0)
horizontal = cv.flip(image, 1)
both = cv.flip(image, -1)
to_pil(cv.hconcat([vertical, horizontal, both]))

- 좌우 반전은 글자나 좌우가 구분되는 대상을 거울에 비친 것처럼 바꿈.
- 예제 이미지에서도 왼쪽의 빨간 공과 오른쪽의 파란 공이 자리를 바꿈.
- 데이터 증강에 사용할 때는 좌우가 바뀌어도 의미가 유지되는지 확인해야 함.
90도 단위 회전
cv.rotate()는 90도 단위로 이미지를 회전.
시계방향 90도 회전:
clockwise = cv.rotate(
image,
cv.ROTATE_90_CLOCKWISE,
)
clockwise.shape
(1456, 816, 3)
180도 회전:
rotated_180 = cv.rotate(
image,
cv.ROTATE_180,
)
rotated_180.shape
(816, 1456, 3)
반시계방향 90도 회전:
counterclockwise = cv.rotate(
image,
cv.ROTATE_90_COUNTERCLOCKWISE,
)
counterclockwise.shape
(1456, 816, 3)
90도 회전하면 너비와 높이가 서로 바뀌고, 180도 회전하면 원래 크기가 유지됨.
to_pil(clockwise)

cv.rotate()는 90도 단위 회전에 적합함. 30도나 45도처럼 임의 각도로 회전하려면 회전 행렬과 cv.warpAffine()이 필요.
퀴즈
cv.resize(image, dsize)의 dsize에 전달하는 크기 순서는?
퀴즈를 풀려면 대화형 기능을 불러와야 합니다.