OpenCV 비전 실무3장 · 디지털 영상과 색공간 변환5 / 21← 이전목차다음 →MetaContents

3장. 디지털 영상과 색공간 변환

비트 깊이와 데이터형

시험 점수를 떠올려 봅시다. 어떤 시험은 255점 만점이고, 어떤 시험은 100점 만점입니다. 두 점수를 함께 계산하려면 "만점의 몇 %인가"처럼 비율로 바꾸는 편이 편합니다. 그림의 숫자도 0~255 의 정수로 저장하지만, 계산할 때는 255 로 나눠 0.0~1.0 의 비율로 바꿔 쓰는 일이 많습니다.

uint8, float32, uint16 세 가지 데이터형의 범위와 바이트 수를 견준 비교 그림

그림의 세 상자는 숫자를 담는 그릇 세 가지입니다. 보통 그림 파일은 왼쪽의 uint8 로 읽히고, 밝기를 곱하거나 나누는 계산은 가운데의 float32 로 바꿔서 합니다. 여기서 255점 만점 점수가 uint8 이고, 비율(0.0~1.0)이 float32 입니다.

세 가지 데이터형

데이터형숫자 범위한 칸의 크기언제 쓰나
uint80~255 정수1바이트(8비트)보통의 png, jpg 그림
float32소수(그림에서는 보통 0.0~1.0)4바이트(32비트)곱하기, 나누기 같은 계산, 딥러닝 입력
uint160~65,535 정수2바이트(16비트)의료·과학용 카메라, 깊이 카메라

16비트는 2를 16번 곱한 65,536단계입니다. 8비트(256단계)보다 밝기를 훨씬 잘게 나눠 적습니다. 16비트 png 를 그대로 읽는 읽기 모드는 2장에서 보았고, 이 과정의 실습 그림은 모두 8비트입니다.

바꾸고 되돌리기

uint8 을 float32 로 바꿀 때는 astype(np.float32) 로 그릇을 바꾼 뒤 255 로 나눕니다. 되돌릴 때는 255 를 곱하고, 0~255 밖의 값을 np.clip 으로 자른 다음 astype(np.uint8) 로 담습니다.

Python
import numpy as np

px = np.array([0, 51, 255], dtype=np.uint8)
# 그릇을 float32 로 바꾸고 255 로 나눈다: 0~255 → 0.0~1.0
f = px.astype(np.float32) / 255
print(f)                      # 결과: [0.  0.2 1. ] → 51 ÷ 255 = 0.2

# 1.5배 밝게 하면 1.0 을 넘는 값이 생긴다
brighter = f * 1.5
print(brighter)               # 결과: [0.  0.3 1.5]
# np.clip(배열, 가장 작은 값, 가장 큰 값): 범위 밖의 값을 끝 값으로 자른다
safe = np.clip(brighter, 0, 1)
# 255 를 곱하고 반올림(round)한 뒤 uint8 그릇에 담는다
back = (safe * 255).round().astype(np.uint8)
print(back)                   # 결과: [  0  76 255] → 0.3 × 255 = 76.5 → 반올림 76

마지막 줄에서 76.5 가 77 이 아니라 76 이 된 까닭은, NumPy 의 round 가 끝자리 .5 를 가까운 짝수 쪽으로 보내기 때문입니다. 1 차이라 눈으로는 구별되지 않습니다.

주의할 점

  • px / 255 처럼 uint8 배열을 그냥 나누면 결과가 float64(8바이트)가 됩니다. 메모리를 아끼려면 px.astype(np.float32) / 255 처럼 먼저 float32 로 바꿉니다.
  • 0~255 를 벗어난 소수를 clip 없이 astype(np.uint8) 로 담으면 엉뚱한 값이 나옵니다. 그 값은 컴퓨터마다 다를 수 있습니다. 실습 2에서 직접 봅니다.
  • astype(np.uint8) 은 소수점 아래를 버립니다(127.9 → 127). 반올림하려면 .round() 를 먼저 붙입니다.
← 이전 절3장 · 해상도다음 절 →3장 · 빛의 삼원색과 RGB