OpenCV 비전 실무4장 · 채널 처리와 히스토그램 분석11 / 21← 이전목차다음 →MetaContents

4장. 채널 처리와 히스토그램 분석

마스크로 일부만 세기

교실 전체의 시험 점수 분포 말고 "앞줄 학생들만"의 분포가 궁금할 때가 있습니다. 출석부에서 앞줄 학생 이름에만 형광펜을 칠해 두고, 칠한 학생만 세면 됩니다. 마스크가 그 형광펜입니다. 그림과 같은 크기의 판에 셀 곳만 흰색(255)으로 칠해 cv2.calcHist 의 셋째 인자로 줍니다.

그림과 같은 크기의 검은 판에 흰 네모를 칠하고, calcHist 의 셋째 인자로 주어 흰 곳의 픽셀만 세는 네 단계 흐름도

그림의 네 단계를 따라 마스크를 만들고 씁니다. 여기서 출석부가 그림이고, 형광펜을 칠한 이름이 마스크의 흰 칸입니다. 3장의 cv2.inRange 가 돌려주는 흑백 판도 같은 꼴이라 그대로 마스크로 쓸 수 있습니다.

노을 그림, 해 둘레만 흰 네모로 칠한 마스크, 마스크를 씌워 해 둘레만 남긴 모습

가운데 그림이 마스크입니다. 해 둘레의 가로 70칸, 세로 70칸만 흰색이므로 4,900칸만 셉니다. 오른쪽은 세는 곳만 남겨 보여 준 모습입니다.

마스크의 약속

항목약속
크기그림과 세로·가로가 같아야 한다
자료형uint8
채널하나(흑백 판)
값0 이 아닌 칸(보통 255)만 센다

짧은 예시

Python
import cv2
import numpy as np

img = cv2.imread("ch04_scenes/sunset.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 그림과 같은 크기의 검은 판을 만들고, 해 둘레(세로 105~174, 가로 165~234)만 흰색으로
mask = np.zeros(gray.shape, dtype=np.uint8)
mask[105:175, 165:235] = 255

whole = cv2.calcHist([gray], [0], None, [256], [0, 256])
part = cv2.calcHist([gray], [0], mask, [256], [0, 256])   # 셋째 인자에 마스크
print(int(whole.sum()), int(part.sum()))   # 결과: 76800 4900

# cv2.mean 도 mask 를 받는다: 흰 칸만의 평균
print(round(cv2.mean(gray, mask=mask)[0], 1), round(cv2.mean(gray)[0], 1))

주의할 점

  • 마스크의 크기가 그림과 다르면 오류가 납니다. np.zeros(gray.shape, ...) 처럼 그림의 모양을 그대로 씁니다.
  • 마스크로 센 막대는 전체보다 훨씬 낮습니다. 전체와 일부를 한 그래프에서 견주려면 막대를 픽셀 수로 나눠 비율로 바꿉니다.
← 이전 절4장 · 컬러 히스토그램다음 절 →4장 · 히스토그램으로 할 수 있는 일