1장. AI 비전과 OpenCV 개발환경
실습 3 — 그림 파일 읽고 정보 보기
과일 진열대 그림(fruit_stand.png)을 읽어 크기, 자료형, 숫자의 범위를 보고, 사과 한가운데 칸의 색 숫자를 읽어 봅니다. 이 그림은 OpenCV 로 도형을 그려 만든 연습용 가상 그림입니다.
1단계. 읽고 모양 보기
import cv2
# cv2.imread(파일 이름): 그림을 읽어 NumPy 배열로 돌려준다. 실패하면 None
img = cv2.imread("fruit_stand.png")
if img is None:
raise SystemExit("fruit_stand.png 를 읽지 못했습니다. 작업 폴더를 확인하세요")
print("자료형:", type(img).__name__) # 결과: ndarray → NumPy 배열
print("모양:", img.shape) # 결과: (세로, 가로, 채널)
print("칸 하나의 자료형:", img.dtype) # 결과: uint8 → 0~255자료형: ndarray
모양: (240, 320, 3)
칸 하나의 자료형: uint82단계. 크기를 숫자로 따져 보기
h, w, c = img.shape # 세로, 가로, 채널 수를 한 번에 나눠 받는다
print(f"해상도: 가로 {w} × 세로 {h}")
print(f"픽셀 수: {w} × {h} = {w * h:,}칸")
print(f"숫자 개수: {w * h:,} × {c} = {img.size:,}개")
# 숫자 하나가 1바이트(uint8)이므로 메모리에서는 숫자 개수만큼의 바이트를 차지한다
print(f"메모리에서 차지하는 크기: {img.nbytes:,}바이트")
print("가장 작은 값:", int(img.min()), "/ 가장 큰 값:", int(img.max()))해상도: 가로 320 × 세로 240
픽셀 수: 320 × 240 = 76,800칸
숫자 개수: 76,800 × 3 = 230,400개
메모리에서 차지하는 크기: 230,400바이트
가장 작은 값: 30 / 가장 큰 값: 2553단계. 사과 한가운데의 색 읽기
# 사과의 가운데는 가로 80, 세로 140 자리다. 배열은 [세로, 가로] 순서로 꺼낸다
b, g, r = img[140, 80]
print("사과 가운데 BGR:", int(b), int(g), int(r))
# 귤(가로 165, 세로 145)과 벽(가로 160, 세로 20)도 견줘 본다
for name, (y, x) in {"귤": (145, 165), "벽": (20, 160)}.items():
print(f"{name} BGR:", [int(v) for v in img[y, x]])사과 가운데 BGR: 40 40 210
귤 BGR: [30, 140, 250]
벽 BGR: [198, 230, 243]4단계. 없는 파일을 읽으면
# 파일 이름에 오타가 있다고 해 보자(fruit_stand → fruit_stnad)
wrong = cv2.imread("fruit_stnad.png")
print("돌아온 값:", wrong)
# None 인지 먼저 확인하면 뒤에서 'NoneType' 오류로 멈추지 않는다
if wrong is None:
print("읽기 실패 → 이름과 위치를 확인하세요")돌아온 값: None
읽기 실패 → 이름과 위치를 확인하세요코드 설명
img.shape는 (240, 320, 3) 처럼 세로가 먼저입니다.h, w, c = img.shape로 나눠 받으면 헷갈리지 않습니다.img.nbytes는 배열이 메모리에서 차지하는 바이트 수입니다. png 파일은 이 크기를 줄여 저장하므로 파일 크기(약 10KB)가 메모리 크기보다 훨씬 작습니다.img[140, 80]은 [세로, 가로] 자리의 칸 하나로, 숫자 세 개를 B, G, R 순서로 돌려줍니다. 사과 칸은 셋째 숫자(빨강)가 가장 큽니다.- 파일 이름이 틀리면
cv2.imread는 오류 없이None을 돌려줍니다. 그래서 읽은 직후에is None으로 확인하는 습관을 들입니다.