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

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

실습 1 — 픽셀 값 읽고 바꾸기

과일 바구니 그림(fruit_basket.png)의 픽셀을 읽고, 점과 영역을 칠하고, 동그라미와 네모를 그립니다. 이 그림은 OpenCV 로 도형을 그려 만든 연습용 가상 그림입니다. 칠할 때는 copy() 로 만든 복사본에 칠해 원본을 지킵니다.

1단계. 읽고 과일 세 칸의 색 보기

Python
import cv2
import matplotlib.pyplot as plt

plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False

img = cv2.imread("fruit_basket.png")
print("모양:", img.shape)                    # 결과: (세로, 가로, 채널)

# 배열은 [세로 y, 가로 x] 순서로 꺼낸다. 결과는 [B, G, R]
points = {"사과": (140, 135), "라임": (62, 128), "포도": (232, 127)}   # 이름: (x, y)
for name, (x, y) in points.items():
    b, g, r = img[y, x]
    print(f"{name} (x={x}, y={y}) → B={int(b)}, G={int(g)}, R={int(r)}")
출력
모양: (240, 320, 3)
사과 (x=140, y=135) → B=34, G=37, R=206
라임 (x=62, y=128) → B=42, G=186, R=92
포도 (x=232, y=127) → B=120, G=49, R=100

2단계. 복사본에 점, 영역, 도형 칠하기

Python
# copy(): 숫자 표를 통째로 하나 더 만든다. 이 복사본에만 칠한다
painted = img.copy()

# 한 칸 바꾸기: 왼쪽 위 칸을 흰색으로(BGR)
painted[0, 0] = (255, 255, 255)
# 영역 바꾸기: 세로 200~229, 가로 110~209 칸을 가격표처럼 흰색에 가깝게
painted[200:230, 110:210] = (245, 245, 245)
# cv2.circle(그림, 가운데 (x, y), 반지름, 색, 굵기): 사과에 파란 동그라미. 굵기 2 는 테두리만
cv2.circle(painted, (140, 135), 30, (255, 0, 0), 2)
# cv2.rectangle(그림, 왼쪽 위 (x, y), 오른쪽 아래 (x, y), 색, 굵기): 포도에 초록 네모
cv2.rectangle(painted, (185, 85), (272, 168), (0, 160, 0), 2)
# cv2.putText(그림, 글자, 글자 왼쪽 아래 (x, y), 글꼴, 크기, 색, 굵기): 가격표에 영어 글자
cv2.putText(painted, "APPLE 3", (122, 222), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (40, 40, 40), 2)

print("가격표 자리, 원본:", [int(v) for v in img[205, 115]])
print("가격표 자리, 복사본:", [int(v) for v in painted[205, 115]])
출력
가격표 자리, 원본: [35, 60, 95]
가격표 자리, 복사본: [245, 245, 245]

3단계. 이름표만 붙이면 원본도 바뀐다

Python
# alias = img 는 복사가 아니다. 같은 숫자 표에 이름을 하나 더 붙일 뿐이다
alias = img
alias[0:5, 0:5] = (0, 0, 0)          # alias 의 왼쪽 위 5×5 칸을 검게
print("img 의 왼쪽 위 칸:", [int(v) for v in img[0, 0]])   # img 도 검게 바뀌었다

# np.shares_memory: 두 배열이 같은 숫자 표를 함께 쓰면 True
import numpy as np
print("alias 와 img 가 같은 표인가:", np.shares_memory(alias, img))
print("painted 와 img 가 같은 표인가:", np.shares_memory(painted, img))

# 망가진 원본은 파일에서 다시 읽어 되돌린다
img = cv2.imread("fruit_basket.png")
print("다시 읽은 왼쪽 위 칸:", [int(v) for v in img[0, 0]])
출력
img 의 왼쪽 위 칸: [0, 0, 0]
alias 와 img 가 같은 표인가: True
painted 와 img 가 같은 표인가: False
다시 읽은 왼쪽 위 칸: [206, 230, 244]

4단계. 원본과 칠한 그림 나란히 보기

Python
fig, axes = plt.subplots(1, 2, figsize=(9, 3.6))
# 띄울 때는 RGB 로 바꾼다
axes[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0].set_title("원본 (그대로)")
axes[1].imshow(cv2.cvtColor(painted, cv2.COLOR_BGR2RGB))
axes[1].set_title("복사본에 칠하고 그림")
for ax in axes:
    ax.axis("off")
plt.tight_layout()
plt.show()
원본 바구니 그림과, 사과에 파란 동그라미, 포도에 초록 네모, 흰 가격표를 칠한 복사본을 나란히 놓은 결과

코드 설명

  • img[y, x] 는 [세로, 가로] 자리의 칸 하나로, [B, G, R] 세 숫자를 돌려줍니다. 사과는 R, 라임은 G, 포도는 B 와 R 이 큽니다.
  • painted[200:230, 110:210] = (245, 245, 245) 는 슬라이싱으로 고른 30줄 × 100칸을 한꺼번에 칠합니다. 반복문 없이 한 줄로 됩니다.
  • cv2.circle, cv2.rectangle, cv2.putText 는 그림 위에 바로 그립니다(돌려받지 않아도 그림이 바뀝니다). 자리는 모두 (x, y) 순서이고, cv2.putText 는 한글을 쓰지 못해 영어로 적었습니다.
  • alias = img 는 같은 표에 이름표만 붙여서 np.shares_memory 가 True 입니다. img.copy() 로 만든 painted 는 False 라, 칠해도 원본이 그대로입니다.
← 이전 절3장 · 실습 지도다음 절 →3장 · 실습 2 — 해상도와 데이터형 살펴보기