OpenCV 비전 실무13장 · Shape 분석과 ROI 처리10 / 21← 이전목차다음 →MetaContents

13장. Shape 분석과 ROI 처리

사각형 ROI

도서관에서 책 한 쪽을 볼 때 두 가지 방법이 있습니다. 책 위에 네모난 구멍이 뚫린 종이(창)를 대고 보거나, 그 쪽을 복사기로 복사해 따로 봅니다. 창으로 보는 동안 연필로 칠하면 책에 칠해지고, 복사본에 칠하면 책은 그대로입니다. NumPy 슬라이싱으로 자른 ROI 는 창이고, .copy() 를 붙이면 복사본입니다.

슬라이싱으로 자른 ROI 는 원본을 보는 창(보기)이고, copy 를 붙이면 따로 숫자를 가진 복사본이라는 비교 그림

왼쪽 상자가 창(보기, view), 오른쪽 상자가 복사본(copy)입니다. 2장에서 잘라 내기를, 3장에서 copy 를, 4장에서 보기와 복사본의 차이를 봤습니다. ROI 에서는 이 차이가 특히 중요합니다. ROI 를 고쳐서 원본에 바로 반영하고 싶으면 창이 편하고, 원본을 지키면서 ROI 만 따로 실험하려면 복사본을 씁니다. 여기서 구멍 뚫린 종이가 슬라이싱, 복사기가 .copy() 입니다.

슬라이싱 ROI 견주기

쓰는 법원본과 숫자를 함께 쓰나ROI 를 칠하면 원본은쓰는 때
roi = img[y:y+h, x:x+w]함께 쓴다(창)함께 바뀐다ROI 를 고쳐 원본에 반영
roi = img[y:y+h, x:x+w].copy()따로 쓴다(복사본)그대로원본을 지키며 따로 실험, 저장
img[y:y+h, x:x+w] = 새조각(대입)그 자리가 새조각으로 바뀐다처리한 조각 붙여 넣기

boundingRect 로 ROI 정하기와 여백

좌표를 손으로 재지 않고, 윤곽선의 cv2.boundingRect 가 돌려준 (x, y, 가로, 세로) 로 자르면 ROI 를 자동으로 정할 수 있습니다. 이때 둘레에 여백을 붙이면 가장자리가 잘리지 않습니다. 그런데 여백 때문에 시작 번호가 0 보다 작아지면 큰 문제가 생깁니다. 파이썬 슬라이싱에서 음수 번호는 "끝에서부터"라는 뜻이라, img[-10:50] 은 오류 없이 빈 조각을 돌려줍니다.

여백 없이 자른 송장, 여백 10을 붙여 자른 송장, 여백이 그림 밖으로 나가 잘린 스티커를 나란히 놓은 그림

왼쪽은 상자에 딱 맞게, 가운데는 여백 10칸을 붙여 자른 송장입니다. 가운데 쪽이 송장의 흰 테두리가 온전히 보입니다. 오른쪽은 스티커에 여백 40칸을 붙인 결과입니다. 아래쪽 끝이 그림 끝(세로 240)을 넘어서 그 자리까지만 잘렸습니다. 이렇게 시작은 max(0, ...) 로, 끝은 min(그림 크기, ...) 로 그림 안에 묶어 둡니다.

계산송장(x=60, 여백 10)송장(x=60, 여백 70)
시작 = x − 여백50−10
그냥 자르면50번 칸부터끝에서 10번째 칸부터 → 빈 조각
max(0, x − 여백)500

짧은 예시

Python
import cv2

img = cv2.imread("ch13_parcel.png")
H, W = img.shape[:2]

x, y, w, h = 60, 40, 145, 113   # 송장의 boundingRect
m = 70                          # 일부러 큰 여백

# 그냥 자르면: 시작 번호가 음수(-30, -10)가 되어 "끝에서 30번째 줄부터", "끝에서 10번째 칸부터"로 읽힌다
bad = img[y - m:y + h + m, x - m:x + w + m]
print(bad.shape)                # 결과: (13, 0, 3) → 가로는 0칸, 세로는 엉뚱한 13줄

# max(0, ...), min(크기, ...) 로 그림 안에 묶는다
y0, y1 = max(0, y - m), min(H, y + h + m)
x0, x1 = max(0, x - m), min(W, x + w + m)
safe = img[y0:y1, x0:x1]
print((x0, y0, x1, y1), safe.shape)   # 결과: (0, 0, 275, 223) (223, 275, 3)

np.clip(값, 아래, 위) 로도 같은 일을 합니다. np.clip(x - m, 0, W) 는 max(0, min(W, x - m)) 과 같습니다.

주의할 점

  • 슬라이싱 ROI 는 원본을 보는 창입니다. cv2.rectangle 처럼 그리는 함수를 ROI 에 쓰면 원본에도 그려집니다. 원본을 지키려면 .copy() 를 붙입니다.
  • 슬라이싱 순서는 [세로, 가로] 이고, boundingRect 는 (x, y, 가로, 세로) 입니다. img[y:y+h, x:x+w] 처럼 y 를 먼저 씁니다(2장).
  • 시작 번호가 음수가 되면 오류 없이 빈 조각이 나옵니다. 자른 뒤 shape 를 찍어 보거나, 처음부터 max(0, ...) 로 묶습니다.
← 이전 절13장 · ROI 란다음 절 →13장 · 모양 ROI