3장. 디지털 영상과 색공간 변환
픽셀과 좌표 다시 보기
극장 좌석표를 떠올려 봅시다. "F열 12번"처럼 줄과 자리 번호를 대면 좌석 하나가 정해집니다. 좌석에 앉은 사람을 바꾸고 싶으면 그 좌석 번호만 대면 되고, 한 줄을 통째로 단체석으로 바꿀 수도 있습니다. 이미지의 픽셀도 줄 번호와 칸 번호로 찾아가 읽고 바꿉니다.
왼쪽은 과일 바구니 그림이고, 다홍 네모가 사과 위의 5×5 칸입니다. 오른쪽은 그 칸을 크게 키운 것으로, 칸마다 위에서부터 B, G, R 숫자가 적혀 있습니다. 빨간 곳은 셋째 숫자(R)가 217 로 크고, 빛 반사가 닿은 곳은 세 숫자가 모두 커져 옅은 빨강이 됩니다. 여기서 극장이 그림이고, 좌석이 픽셀이고, "F열 12번"이 [y, x] 입니다.
읽고 바꾸는 법
좌표의 두 가지 순서, 곧 함수에는 (x, y) 를, 배열에는 [행, 열] 을 주는 규칙은 2장에서 보았습니다. 이 장에서는 그 위에서 값을 바꾸는 법을 익힙니다.
| 하고 싶은 일 | 코드 | 뜻 |
|---|---|---|
| 한 칸 읽기 | img[135, 140] | 세로 135, 가로 140 칸의 [B, G, R] |
| 한 칸의 한 채널 읽기 | img[135, 140, 2] | 그 칸의 R(2번 채널) 하나 |
| 한 칸 바꾸기 | img[135, 140] = (255, 255, 255) | 그 칸을 흰색으로 |
| 영역 바꾸기 | img[200:230, 110:210] = (245, 245, 245) | 세로 200~229, 가로 110~209 칸을 한꺼번에 |
| 동그라미 그리기 | cv2.circle(img, (140, 135), 30, (255, 0, 0), 2) | 가운데 (x, y), 반지름, 색, 굵기 |
import cv2
img = cv2.imread("fruit_basket.png")
# 배열은 [세로, 가로] 순서: 왼쪽 사과의 가운데 칸
print(img[135, 140]) # 결과: [ 34 37 206] → B, G, R
# 슬라이싱으로 영역을 한꺼번에 칠한다. 원본을 지키려고 copy() 한 그림에 칠한다
tag = img.copy()
tag[200:230, 110:210] = (245, 245, 245)
# cv2.circle 은 (x, y) 순서로 가운데를 받는다. 굵기 2 는 테두리만, -1 이면 속까지 칠한다
cv2.circle(tag, (140, 135), 30, (255, 0, 0), 2)
print(img[215, 160], tag[215, 160]) # 결과: 원본은 바구니 색 그대로, tag 는 [245 245 245]왼쪽은 이름표만 하나 더 붙인 경우, 오른쪽은 복사본을 만든 경우입니다. 서류에 메모하고 싶을 때 원본 대신 복사본에 쓰는 것과 같습니다. 파이썬에서 b = a 는 서류를 복사하지 않고, 같은 서류에 이름표를 하나 더 붙입니다.
주의할 점
b = img로 받은 뒤b를 칠하면img도 바뀝니다. 원본을 지키려면b = img.copy()로 복사본을 만듭니다.- 슬라이싱
img[200:230, ...]의 끝 번호(230)는 들어가지 않습니다. 200~229 의 30줄입니다. - 배열 밖의 칸(예:
img[300, 10], 세로가 240칸인 그림)을 읽으면IndexError로 멈춥니다.cv2.circle처럼 그리는 함수는 그림 밖으로 나간 부분을 조용히 잘라 냅니다.