OTSU算法及其Python实现

2023-12-07 11:20
文章标签 python 算法 实现 otsu

本文主要是介绍OTSU算法及其Python实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 原理
    • 实现和验证
    • 分析和优化

原理

OTSU算法是大津展之提出的阈值分割方法,又叫最大类间方差法。OTSU并不是一个英文缩写,而是日语假名,是其提出者的姓氏“大津”。

假设存在阈值 T T T可以将图像分为两部分,记二者均值为 m 1 , m 2 m_1, m_2 m1,m2,图像总均值为 m m m,像素被分入这两部分的比例分别为 p 1 , p 2 p_1, p_2 p1,p2。从而

p 1 + p 2 = 1 p 1 m 1 + p 2 m 2 = m \begin{aligned} p_1+p_2&=1\\ p_1m_1+p_2m_2&=m\\ \end{aligned} p1+p2p1m1+p2m2=1=m

则类间方差可表示为

σ 2 = p 1 ( m 1 − m ) 2 + p 2 ( m 2 − m ) 2 = p 1 m 1 2 + p 2 m 2 2 − m 2 \begin{aligned} \sigma^2&=p_1(m_1-m)^2+p_2(m_2-m)^2\\ &=p_1m_1^2+p_2m_2^2-m^2 \end{aligned} σ2=p1(m1m)2+p2(m2m)2=p1m12+p2m22m2

实现和验证

由于OTSU算法的逻辑和公式都非常清晰,所以实现起来也及其方便

import numpy as np
import matplotlib.pyplot as plt# 计算类间方差
def getVar(img, th):slct = img>thp1 = np.sum(slct)/img.sizeif p1 in [0, 1]:return 0p2 = 1-p1m1 = np.mean(img[slct])m2 = np.mean(img[~slct])m = p1*m1+p2*m2return p1*m1**2+p2*m2**2-m**2def otsu(img):vs = [getVar(img, th) for th in range(256)]return np.argmax(vs)

其中,getVar用于计算类间方差,后面的otsu则返回分割阈值。下面创建函数用于测试otsu算法

def drawOne(fig, index, img):fig.add_subplot(index)plt.imshow(img, cmap="gray")plt.axis('off')def test():img = plt.imread(r"D:\Code\NotePL\python\lena.jpg").astype(float)img = np.mean(img, axis=2)th = otsu(img)print(th)fig = plt.figure(figsize=(8,3))drawOne(fig, 131, img)drawOne(fig, 132, img>th)drawOne(fig, 133, img<=th)plt.tight_layout()plt.show()

效果如下

在这里插入图片描述

分析和优化

由于图像的像素值是八位整型,所以迭代256次就可以得到所有的类间方差。

img = plt.imread(r"D:\Code\NotePL\python\lena.jpg").astype(float)
img = np.mean(img, axis=2)
vs = [getVar(img, th) for th in range(256)]
print(np.argmax(vs))    # 121
plt.plot(vs)
plt.show()

类间方差分布如下,当阈值是121时,得到最大类间方差。

在这里插入图片描述

对于精度更高的16位图像,或者其他非图像的数值,遍历的方案效率太低了,为此可进行做一个步长二分的爬山算法,代码如下,最终得到的结果位121.7,由于在阈值分割时采用的是大于号,所以效果与121相同。

def climb(img, step, st=0, err=0.1):vSt = getVar(img, st)while abs(step)>err:ed = st+stepvEd = getVar(img, ed)if vEd < vSt:step = -step/2st, vSt = ed, vEdreturn edclimb(img, 40)
# 121.71875

这篇关于OTSU算法及其Python实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/465667

相关文章

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.