logo

마스크와 색상 기반 탐지

실습 준비

import cv2 as cv
import numpy as np
from yeom import to_pil

image = cv.imread("balloon.webp")

마스크

마스크(mask): 이미지에서 처리할 픽셀을 표시하는 1채널 배열. 원본 이미지와 높이·너비가 같고, 보통 uint8 자료형의 0과 255를 사용.

마스크 값 의미
0 선택하지 않은 영역
255 선택한 영역
mask_example = np.array(
    [
        [0, 0, 255, 255],
        [0, 255, 255, 0],
    ],
    dtype=np.uint8,
)
mask_example
실행 결과
array([[  0,   0, 255, 255],
       [  0, 255, 255,   0]], dtype=uint8)

마스크에는 원본의 색 정보가 없고, 각 위치의 사용 여부만 표시.

색상 범위로 마스크 만들기

원본 이미지와 HSV 색상 범위 HSV 색 공간은 색상 H와 밝기 V가 분리되어 있어 색 범위 지정에 유리.

hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)

lower = np.array([40, 50, 50], dtype=np.uint8)  # 초록 계열의 H·S·V 하한
upper = np.array([80, 255, 255], dtype=np.uint8)  # 초록 계열의 H·S·V 상한

HSV 범위에서 마스크를 만드는 과정

cv.inRange(): 각 채널이 하한과 상한 사이인 픽셀은 255, 나머지는 0으로 변환. 하한과 상한도 범위 안.

mask = cv.inRange(hsv, lower, upper)
mask.shape  # 형태
실행 결과
(1024, 1024)
mask.dtype  # 자료형
실행 결과
dtype('uint8')
np.unique(mask)  # 고유한 픽셀값
실행 결과
array([  0, 255], dtype=uint8)

결과는 원본과 높이·너비가 같은 2차원 uint8 배열. 고유 픽셀값은 0과 255.

to_pil(mask)

색상 범위에 해당하는 1채널 이진 마스크

마스크 적용

cv.bitwise_and()에 같은 이미지 두 개와 mask를 전달하면 선택한 픽셀만 원래 값 유지. 나머지는 0으로 바뀌어 검게 표시.

selected = cv.bitwise_and(image, image, mask=mask)
to_pil(selected)

마스크로 선택한 원본 이미지의 초록색 영역

같은 이미지끼리 AND한 픽셀값은 변화 없음. mask 인자는 연산 위치를 제한.

마스크 반전

cv.bitwise_not(): 각 비트를 반전. 0과 255로 구성된 마스크에서는 선택 영역과 제외 영역을 서로 교환.

inverse_mask = cv.bitwise_not(mask)
to_pil(inverse_mask)

선택 영역과 제외 영역이 바뀐 반전 마스크

excluded = cv.bitwise_and(image, image, mask=inverse_mask)
to_pil(excluded)

반전 마스크로 초록색 영역을 제외한 원본 이미지

반전 마스크에서는 기존 초록색 선택 영역이 검정이고 나머지 픽셀은 유지. 원래 마스크와 겹치지 않으며 두 마스크의 OR 결과는 전체 영역.

비트 연산

비트 연산(bitwise operation): 정수를 구성하는 각 비트를 같은 위치끼리 계산.

연산 결과가 1이 되는 조건
AND 두 비트가 모두 1
OR 하나 이상의 비트가 1
XOR 두 비트가 서로 다름
NOT 입력 비트를 반전

10과 12의 4비트 이진수 표현은 각각 1010, 1100.

a = np.array([10], dtype=np.uint8)
b = np.array([12], dtype=np.uint8)

AND

a b a AND b
0 0 0
0 1 0
1 0 0
1 1 1
cv.bitwise_and(a, b).item()  # AND 결과
실행 결과
8
AND: 1010 & 1100 = 1000 → 8

두 비트가 모두 1인 자리만 1. 10과 12에 공통인 8의 자리만 남아 결과는 8.

OR

a b a OR b
0 0 0
0 1 1
1 0 1
1 1 1
cv.bitwise_or(a, b).item()  # OR 결과
실행 결과
14
OR: 1010 | 1100 = 1110 → 14

두 비트 중 하나 이상이 1이면 결과 비트는 1. 두 수의 1을 합친 1110의 값은 14.

XOR

a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0
cv.bitwise_xor(a, b).item()  # XOR 결과
실행 결과
6
XOR: 1010 ^ 1100 = 0110 → 6

두 비트가 서로 다를 때만 결과 비트는 1. 4와 2의 자리가 남아 결과는 6.

NOT

a NOT a
0 1
1 0
cv.bitwise_not(a).item()  # NOT 결과
실행 결과
245
NOT: ~00001010 = 11110101 → 245

NOT은 각 비트의 0과 1을 교환. auint8이므로 8개 비트 전체를 반전한 결과는 245.

퀴즈

문제 1 / 5맞음: 0힌트: 0틀림: 0채점중: 0남음: 5

OpenCV 이미지 마스크의 일반적인 특징으로 맞는 것을 모두 고르세요.

  • 원본 이미지와 높이·너비가 같다
  • 1채널 uint8 배열을 사용한다
  • 이진 마스크는 보통 0과 255로 구성한다
  • 원본 이미지와 같은 BGR 색상값을 저장한다

퀴즈를 풀려면 대화형 기능을 불러와야 합니다.

Previous
좌표로 도형과 글자 그리기