1.Otsu法
otsu方法也叫做大津法、类间最大方差法
otsu方法的核心思想是假设一幅图像,这幅图像被分为了前景区域C1和背景区域C2,那么我们应该用什么样的思想推出最佳分割阈值?日本学者大津在197x年给出了他的答案。
otus假设存在阈值TH,将所有像素分割为前景C1和背景C2,接下来进行数学推导
TH:滑动开关,遍历0-255轴,记录出现的4个相关数据p1 p2 m1 m2 成为一个资料表
P1、P2:对应像素出现在C1、C2区域的概率
m1、m2:对应区域C1与C2平均像素值
最后利用TH生成的资料表,计算出图中3公式的值,也称为类间方差,这个值越大,说明被分割区域越清晰,otus方法暴力穷举了分割阈值TH,不需要人为给定参数,同时,也有多阈值分割的otus方法,缺点则是计算量大
import cv2 as cv
import numpy as np
def grayscale(img):
r = img[:, :, 2].copy()
g = img[:, :, 1].copy()
b = img[:, :, 0].copy()
out = 0.2126*r + 0.7152*g + 0.0722*b
out = out.astype(np.uint8)
return out
def otsu(img, th=0):
max_th = 0
max_sigma = 0
for _x in range(1, 255):
# 公式元素准备
v0 = img[np.where(img < _x)]
m0 = np.mean(v0) if len(v0) > 0 else 0.
w0 = len(v0)/(h * w)
v1 = img[np.where(img > _x)]
m1 = np.mean(v1) if len(v0) > 0 else 0.
w1 = len(v1)/(h * w)
# 计算类间方差
sigma = w0 * w1 * (m1 - m0)**2
if sigma >= max_sigma:
max_sigma = sigma
max_th = _x
print('the best threshould is: %d', max_th)
print('the best sigma is: %d', max_sigma)
# 阈值分割
th = max_th
img[img < th] = 0
img[img >= th] = 128
return img
# run main
img = cv.imread('your/path/jpg')
h, w, c = img.shape
out = grayscale(img).astype(np.float32)
img = otsu(out)
cv.imshow('otsu_method', img); cv.waitKey(0)
2.基本的全局阈值处理
基本全局阈值方法与otsu方法相似,只能处理没有光照渐变的图像
流程为:
1.选择T作为初始估计值;
2.利用T的取值将图像分为两个区域C1,C2;
3.计算两个区域的平均灰度f1、f2;
4.计算f0 = (f1 + f2)/2,得到新灰度值f0,进行判断是否f0<Ω,Ω为人为给定,若满足条件则停止计算,不满足则用f0再次计算;
最终的处理图片两幅看不出有什么变换,不过后一种方法需要人为给定开始条件与停止条件,有可能处理时停止条件永远也满足不了。
也有双峰法,找到灰度直方图的双峰最高点,记录这两个点的所在区间向下搜索,找到谷底对应的灰度值,以谷底为分割阈值,但是我觉得想让一张图片只出现两个驼峰,有点难,万一有很多驼峰分割起来会很麻烦。