Otsu简介
即最大类间方差法,是一种图像二值化的算法,利用阈值将原图像分成前景,背景两个图象。当取最佳阈值时,背景应该与前景差别最大,关键在于如何选择衡量差别的标准,而在otsu算法中这个衡量差别的标准就是最大类间方差。
具体公式推导参考:https://www.cnblogs.com/xiaomanon/p/4110006.html
python源码
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 8 18:31:35 2019
@author: lenovo
"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def OTSU(gray):
hist = cv.calcHist([gray],[0],None,[256],[0,256])#255*1的灰度直方图的数组
gray_size = gray.size#图像像素数
k = 0#初始化灰度阈值
best_k = 0#最佳阈值
best_M = 0#衡量阈值性
p = []#灰度出现概率
#for k in range(30,150):
for i in range(len(hist)):
p.insert(i,hist[i][0]/gray_size) #灰度集概率分布
for k in range(30,150):
u = 0#从1到k的累计出现概率的平均灰度级
u_t = 0#从1到256的累计出现概率的平均灰度级
σ2_0 = 0#类内方差
σ2_1 = 0#类内方差
σ2_t = 0#灰度级的总方差
sum_0 = np.sum(hist[0:k+1:], axis=0)
sum_1 = np.sum(hist[k+1:256:], axis=0)
w_0 = np.sum(p[0:k+1:])
w_1 = np.sum(p[k+1:256:])#各类的概率
for i in range(k+1):
u = i*p[i]+u
for i in range(len(hist)):
u_t = i*p[i]+u_t
u0 = u/w_0
u1 = (u_t - u)/w_1#各类的平均灰度级
for i in range(k+1):
σ2_0 = (p[i]/w_0)*np.square(i-u0) + σ2_0
for i in range(k+1,256):
σ2_1 = (p[i]/w_1)*np.square(i-u1) + σ2_1#两类的类内方差
for i in range(256):
σ2_t = p[i]*np.square(i-u_t) + σ2_t#总方差
σ2_w = w_0*σ2_0+w_1*σ2_1#类内方差
σ2_b = w_0*w_1*np.square(u1-u0)#类间方差
M = σ2_b/σ2_t#衡量阈值k的好坏
if M>best_M:
best_M = M;
best_k= k;
return best_M,best_k
if __name__ == "__main__":
img = cv.imread('flower.jpg')#读取图像(BGR)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) #转灰度图像
M,k = OTSU(gray)
print(M,k)
ret,thresh1=cv.threshold(gray,k,255,cv.THRESH_BINARY)
cv.imshow("histogram", thresh1)
分析
灰度直方图:
总结
Otsu算法在处理目标和背景大小相差不大时(灰度直方图具有典型双峰性)效果还好,否则二值化效果不理想。