在進行圖像二值化的操作中,我們往往要去去定一個閾值,像素值小於閾值的爲背景,像素值大於背景的爲前景。不同的閾值選擇會產生出截然不同的二值化圖像。因此,如何選取一個合適的閾值,是一個關鍵的問題。
大津算法,作爲一個自動確定二值化閾值的算法,是從類內方差和類間方差的比值計算得來,各種方差的定義如下:
類內方差:
類間方差:
圖像所有像素的方差:
在上式中,我們令小於閾值的類記爲,大於閾值的類記爲;
和是閾值分開的兩個類中的像素數佔總像素數的比值(滿足);
, 是這兩個類中像素值的方差;
,是這兩個類的像素值的平均值;
根據上面的式子,我們定義分離度:
在上式中,我們希望最大化分離度,即最大化類間方差,同時最小化類內方差。但由於類間方差與類內方差之和爲常數,因此問題轉化爲最大化類間方差,也就是說:
因此,如果使最大,就可以得到最好的二值化閾值。
代碼實現
import cv2
import numpy as np
#將BGR圖像轉化爲灰度圖(opencv默認顏色通道爲BGR)
def RGB2GRAY(img):
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
#大津算法得到二值化圖像
def otsu(img):
max_sigma = 0
max_t = 0
for t in range(1, 255):
v0 = img[img < t]
m0 = np.mean(v0) if len(v0) else 0.
w0 = len(v0) / (H*W)
v1 = img[img >= t]
m1 = np.mean(v1) if len(v1) else 0.
w1 = len(v1) / (H * W)
sigma = w0 * w1 * ((m0 - m1) ** 2)
if sigma > max_sigma:
max_sigma = sigma
max_t = t
print('t = ', max_t)
img[img < max_t] = 0
img[img >= max_t] = 255
return img
img = cv2.imread('../imori.jpg').astype(np.float)
gray = RGB2GRAY(img)
H, W = gray.shape
out = otsu(gray)
cv2.imwrite('4.jpg', out)
cv2.imshow('otsu', out)
cv2.waitKey()
cv2.destroyAllWindows()