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

news/2024/7/21 3:57:19 标签: 图像处理, 算法, 人工智能

这里写自定义目录标题

  • 数学原理
  • 算法评价
  • 参考链接

数学原理

以灰度图像为例,对于图像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)

算法评价

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

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

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

原文链接:

参考链接

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


http://www.niftyadmin.cn/n/5187507.html

相关文章

切换阿里云ES方式及故障应急处理方案

一、阿里云es服务相关问题及答解 1.1 ES7.10扩容节点时间 增加节点数量需要节点拉起和数据Rebalance两步,拉起时间7.16及以上的新版本大概10分钟以内,7.16以前大概一小时,数据迁移的时间就看数据量了,一般整体在半小时以内 (需进行相关测试验证) 1.2 ES7.10扩容数据节点…

leetcode刷题日志-13整数转罗马数字

罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即为两个并列的 1。12 写做 XII &#xff0c;即为…

大语言模型量化方法对比:GPTQ、GGUF、AWQ

在过去的一年里&#xff0c;大型语言模型(llm)有了飞速的发展&#xff0c;在本文中&#xff0c;我们将探讨几种(量化)的方式&#xff0c;除此以外&#xff0c;还会介绍分片及不同的保存和压缩策略。 说明&#xff1a;每次加载LLM示例后&#xff0c;建议清除缓存&#xff0c;以…

基于ssm+vue员工工资管理系统

基于ssmvue员工工资管理系统 摘要 随着信息技术的不断发展&#xff0c;各行各业对于高效管理和利用数据的需求也日益增长。员工工资管理系统作为企业管理中的一个重要组成部分&#xff0c;对于实现工资信息的精确计算、及时发放和有效管理具有重要意义。本文基于SSM&#xff08…

Go语言常用库

Go语言常用库 文本主要介绍Go常用的一些系统库&#xff1a; sort、math、copy、strconv、crypto 1、sort package mainimport ("fmt""sort" )// sort // int排序 // sort.Ints([]int{}) // 字符串排序 // sort.Strings([]string{}) // 自定义排序 // s…

udp多点通信-广播-组播

单播 每次只有两个实体相互通信&#xff0c;发送端和接收端都是唯一确定的。 广播 主机之间的一对多的通信所有的主机都可以接收到广播消息(不管你是否需要)广播禁止穿过路由器&#xff08;只能做局域网通信&#xff09;只有UDP可以广播广播地址 有效网络号全是1的主机号 192.1…

vb.net 实时监控双门双向门禁控制板源代码

本示例使用设备介绍&#xff1a;实时网络双门双向门禁控制板可二次编程控制网络继电器远程开关-淘宝网 (taobao.com) Imports System.Net.Sockets Imports System.Net Imports System.Text Imports System.ThreadingImports System.Net.NetworkInformation Imports System.Man…

限制Domain Admin登录非域控服务器和用户计算机

限制Domain Admin管理员使用敏感管理员帐户(域或林中管理员组、域管理员组和企业管理员组中的成员帐户)登录到信任度较低的服务器和用户端计算机。 此限制可防止管理员通过登录到信任度较低的计算机来无意中增加凭据被盗的风险。 建议采用的策略 建议使用以下策略限制对信任度…