Otsu算法
图像分割是一个经典的图像任务,Otsu算法是借用图像的灰度值,计算几个阈值,然后起到分割图像的作用。本文介绍的Otsu算法常用于基于图像分割的聚类。该算法的理论依据是:假定图像包含两类像素(前景像素和背景像素),直方图为双峰直方图,然后计算使得两类像素能分开的最佳阈值(类内方差),或等价的间类间方差最大。
算法过程
对于图像 I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为 w0,平均灰度为 μ0;背景像素点数占整幅图像的比例为w1,平均灰度为 μ1;整幅图像的平均灰度记为μ,类间方差记为g。
假设图像大小为M×N,图像中像素的灰度值小于阈值T 的像素个数为 N0,像素灰度大于阈值T的像素个数为 N1,那么:
w0=M×NN0(1.1)
w1=M×NN1(1.2)
N0+N1=M×N(1.3)
w0+w1=1(1.4)
μ=w0∗μ0+w1∗μ1(1.5)
g=w0(μ0−μ)2+w1(μ1−μ)(1.6)
g=w0w1(μ0−μ1)2(1.7)
采用遍历的方法使得类间方差g最大的阈值T,即为所求。采用阈值的方法一定会存在边界问题,Otsu算法也是一样的,所以Otsu算法是有自己的应用场景的,例如Otsu算法常常用在车牌检测类型的任务上。
举个栗子
# coding=utf-8
import numpy as np
def OTSU(img_array): # 传入的参数为ndarray形式
height = img_array.shape[0]
width = img_array.shape[1]
count_pixel = np.zeros(256)
for i in range(height):
for j in range(width):
count_pixel[int(img_array[i][j])] += 1
max_variance = 0.0
best_thresold = 0
for thresold in range(256):
n0 = count_pixel[:thresold].sum()
n1 = count_pixel[thresold:].sum()
w0 = n0 / (height * width)
w1 = n1 / (height * width)
u0 = 0.0
u1 = 0.0
for i in range(thresold):
u0 += i * count_pixel[i]
for j in range(thresold, 256):
u1 += j * count_pixel[j]
u = u0 * w0 + u1 * w1
tmp_var = w0 * np.power((u - u0), 2) + w1 * np.power((u - u1), 2)
if tmp_var > max_variance:
best_thresold = thresold
max_variance = tmp_var
return best_thresold