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

8장. Threshold, Adaptive Threshold, Otsu

세 방법 견주기와 고르는 기준

길을 찾을 때 동네 길을 훤히 알면 지도 없이 가고, 처음 가는 길이면 내비게이션을 켜고, 공사 중인 길이 많으면 구간마다 길을 다시 찾습니다. 이진화도 사진의 형편에 따라 방법을 고릅니다. 조명이 고르고 커트라인을 알면 전역 임계값, 모르면 Otsu, 그늘이 지면 Adaptive Threshold 입니다.

전역 임계값, Otsu, Adaptive 의 특징과 쓰는 때를 나란히 놓은 비교 그림

초록 상자의 전역 임계값과 다홍 상자의 Otsu 는 둘 다 그림 전체에 숫자 하나를 쓰고, 그 숫자를 사람이 정하느냐 자동으로 고르느냐만 다릅니다. 보라 상자의 Adaptive 는 칸마다 기준이 다릅니다. 여기서 지도 없이 가는 것이 전역 임계값, 내비게이션이 Otsu, 구간마다 길을 다시 찾는 것이 Adaptive 입니다.

조명 보기, 노이즈 보기, 방법 고르기, 결과 확인의 네 단계 흐름도

고르는 순서는 그림처럼 네 단계입니다. 먼저 그늘·얼룩이 있는지 보고, 노이즈가 많으면 블러를 먼저 하고, 방법을 고른 뒤, 결과 그림을 보고 숫자를 고칩니다.

세 방법 견주기

견줄 것전역 임계값OtsuAdaptive Threshold
함수cv2.thresholdcv2.threshold + THRESH_OTSUcv2.adaptiveThreshold
임계값사람이 정한 숫자 하나히스토그램으로 자동 고른 숫자 하나칸마다 "주변 평균 − C"
돌려주는 것(임계값, 결과)(고른 임계값, 결과)결과 하나
정할 숫자thresh없음blockSize, C
잘 맞는 그림조명이 고르고 값을 아는 그림조명이 고르고 봉우리가 둘인 그림그늘·얼룩이 진 문서
약한 곳사진마다 숫자를 다시 정해야 한다그늘, 노이즈, 작은 물체넓은 빈 바탕의 잡티

짧은 예시

Python
import cv2

gray = cv2.imread("ch08_shadow_doc.png", cv2.IMREAD_GRAYSCALE)
clean = cv2.imread("ch08_clean_doc.png", cv2.IMREAD_GRAYSCALE)
# 그늘 없는 판을 127 로 나눈 것을 "정답"으로 삼는다
_, answer = cv2.threshold(clean, 127, 255, cv2.THRESH_BINARY)

results = {
    "전역 127": cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)[1],
    "Otsu": cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1],
    "Adaptive": cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                      cv2.THRESH_BINARY, 15, 10),
}
for name, out in results.items():
    # 정답과 같은 칸의 비율
    print(name, round(float((out == answer).mean()), 3))

교안 PC 에서는 전역 127 이 0.619, Otsu 가 0.560, Adaptive 가 0.987 입니다. 그늘진 안내문에서는 Adaptive 만 정답에 가깝습니다.

주의할 점

  • "정답과 같은 칸의 비율"은 바탕이 넓으면 높게 나오기 쉽습니다. 모두 흰색으로 칠해도 바탕만큼은 맞히기 때문입니다. 프로젝트에서는 글자를 찾은 비율도 함께 봅니다.
  • 한 가지 방법이 모든 사진에 가장 좋지는 않습니다. 사진 몇 장으로 세 방법을 견줘 보고 고릅니다.
← 이전 절8장 · Otsu 가 잘 안 맞는 경우와 블러 먼저 하기다음 절 →8장 · 실습 지도