이미지 임계 처리, Image Thresholding은 특정 임계값(threshold)를 기준으로 이미지의 픽셀값을 두 가지로 나누는 것이다. 물체와 배경을 분리하거나 이미지에서 특정 영역을 추출하는 가장 기본적인 방법으로 활용된다. 또한 텍스트 추출, 노이즈 제거 등에도 활용될 수 있다.
기본적인 binary thresholding에서는 픽셀값이 임계값보다 크면 255(흰색), 작으면 0(검은색)으로 변환한다. openCV에서는 binary thresholding의 여러가지 변형으로 몇가지를 제공한다.
- Binary Threshold Inverted: 임계값보다 크면 0, 작으면 255
- Truncated Threshold: 임계값보다 크면 임계값, 작으면 픽셀값 유지
- To Zero Threshold: 임계값보다 크면 픽셀값 유지, 작으면 0
- To Zero Inverted Threshold: 임계값보다 크면 0, 작으면 픽셀값 유지
img = cv2.imread("/content/drive/MyDrive/Dataset/opencv/Ganeshji.webp")
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh_binary = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY)
_, thresh_binary_inv = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY_INV)
_, thresh_trunc = cv2.threshold(gray_img, 120, 255, cv2.THRESH_TRUNC)
_, thresh_tozero = cv2.threshold(gray_img, 120, 255, cv2.THRESH_TOZERO)
_, thresh_tozero_inv = cv2.threshold(gray_img, 120, 255, cv2.THRESH_TOZERO_INV)

위에서 시도한 Simple Thresholding에서는 임계값이 하나로 고정된다. 하지만 이미지의 조명이 불규칙하거나 배경색이 여러가지인 경우 아래처럼 하나의 임계값을 사용했을 때 결과가 좋지 않을 수 있다. 이를 보완하기 위한 Adaptive Thresholding이 있다.

Adaptive Thresholding에서는 이미지 내에서 주변 픽셀값들에 따라 임계값을 조절한다. 임계값을 결정하는 방법에 따라서 Adaptive Mean Thresholding, Adaptive Gaussian Thresholding 두 가지로 나뉜다.
- Adaptive Mean Thresholding: 임계값 = 주변 픽셀들의 평균값 - C
thresh_mean = cv2.adaptiveThreshold(
gray_img, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,
199, 5
)
- Adaptive Gaussian Thresholding = 주변 픽셀들의 Weighted Sum - C
thresh_gauss = cv2.adaptiveThreshold(
gray_img, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
199, 5
)

Simple Thresholding을 적용했을 때 자동차의 세부적인 부분을 구분하지 못한 반면 Adaptive Thresholding을 적용했을 때는 임계값이 유동적으로 바뀌어 자동차의 형태를 선명하게 잡아냈다.
마지막으로 Binary Thresholding에 많이 사용되는 알고리즘으로 오츠의 알고리즘(Otsu's Binarization Method)이 있다. 오츠의 알고리즘은 여러 임계값을 시도해보면서 명암 분리가 극대화되는 임계값을 찾는다. 정확히는 이미지를 forgeground / bakground 으로 나눈 후 histogram을 그렸을 때 두 histogram 간 분산이 가장 커지는 임계값을 찾는 것이다.
# Otsu Thresholding: automatically determine optimal threshold valueto separate forgeground and backgound in a grayscale img
ret, otsu_thresh = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
