2장. 이미지 입출력과 영상 시각화
실습 3 — 좌표로 자리 찾고 잘라 내기
동네 장터의 진열대 그림(ch02_market.png)에서 눈금으로 물건의 자리를 읽고, 배열의 [행, 열] 로 꺼내고 잘라 냅니다. (x, y) 와 [행, 열] 의 순서가 거꾸로라는 것을 직접 확인합니다. 그림은 연습용 가상 그림입니다.
1단계. 눈금을 켜고 자리 읽기
import cv2
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False
img = cv2.imread("ch02_market.png")
h, w = img.shape[:2]
print(f"가로 {w}, 세로 {h}")
fig, ax = plt.subplots(figsize=(7, 5.4))
ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 20칸마다 눈금을 두고 옅은 격자선을 그어 자리를 읽기 쉽게 한다
ax.set_xticks(range(0, w + 1, 40))
ax.set_yticks(range(0, h + 1, 20))
ax.grid(color="white", alpha=0.6)
ax.set_xlabel("x (가로 칸 번호)")
ax.set_ylabel("y (세로 칸 번호)")
plt.show()가로 320, 세로 240
2단계. (x, y) 를 [행, 열] 로 바꿔 꺼내기
# 눈금으로 읽은 수박의 가운데: x=60, y=186
x, y = 60, 186
# 배열은 [행(y), 열(x)] 순서로 꺼낸다
print("img[y, x] = img[186, 60]:", [int(v) for v in img[y, x]], "→ 수박의 초록")
# 순서를 거꾸로 적으면 전혀 다른 자리(60번 줄, 186번 칸)를 읽는다
print("img[x, y] = img[60, 186]:", [int(v) for v in img[x, y]], "→ 다른 자리")img[y, x] = img[186, 60]: [40, 120, 30] → 수박의 초록
img[x, y] = img[60, 186]: [90, 170, 225] → 다른 자리3단계. 수박 잘라 내고 저장하기
# 수박은 가운데 (60, 186), 반지름 36. 둘레에 2칸 여유를 두고 자른다
# 행: 186-38 = 148 부터 186+38 = 224 앞까지, 열: 60-38 = 22 부터 60+38 = 98 앞까지
melon = img[148:224, 22:98].copy() # copy(): 원본과 숫자를 따로 쓰게 복사한다
print("잘라 낸 모양:", melon.shape)
ok = cv2.imwrite("out_ch02_watermelon.png", melon)
print("저장:", ok)잘라 낸 모양: (76, 76, 3)
저장: True4단계. 상자 목록으로 여러 개 잘라 보기
# 물건마다 (x, y, 가로, 세로) 상자. 그림 함수와 같은 가로 먼저 꼴로 적어 둔다
boxes = {"우유": (30, 22, 50, 86), "식빵": (118, 46, 84, 62), "당근": (230, 160, 72, 64)}
fig, axes = plt.subplots(1, 3, figsize=(8, 3), layout="constrained")
for ax, (name, (bx, by, bw, bh)) in zip(axes, boxes.items()):
# (x, y, 가로, 세로) → 배열 [y : y+세로, x : x+가로] 로 바꿔 자른다
piece = img[by:by + bh, bx:bx + bw]
ax.imshow(cv2.cvtColor(piece, cv2.COLOR_BGR2RGB), interpolation="nearest")
ax.set_title(f"{name} {piece.shape[1]}×{piece.shape[0]}")
ax.axis("off")
plt.show()
코드 설명
ax.set_xticks(range(0, w + 1, 40))는 가로축 눈금을 40칸마다 둡니다.ax.grid와 함께 쓰면 그림 위에서 자리를 읽기 쉽습니다.img[y, x]처럼 배열은 행(y)을 먼저 적습니다. 눈금으로 읽은 (x, y) 를 그대로img[x, y]로 적으면 전혀 다른 칸을 읽습니다.img[148:224, 22:98]은 148~223번 줄, 22~97번 칸을 잘라 76×76 칸이 됩니다. 끝 번호는 들어가지 않으므로 길이는 끝 − 시작입니다.- 상자를 (x, y, 가로, 세로) 로 적어 두고
img[y:y+세로, x:x+가로]로 바꾸는 꼴은 17장부터 다룰 객체 탐지의 상자에서도 똑같이 씁니다.