图像分割是计算机视觉最基础的任务。在图像分割中,最基础的方法便是阈值分割。阈值分割,顾名思义就是使用一个阈值将图像背景和前景分开。OSTU,即大津法是阈值分割算法中常用的算法之一。总体而言,大津法的思路是寻找一个可以使得背景和前景两类像素之间类间距离最大化。详细的思路如下:
我们定义前景类为,总共有个像素,背景类为?, 总共有个像素。那么这种图像一个有个像素。
对于,其像素的概率为, 其灰度平均值为?,?对于,其像素的概率为, 其灰度平均值为, 那么所有它们的方差为:
其中,表示灰度值为i的像素的比例,i 为灰度值。我们的目的即使找到一个阈值K,低于K的像素归为, 大于K归为类 ,从而使得最大。我们可以表达为:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?对于如何寻找最佳的K,对于一张灰度图像,其灰度值范围在0-255之间,我们可以遍历这256个值来寻找最佳的K。如果想要减少计算量,那么最简单的方法便是绘制灰度直方图,找到两个峰之间的谷,取一定范围遍历,寻找最佳的K。
import cv2
import numpy as np
def get_mean(histogram):
total=np.sum(histogram)
mean=0
for i in range(len(histogram)):
mean+=(histogram[i]/total)*i
return mean
def get_variance(histogram,mean):
total=np.sum(histogram)
variance=0
for i in range(len(histogram)):
variance+=(histogram[i]/total)*((i-mean)**2)
return variance
def OSTU(img):
h,w=img.shape
total=h*w
best_k=0
max_variance=-10000
histogram=np.zeros(256)
for i in range(h):
for j in range(w):
histogram[img[i,j]]+=1
for k in range(256):
bg=histogram[:k]
object=histogram[k:]
bg_mean=get_mean(bg)
object_mean=get_mean(object)
bg_variance=get_variance(bg,bg_mean)
object_variance=get_variance(object,object_mean)
variance=bg_variance+object_variance
if(variance>max_variance):
max_variance=variance
best_k=k
img[img>=best_k]=255
img[img<best_k]=0
return img
|