OpenCV 비전 실무8장 · Threshold, Adaptive Threshold, Otsu5 / 21← 이전목차다음 →MetaContents

8장. Threshold, Adaptive Threshold, Otsu

임계값 방식 다섯 가지

택배 상자를 무게로 나누는 장면을 떠올려 봅시다. "5kg 넘으면 빨간 딱지, 아니면 아무것도 안 붙임"으로 나눌 수도 있고, "5kg 넘는 상자는 5kg 짜리로 쳐서 요금을 깎아 줌"처럼 다르게 처리할 수도 있습니다. cv2.threshold 의 넷째 인자 type 은 커트라인을 넘은 칸과 못 넘은 칸을 어떻게 적을지를 고릅니다.

0~255 로 고르게 오르는 한 줄에 다섯 가지 방식을 적용해 들어간 밝기와 나온 밝기를 그린 여섯 그래프

그래프마다 가로는 들어간 밝기, 세로는 나온 밝기이고, 갈색 점선이 임계값 127 입니다. 왼쪽 위의 회색 선은 아무것도 하지 않은 입력이라 곧게 오릅니다. 초록 BINARY 는 127 에서 0 에서 255 로 뛰어오르고, 다홍 BINARY_INV 는 거꾸로 255 에서 0 으로 떨어집니다. 보라 TRUNC 는 127 위를 평평하게 깎고, 갈색 TOZERO 는 127 아래만 0 으로, 산호 TOZERO_INV 는 127 위만 0 으로 만듭니다. 여기서 빨간 딱지를 붙이는 것이 BINARY, 무거운 상자를 5kg 으로 쳐 주는 것이 TRUNC 입니다.

다섯 방식 견주기

방식임계값보다 큰 칸임계값 이하인 칸[30, 100, 127, 128, 200] 의 결과쓰는 곳
THRESH_BINARYmaxval0[0, 0, 0, 255, 255]밝은 물체를 흰색으로
THRESH_BINARY_INV0maxval[255, 255, 255, 0, 0]어두운 글자·물체를 흰색으로
THRESH_TRUNC임계값그대로[30, 100, 127, 127, 127]너무 밝은 곳을 눌러 주기
THRESH_TOZERO그대로0[0, 0, 0, 128, 200]어두운 바탕만 지우기
THRESH_TOZERO_INV0그대로[30, 100, 127, 0, 0]밝은 곳만 지우기

앞의 두 방식만 결과가 0 과 255 두 값인 이진 그림입니다. 나머지 셋은 밝기의 일부를 남기므로 엄밀히는 이진화가 아니지만, 같은 함수로 하므로 함께 배웁니다.

짧은 예시

Python
import cv2
import numpy as np

row = np.array([[30, 100, 127, 128, 200]], dtype=np.uint8)
kinds = ["THRESH_BINARY", "THRESH_BINARY_INV", "THRESH_TRUNC", "THRESH_TOZERO", "THRESH_TOZERO_INV"]
for name in kinds:
    # getattr(cv2, 이름): 이름 글자로 cv2 의 상수를 꺼낸다
    _, out = cv2.threshold(row, 127, 255, getattr(cv2, name))
    print(f"{name:18}", out.ravel().tolist())
# 결과: 위 표의 다섯 줄과 같다

getattr 은 get attribute(속성 꺼내기)를 줄인 이름입니다. 상수 다섯 개를 하나씩 쓰지 않고 이름 목록으로 돌려 봅니다.

주의할 점

  • 3장의 마스크처럼 "고른 것이 흰색"이 되게 하려면, 어두운 글자나 부품을 고를 때 THRESH_BINARY_INV 를 씁니다.
  • TRUNC 와 TOZERO 에서는 maxval 을 쓰지 않습니다. 그래도 자리를 채우려고 255 를 줍니다.
← 이전 절8장 · 전역 임계값과 cv2.threshold다음 절 →8장 · 임계값을 고르는 어려움