• 【图像处理】:Otsu算法最大类间方差法(大津算法:附源码)


    这里写自定义目录标题

    数学原理

    以灰度图像为例,对于图像M×N大小的矩阵,即图像中的像素,每一个值即为像素值,其中灰度图像像素值在(0~255)之间。
    主要实现前景(即目标)和背景的分割:
    主要公式:
    前景的像素点数占整幅图像的比例记为ω0,前景平均灰度记为μ0
    ​背景像素点数占整幅图像的比例记为ω1,其平均灰度记为μ1
    ​图像的总平均灰度记为μ,类间方差记为maximum。
    假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值optimal threshold的像素个数记作N0
    ,像素灰度大于等于阈值optimalthreshold 的像素个数记作N1,
    则有:
                ω0 = N0 / ( M × N )             (1)   
                ω1 = N1 / ( M × N )             (2)       
            N0 + N1 = M × N             (3)   
                1 = ω 0 + ω 1             (4)      
                μ = ω0 × μ0 + ω1 × μ1         (5)   
           maximum = ω0 × ( μ0 − μ ) 2 + ω1 × ( μ1 − μ ) 2 (6)  
    将式(5)代入式(6),得到等价公式(7):
          maximum = ω0 × ω1 × (μ0 − μ1 ) 2 (7)    
    采用遍历的方法得到使类间方差maximum最大的阈值optimal threshold
    实现过程:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    # author:longc
    # datetime:2023/11/16 10:30
    # software: PyCharm
    # function: 图像处理逻辑
    
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    from PIL import Image
    
    
    # otsu算法
    def otsu(gray):
        pixel_number = gray.shape[0] * gray.shape[1]
        mean_weigth = 1.0 / pixel_number
        # #统计各灰度级的像素个数,灰度级分为256级
        # bins必须写到257,否则255这个值只能分到[254,255)区间
        his, bins = np.histogram(gray, np.arange(0, 257))  # 计算灰度的直方图,计数统计区间为0-257
        print("bins", bins)
        print("his", his)
        # 绘制直方图
        plt.figure(figsize=(12, 8))
        # plt.hist(gray, 256, [0, 256], label='灰度级直方图')  # 运行比较慢,如果电脑卡顿,可以将本行代码注释掉
        plt.show()
    
        final_thresh = -1
        final_value = -1
        intensity_arr = np.arange(256)  # 灰度分为256级,0级到255级
    
        # ************************************************************ 采用遍历的方法得到类间方差最大的阈值
        
        for t in bins[1:-1]:  # 遍历1到254级 (一定不能有超出范围的值)
            pcb = np.sum(his[:t])  # 小于当前灰度对应的所有像素点计数
            pcf = np.sum(his[t:])  # 大于当前灰度对应的所有像素点计数
            Wb = pcb * mean_weigth  # 像素被分类为背景的概率
            Wf = pcf * mean_weigth  # 像素被分类为目标的概率
            # if t == 100:
            #     print("1>>>", intensity_arr[:t])
            #     print("2>>>", his[:t])
            #     print("3>>>", np.sum(intensity_arr[:t] * his[:t]))
            #     print("4>>>", float(pcb))
            #     print("5>>>", np.sum(intensity_arr[:t] * his[:t]) / float(pcb))
    
            mub = np.sum(intensity_arr[:t] * his[:t]) / float(pcb)  # 分类为背景的像素均值
            muf = np.sum(intensity_arr[t:] * his[t:]) / float(pcf)  # 分类为目标的像素均值
    
            # print mub, muf
            value = Wb * Wf * (mub - muf) ** 2  # 计算目标和背景类间方差
            # 采用遍历的方法得到使类间方差value最大的阈值final_value和二值化对应最大的final_thresh
            
            if value > final_value:
                final_thresh = t  # 进行二值化的操作值
                final_value = value
        print("final_thresh>>>", final_thresh)
        print("final_value>>>", final_value)
        
        # 二值化操作处理
        # final_img = gray.copy()
        # print(final_thresh)
        # final_img[gray > final_thresh] = 255
        # final_img[gray < final_thresh] = 0
        # cv2.imwrite("final_img.jpg", final_img)
        plt.imshow(gray)
        plt.show()
    
        # 二值化图像(多种方法对比)
        ret, binary_image = cv2.threshold(gray, final_thresh-15, 255, cv2.THRESH_BINARY)
        plt.imshow(binary_image, cmap='gray')
        plt.show()
    
        # ret, binary_image1 = cv2.threshold(gray, final_thresh, 255, cv2.THRESH_TRUNC)
        # plt.imshow(binary_image1)
        # plt.show()
        #
        # ret, binary_image2 = cv2.threshold(gray, final_thresh, 255, cv2.THRESH_TOZERO)
        # plt.imshow(binary_image2)
        # plt.show()
        #
        # ret, binary_image3 = cv2.threshold(gray, final_thresh, 255, cv2.THRESH_TOZERO_INV)
        # plt.imshow(binary_image3)
        # plt.show()
    
    
    imggray = cv2.imread("IMG_0004_3.jpg", 0)
    plt.title("imggray")
    plt.imshow(imggray, cmap='gray')
    plt.show()
    
    # 进行OSTU运算
    otsu(imggray)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    算法评价

    优点:算法简单,当目标与背景的面积相差不大时,能够有效地对图像进行分割。

    缺点:类间方差法对噪声以及目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。当目标与背景的大小比例悬殊时(例如受光照不均、反光或背景复杂等因素影响),类间方差准则函数可能呈现双峰或多峰,或者目标与背景的灰度有较大的重叠时,效果不不是很理想。

    原因:该方法忽略了图像的空间信息,同时将图像的灰度分布作为分割图像的依据,对噪声也相当敏感

    原文链接:

    参考链接

    数字图像处理——最大类间方差法(OTSU)图像阈值分割实例

  • 相关阅读:
    Spark RDD简记
    【图像融合】基于多尺度奇异值分解的图像融合附matlab代码
    Redis高可用之战:主从架构
    Vue3 ~
    Linux系统上非管理员如何启动EasyDSS视频直播点播程序?
    git的详细使用
    js:深拷贝与浅拷贝的区别,如何实现深拷贝
    [附源码]计算机毕业设计springboot基于人脸识别的社区防疫管理系统
    HTML5期末大作业:基于HTML+CSS+JavaScript仿蘑菇街购物商城设计毕业论文源码
    c++ std::mutex 多个线程同时访问的同步原语
  • 原文地址:https://blog.csdn.net/weixin_44322778/article/details/134439381