【图像分割】使用Otsu 算法及迭代计算最佳全局阈值估计并实现图像分割(代码实现与分析)

news2024/11/24 2:07:15

        本实验要求理解全局阈值分割的概念,并实现文本图像分割。需要大家深入理解Ostu 算法的实现过程及其迭代原理,同时通过学习使用Otsu 算法及其迭代,实践图像分割技术在文本图像处理中的应用。

        以下将从实验原理、实验实现、实验结果分析三部分对整个实验进行阐述

实验原理

全局阈值分割原理

        全局阈值分割是一种基于灰度图像的简单分割方法。其基本思想是根据一个固定的阈值T,将图像中的每个像素点的灰度值与阈值T进行比较。如果像素点的灰度值大于或等于T,则将其归为前景(通常表示感兴趣的物体或区域);否则,将其归为背景。

Otsu算法原理

        Otsu算法是一种自动选择全局阈值的方法,它通过最大化类间方差(inter-class variance)来确定最优的阈值。类间方差反映了前景和背景两类像素之间的差异程度,差异越大,说明分割效果越好。

以下是Otsu算法的具体步骤:

        a. 计算图像的灰度直方图:直方图表示了图像中各个灰度级像素出现的频率。

        b. 计算各类别的概率:对于每一个可能的阈值T,可以将图像分为两个类别,一类是灰度值小于T的像素,另一类是灰度值大于或等于T的像素。计算这两个类别的像素数(或者像素的概率)。

        c. 计算类间方差:类间方差定义为两类像素的平均灰度值之差的平方乘以两类像素的概率之和。类间方差越大,说明两类像素的差异越大,分割效果越好。

        d. 寻找最优阈值:遍历所有可能的阈值,对于每个阈值,计算其对应的类间方差。选择使类间方差最大的那个阈值作为最佳全局阈值。

图像分割实现

        利用计算出的最佳全局阈值,对原始图像进行二值化处理,即根据阈值将每个像素点的灰度值转换为0(背景)或1(前景),从而实现图像的分割。

实验实现

输入图像

在本次实验中,小组选取了三幅灰度图片作为实验的输入图像,如下图所示。

实验代码 

        利用Python实现Otsu算法及其迭代方法。对于输入的图像,首先生成它的一个渐变灰度图像,接着计算图像的直方图,并基于直方图使用Otsu方法和迭代方法分别寻找最佳的阈值。

import cv2
import numpy as np
import os

def get_file_paths(folder_path):
    # 获取文件夹内所有文件的路径
    file_paths = [os.path.join(folder_path, file) for file in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, file))]
    return file_paths

def generate_gradient_image(width, height):
    # 生成渐变灰度图像数据
    gradient_image = np.zeros((height, width), dtype=np.uint8)

    # 计算每一列的亮度值
    for col in range(width):
        brightness = int(255 * col / width)
        gradient_image[:, col] = brightness

    return gradient_image

def save_image(image, file_path):
    # 保存图像
    cv2.imwrite(file_path, image)

def iterative_thresholding(image, epsilon=1e-6, max_iter=100):
    # 初始阈值
    threshold = 128.0

    for _ in range(max_iter):
        # 根据当前阈值将图像二值化
        binary_image = image > threshold

        # 计算前景和背景的平均灰度
        mean_foreground = np.mean(image[binary_image])
        mean_background = np.mean(image[~binary_image])

        # 计算新的阈值
        new_threshold = 0.5 * (mean_foreground + mean_background)

        # 如果新旧阈值之间的差异小于 epsilon,停止迭代
        if abs(new_threshold - threshold) < epsilon:
            break

        threshold = new_threshold

    return threshold

def otsu_thresholding(image): # 计算otsu全局最优阈值
    # 计算直方图
    hist, bins = np.histogram(image.flatten(), 256, [0, 256])
    # 归一化直方图
    hist = hist.astype(float) / sum(hist)
    # 初始化类内方差和类间方差
    var_within = np.zeros(256)
    var_between = np.zeros(256)
    for t in range(1, 256):
        # 类内方差
        w0 = sum(hist[:t])
        w1 = sum(hist[t:])
        mu0 = sum(i * hist[i] for i in range(t)) / w0 if w0 > 0 else 0
        mu1 = sum(i * hist[i] for i in range(t, 256)) / w1 if w1 > 0 else 0
        var_within[t] = w0 * w1 * (mu0 - mu1) ** 2

        # 类间方差
        var_between[t] = w0 * w1 * (mu0 - mu1) ** 2
    # 找到最佳阈值
    optimal_threshold = np.argmax(var_between)
    return optimal_threshold

def threshold(image_path): # 生成阈值化图像
    # 读取图像
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    image_path=image_path[5:]
    # 应用Otsu方法获取最佳阈值
    otsu_threshold = otsu_thresholding(img)
    # print(f"threshold:{threshold}")
    # 使用阈值进行二值化
    print(f'otsu_threshold:{otsu_threshold}')
    _, binary_image = cv2.threshold(img, otsu_threshold, 255, cv2.THRESH_BINARY)
    # 保存阈值化图像
    save_image(binary_image, f'Otsu_{image_path}')

    iterative_threshold = iterative_thresholding(img)
    # print(f"threshold:{threshold}")
    # 使用阈值进行二值化
    print(f'iterative_threshold:{iterative_threshold}')
    _, binary_image = cv2.threshold(img, iterative_threshold, 255, cv2.THRESH_BINARY)
    # 保存阈值化图像
    save_image(binary_image, f'iterative_{image_path}')
    print(f'{image_path[:-4]}测试已完成')


if __name__ == '__main__':
    # # 设置图像的宽度和高度
    # width = 640
    # height = 480
    # # 生成渐变图像
    # image = generate_gradient_image(width, height)
    # # 保存图像
    # save_image(image, 'exam0.jpg')

    folder_path = 'exam'
    # 获取文件夹内所有文件的路径
    exam_paths = get_file_paths(folder_path)
    # 依次测试图像
    for image_path in exam_paths:
        print(f'image_name:{image_path[5:]}')
        threshold(image_path)

实验结果分析 

对于三幅图像使用Otsu方法和迭代方法进行全局阈值分割的实验结果和分析如下:

(1)图像一处理结果

        由上图第一组实验结果可以看出,对于灰度分布规律简单的图像,全局分割的阈值寻找较为简单,利用Otsu算法和迭代算法的效果几乎没有区别。 

(2)图像二处理结果

        如上图所示,第二组实验中,Otsu算法和迭代方法在作用于灰度值分界较为明显的图像上时均取得了很好的分割效果。 

(3)图像三处理结果

        由上图所示第三组实验可以看出,即使是边界并不是非常清晰的图片,Otsu方法和迭代方法也都能取得很好的分割效果。


以上为本次实验的全部内容~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1523485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-队列java实现

队列 队列(queue)1.队列的特点2.数组模拟队列JAVA代码3.上述过程优化 博文主要是自己学习的笔记&#xff0c;供自己以后复习使用&#xff0c; 参考的主要教程是B站的 尚硅谷数据结构和算法 队列(queue) 1.队列的特点 1&#xff09;队列是一个有序列表&#xff0c;可以用数组…

cannot find -xml2: No such file or directory的解决方法

一&#xff0c;问题现象 在编译库的时候出现如下图所示的报错&#xff1a;C:/msys64/mingw32/bin/…/lib/gcc/i686-w64-mingw32/13.2.0/…/…/…/…/i686-w64-mingw32/bin/ld.exe: ca nnot find -lxml2: No such file or directory collect2.exe: error: ld returned 1 exit s…

Linux环境下用IDEA运行Golang记录

一、背景 和存储同时开发AI项目&#xff0c;在Linux环境运行Golang项目&#xff0c;因此需要进行相关的配置。 二、Golang安装 参考&#xff1a;【Linux — 安装 Go】Linux 系统安装 Go 过程总结_linux 安装go-CSDN博客 三、IDEA中Golang配置 1、去除代理 否则在Plugins中…

奇舞周刊第522期:“Vite 又开始搞事情了!!!”

奇舞推荐 ■ ■ ■ Vite 又开始搞事情了&#xff01;&#xff01;&#xff01; Vite 的最新版本将引入一种名为 Rolldown 的新型打包工具。 unocss 究竟比 tailwindcss 快多少&#xff1f; 我们知道 unocss 很快&#xff0c;也许是目前最快的原子化 CSS 引擎 (没有之一)。 巧用…

每日五道java面试题之mybatis篇(一)

目录&#xff1a; 第一题. MyBatis是什么&#xff1f;第二题. ORM是什么?第三题. 为什么说Mybatis是半自动ORM映射工具&#xff1f;它与全自动的区别在哪里&#xff1f;第四题. 传统JDBC开发存在的问题第五题. JDBC编程有哪些不足之处&#xff0c;MyBatis是如何解决这些问题的…

差分逻辑电平 — LVDS、CML、LVPECL、HCSL互连

前言 首先了解差分逻辑电平、单端逻辑电平的基础知识 地址&#xff1a;常见的逻辑电平_常用的逻辑电平-CSDN博客 注&#xff1a; ECL >> PECL >> LVPECL演变&#xff1b; ECL速度快&#xff0c;驱动能力强&#xff0c;噪声小&#xff0c;但是功耗大&#xff0c;使…

SpringBoot(数据库操作 + druid监控功能)

文章目录 1.JDBC HikariDataSource&#xff08;SpringBoot2默认数据源&#xff09;1.数据库表设计2.引入依赖 pom.xml3.配置数据源参数 application.yml4.编写一个bean&#xff0c;映射表5.编写测试类来完成测试1.引入依赖 pom.xml2.使用JdbcTemplate进行测试3.成功&#xff0…

并发编程CountDownLatch浅析

目录 一、CountDownLatch简介二、源码三、使用3.1 demo13.2 demo2 四、应用场景五、参考链接 一、CountDownLatch简介 CountDownLatch(倒计时锁存器)是Java并发包中的一个工具类&#xff0c;用于实现多个线程之间的同步。它通过一个计数器来实现线程之间的等待和唤醒操作&…

51单片机系列-单片机定时器

&#x1f308;个人主页&#xff1a;会编辑的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 软件延时的缺点 延时过程中&#xff0c;CPU时间被占用&#xff0c;无法进行其他任务&#xff0c;导致系统效率降低&#xff0c;延时时间越长&#xff0c;该缺点就越明显&…

esp8266调试记录

连接笔记本电脑 使用笔记本电脑的USB接口为NodeMCU开发板供电&#xff0c;你需要确保电压和电流在安全范围内。虽然NodeMCU的输入输出电压限制为3.3V&#xff0c;但是大多数开发板都内置了电压调节器&#xff0c;可以从5V的USB电源降压到3.3V。因此&#xff0c;通常情况下&…

通用的springboot web jar包执行脚本,释放端口并执行jar包

1、通用的springboot web jar包执行脚本&#xff0c;释放端口并执行jar包&#xff1a; #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/data/yitu-projects/yitu-xzhq/sftp # 服务名称。同时约定部署服务的 jar 包名字也为它。 SERVER_NAMEyitu-server # 环境…

【图论】拓补排序 - 邻接表

文章目录 题目&#xff1a;310. 最小高度树题目描述代码与注释 题目&#xff1a;310. 最小高度树 题目描述 代码与注释 func findMinHeightTrees(n int, edges [][]int) (ans []int) {if n 1 {return []int{0}}g : make([][]int, n)degree : make([]int, n) // 记录每个节点…

Android Studio字体大小调节

外观页面字体调节 settings->Appearance->User cunstom font 代码字体调节 Settings->Editor->Font此时logcat窗口、Build窗口和Ternimal窗口字体大小也会同步调节&#xff08;2023.2.1版本上验证&#xff09;

FFmpeg查看所有支持的编码/解码器/封装/解封装/媒体格式/滤镜

查看所有支持的编码器与解码器 ffmpeg -codecs 只查看所有编码器: ffmpeg -encoders 只查看所有解码器: ffmpeg -decoders 只查看H264编码器: ffmpeg -h encoderh264 只查看H264解码器: ffmpeg -h decoderh264 查看所有支持的封装: ffmpeg -muxers 查看所有支持的解封装…

【算法】数论(求质数)——蓝桥杯笔记、2.质数、7.质数、质数数目、纯质数、函数判断顺序的优化

文章目录 蓝桥杯2.质数7.质数质数数目纯质数 蓝桥杯 2.质数 求质数的几种方法&#xff1a; #include<iostream> #include<algorithm> using namespace std;bool is_primer1(int n) {if (n < 2) return n;//for (int i 2; i < n; i)for (int i 2; i < …

简历信息泄露?如何用图数据库技术解决简历泄露事件的反欺诈挑战

“金三银四”&#xff0c;又到了春招黄金期&#xff0c;但个人简历泄露的数据安全问题诸见报端&#xff0c;甚至在此前的3.15晚会报道中就揭露过招聘平台上的简历信息被泄露&#xff0c;不法分子通过各种渠道获取到简历&#xff0c;并用于欺诈活动&#xff0c;形成了一套庞大的…

ZK vs FHE

1. 引言 近期ZAMA获得7300万美金的投资&#xff0c;使得FHE获得更多关注。FHE仍处于萌芽阶段&#xff0c;是未来隐私游戏规则的改变者。FHE需与ZK和MPC一起结合&#xff0c;以发挥最大效用。如&#xff1a; Threshold FHE&#xff1a;将FHE与MPC结合&#xff0c;实现信任最小…

【Sql Server】通过Sql语句批量处理数据,使用变量且遍历数据进行逻辑处理

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

c语言案例03-流程控制-if语句

c语言打卡-流程控制-if语句 一.在 C/C&#xff0c;if 函数或关键字具有判断功能&#xff0c;而判断这一操作必须基于给定条件&#xff0c;同样的&#xff0c;程序中使用 if 函数同样需要将判断条件作为参数传入&#xff0c;描述判断条件的代码语句简称为条件语句。如同现实生活…

【Python编程基础】第一节.Python基本语法(上)

文章目录 前言⼀、Python介绍二、Python环境配置三、Pycharm 书写代码四、Python基本语法 4.1 print 函数的简单使用 4.2 注释 4.3 Python 代码中三种波浪线和 PEP8 4.4 在 cmd 终端中运⾏ Python 代码 4.5 变量 4.6 数据类型 4.7 类型转换…