大津法 二值化

  • 参考了 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')
posted @ 2021-03-23 14:53  boyang987  阅读(98)  评论(0编辑  收藏  举报