2장. 이미지 입출력과 영상 시각화
좌표 두 가지와 잘라 내기
극장 좌석표는 "몇 번째 줄, 몇 번째 자리"로 적습니다. 줄이 먼저입니다. 그런데 지도에서 자리를 말할 때는 "동쪽으로 몇 칸, 남쪽으로 몇 칸"처럼 가로를 먼저 말하기도 합니다. 그림에도 이 두 가지 순서가 함께 쓰입니다. 그림을 그리는 함수는 가로 먼저인 (x, y) 를 받고, 배열에서 칸을 꺼낼 때는 줄 먼저인 [행, 열] 을 씁니다.
![8×6 칸 모눈에서 (x, y) 와 [행, 열] 의 순서, 그리고 img[1:4, 1:4] 로 잘라 내는 구간을 보인 그림](assets/img/diagram/ch02_coords.svg)
그림의 모눈은 가로 8칸, 세로 6칸짜리 그림입니다. 원점 (0, 0) 은 왼쪽 위이고, 초록 화살표 방향으로 x(열 번호)가, 보라 화살표 방향으로 y(행 번호)가 커집니다. 수학 시간의 그래프와 달리 y 는 아래로 갈수록 커집니다. 다홍 칸은 그림 함수로는 (x=5, y=2), 배열로는 img[2, 5] 입니다. 보라 점선 상자는 img[1:4, 1:4] 로 잘라 낸 9칸입니다. 여기서 극장의 "줄"이 행(y), "자리"가 열(x)입니다.
두 순서 견주기
| 쓰는 곳 | 순서 | 예 |
|---|---|---|
| 배열에서 칸 꺼내기 | [행(y), 열(x)] | img[186, 60] |
| 배열 잘라 내기 | [y 시작:y 끝, x 시작:x 끝] | img[150:222, 24:96] |
img.shape | (세로, 가로, 채널) | (240, 320, 3) |
그림 함수(cv2.circle, cv2.rectangle 등) | (x, y) | cv2.circle(img, (60, 186), 36, ...) |
크기를 주는 함수(cv2.resize) | (가로, 세로) | cv2.resize(img, (160, 120)) |
잘라 내기는 슬라이싱 한 줄
슬라이싱의 끝 번호는 들어가지 않습니다. img[150:222, 24:96] 은 150번부터 221번 줄까지 72줄, 24번부터 95번 칸까지 72칸입니다. 끝 − 시작 = 길이로 셉니다.
import cv2
img = cv2.imread("ch02_market.png")
# 수박의 가운데는 그림 함수로 (x=60, y=186). 배열에서는 [186, 60] 으로 꺼낸다
print("수박 가운데 BGR:", [int(v) for v in img[186, 60]])
# 가운데에서 위아래·좌우로 36칸씩 → [186-36 : 186+36, 60-36 : 60+36]
melon = img[150:222, 24:96]
print("잘라 낸 모양:", melon.shape) # 결과: (72, 72, 3)
# 잘라 낸 조각은 원본과 숫자를 함께 쓴다. 따로 쓰려면 copy() 로 복사한다
melon_copy = melon.copy()주의할 점
- 슬라이싱으로 잘라 낸 조각은 원본과 같은 숫자 칸을 가리킵니다. 조각을 칠하면 원본도 칠해집니다. 원본을 지키려면
.copy()를 붙입니다. - 그림 밖 번호로 잘라도 오류가 나지 않고 있는 만큼만 잘립니다. 잘라 낸 뒤
shape로 크기가 생각한 대로인지 확인합니다.