otsu分割算法
otsu算法是一种确定阈值的算法,也叫最大类间方差法,是由日本学者大津于1979年提出的,可见也是比较老的经典的算法了~
之所以称为最大类间方差法是因为,用阈值进行的图像固定阈值二值化,类间方差最大化,是按照图形的灰度特性分为前景与背景。是类间方差最大的分割意味着错分概率最小。
原理:其实原理不难,涉及到的计算就是均值方差及一些公式推导,可以反推。对于图像M(x,y),假设存在阈值T将图像分为前景与背景。其中前景像素数占整张图像的比例为w0,平均灰度值为u0;背景像素数占整张图像比例为w1,平均灰度值为u1。图像的总平均灰度记为u,类房间差记为g。
假设图像大小为M*N,图像中像素值小于阈值T的像素数为N0,像素值大于阈值T的像素数为N1,那么就有如下的公式:
(1) w0=N0 / M x N
(2) w1=N1/ M x N
(3)N0+N1=M x N
(4)w0+w1=M x N
(5)u = w0 x u0+w1 x u1
根据计算方差公式 (6) g=w0 x (u-u0)²+w1x(u-u1)²
将公式(5)带入到公式(6)中,得到等价公式:
(7)g=w0 x w1x(u0-u1)²
然后遍历求类间方差g最大的阈值T。
优缺点:
优点:算法简单,当目标与背景的面积相差不大时,能够有效地对图像进行分割。
缺点:当图像中的目标与背景的面积相差很大时,表现为直方图没有明显的双峰,或者两个峰的大小相差很大,分割效果不佳,或者目标与背景的灰度有较大的重叠时也不能准确的将目标与背景分开。
原因:该方法忽略了图像的空间信息,同时将图像的灰度分布作为分割图像的依据,对噪声也相当敏感。
Python代码实现:
import numpy as np
def otsu_threshold(im):
width, height = im.size
img_size = width * height
pixel_counts = np.zeros(256)
for x in range(width):
for y in range(height):
pixel = im.getpixel((x, y))
pixel_counts[pixel] = pixel_counts[pixel] + 1
# 得到图片的以0-255索引的像素值个数列表
s_max = (0, -10)
for threshold in range(256):
# 遍历所有阈值
# 更新
n_0 = sum(pixel_counts[:threshold]) # 得到阈值以下像素个数
n_1 = sum(pixel_counts[threshold:]) # 得到阈值以上像素个数
w_0 = n_0 / img_size
w_1 = n_1 / img_size
# 得到阈值下所有像素的平均灰度
u_0 = sum([i * pixel_counts[i] for i in range(0, threshold)]) / n_0 if n_0 > 0 else 0
# 得到阈值上所有像素的平均灰度
u_1 = sum([i * pixel_counts[i] for i in range(threshold, 256)]) / n_1 if n_1 > 0 else 0
# 总平均灰度
u = w_0 * u_0 + w_1 * u_1
# 类间方差
g = w_0 * (u_0 - u) * (u_0 - u) + w_1 * (u_1 - u) * (u_1 - u)
# 类间方差等价公式
# g = w_0 * w_1 * (u_0 * u_1) * (u_0 * u_1)
# 取最大的
if g > s_max[1]:
s_max = (threshold, g)
return s_max[0]
另外有聚义计算的博客地址:这里



