大津法 二值化
-
参考了 https://blog.csdn.net/qq_41398808/article/details/103404313
-
这篇博文提到的公式看上去有点晦涩 ,代码实现其实非常简单,建议直接看我新写的代码去理解
-
大津 (OSTU ,おつ) 日本人名。很多人写成大律,不过也能在Google中搜索到,不必纠结。
-
关键点 #按当前的i 来分割时候 ,如果前景类中一个像素也没有 ,自然平均值也是0
-
完整代码
import numpy as np
import cv2
import matplotlib.pyplot as plt
#————————————————
#版权声明:本文为CSDN博主「猫猫虫(——)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
#原文链接:https://blog.csdn.net/qq_41398808/article/details/103404313
class OTSU():
def __init__(self, img_path):
img = cv2.imread(img_path)
self.img = img
img_gray = self.Gray()
self.img = img_gray
num_list = self.Pixel_num()
self.num_list = num_list
rate_list = self.Pixel_rate()
self.rate_list = rate_list
optimal_pixel = self.Optimal_partition()
optimal_pixelEx =self.Optimal_partitionEx()
assert(optimal_pixel== optimal_pixelEx)
self.optimal_pixel = optimal_pixel
def Gray(self):
a = np.shape(self.img)
r,g,b = cv2.split(self.img)
img_new = np.zeros((a[0], a[1]))
for i in range(a[0]):
for j in range(a[1]):
data = (299*r[i][j] + 587*g[i][j] + 114*b[i][j])/1000
img_new[i][j] = data
img_new = img_new.astype('uint8')
return img_new
def Pixel_num(self):
num = [0 for _ in range(256)]
a = np.shape(self.img)
for i in range(a[0]):
for j in range(a[1]):
num[self.img[i][j]] += 1
return num
def Pixel_rate(self):
rate_list = []
n = sum(self.num_list)
for i in range(len(self.num_list)):
rate = self.num_list[i] / n
rate_list.append(rate)
return rate_list
def Optimal_partition(self):
deltaMax = 0
T = 0
for i in range(256):
w1 = w2 = u1 = u2 = 0
u1tmp = u2tmp = 0
deltaTmp = 0
for j in range(256):
if (j <= i):
w1 += self.rate_list[j]
u1tmp += j * self.rate_list[j] #前景的平均灰度值
else:
w2 += self.rate_list[j]
u2tmp += j * self.rate_list[j]
if w1 == 0:
u1 = 0
else:
u1 = u1tmp / w1
if w2 == 0:
u2 = 0
else:
u2 = u2tmp / w2
deltaTmp = w1 * w2 * ((u1- u2) ** 2)
if deltaTmp > deltaMax:
deltaMax = deltaTmp
T = i
return T
def Optimal_partitionEx(self):
#遍历256直方图
#算出w1 w2 u1 u2
#w1: 前景占比
#u1: 前景的平均灰度值
lstG= []
for i in range(256):
N1arr= np.array(self.num_list[0:i+1])
totalSize= self.img.size;
w1= np.sum(N1arr) / totalSize
N1sum= np.sum(N1arr) #按当前的i 来分割时候 ,如果前景类中一个像素也没有 ,自然平均值也是0
u1= np.sum(np.array(range(i+1))* N1arr )/N1sum if N1sum>0 else 0
#############
N2arr= np.array(self.num_list[i+1:])
w2= 1- w1 #背景肯定与前景 比例互补 or np.sum(N2arr) / totalSize
N2sum= np.sum(N2arr)
u2= np.sum(np.array(range(i+1,256,1))* N2arr) / N2sum if N2sum>0 else 0
lstG.append( w1*w2*(u1-u2)**2)
return np.array(lstG).argmax()
def Otsu(self):
a = np.shape(self.img)
new_img = np.zeros((a[0], a[1]))
for i in range(a[0]):
for j in range(a[1]):
if self.img[i][j] > self.optimal_pixel:
new_img[i][j] = 255
else:
new_img[i][j] = 0
return new_img
if __name__ == "__main__":
path = r'C:\images\lena.jpg'
a = OTSU(path)
new_img = a.Otsu()
plt.imshow(new_img, 'gray')
plt.axis('off')