otsu算法_Otsu 灰度图像阈值算法及实现

2023-10-28

人工智能导论课的第一次作业。文末提供 HTML 文件源码,可直接体验。

一、简介

我们要做的,其实就是将一张(彩色)图片,转成黑白图片(二值图)。

二值图:只有黑色或白色, 000fff0255

看看效果图就基本了解了,左原图,右图经过算法处理:

(原图为网络收集图 侵权删)

在彩色图和黑白图片之中,还有一个灰度图。

这个灰度图是我们这次的主角。

二、概念

1. 像素与色彩

每张图片是由多个像素点构成的,比如长 200, 宽 200 ,那么它就有 40000 个像素点。

每个像素点都有自己的颜色,每个颜色又都有不同的值,那么要怎么将缤纷五彩变为“非黑即白”?

RGB 来表示每种颜色,即三原色(红绿蓝)各自的比例,比如白色的 RGB(255,255,255),如果用十六进制来表达就是 #ffffff(可简写为 #fff ),黑色的 RGB(0,0,0)#000

RGBA ,在原来的基础上,加上了 alpha ,用来设置透明度的。一般一个像素点含有四个数值。
所有数值范围: 0 ~ 255,共 256 个。

更改图片颜色,就是分别更改它们每个像素点的 RGB 的具体数字!

推荐一篇文章:彩色图像怎样转灰度图像 ,它的第四部分“二值图像” ,其实就是这个题目的含义。

2. Otsu

一个算法名称。

它是计算一个阈值(临界值)的算法。

3. 灰度 grayscale

用不同饱和度的黑色来显示图像。最高的灰度就是黑,最低的灰度就是白。

每个像素点的灰度值要怎么计算?

通常是采用平均数法,也就是 Gray = (R+G+B)/3

再用计算出来的 Gray 替换掉对应像素点的 RGB 三个数,就会得到灰度图了。

4. 阈值 threshold

临界值。

我们现在已经有了每个像素点的灰度值,但二值图,黑白是两个极端。

所以我们需要一个临界值来分隔它们,灰度值大于这个临界值的,RGB 三个值均设为 255 (或 0),小于这个临界值的,RGB 三个值均设为 0 (或255)。

这个临界值,也就是题目中的阈值,该设置为什么,就是 Otsu 算法要解决的问题。

5. 关键词总结

RGB :色彩标准,红绿蓝

Otsu :算法名称,计算阈值的算法。

grayscale:灰度值。

histogram :直方图,用于统计图像中灰度数据,便于计算灰度的频率分布、平均值等。

prob :频率分布,每部分的 histogram / 总数

threshold :门槛,界,也就是标题中的“阈值

三、题目

图像有 L 阶灰度, ni 是灰度为 i 的像素数,图像总像素数有 N = n1 + n2 + ··· + nL

灰度为 i 的像素概率:pi = ni / N

类间方差:ICV = PA * (MA - M) * (MA - M) + PB * (MB - M) * (MB - M)

强烈推荐阅读此篇文章:灰度图像的自动阈值分割(Otsu 法),一篇就能理解题目含义。

四、步骤解析

部分将结合已实现效果的代码进行解释。

且基本上一个小节的返回值就是下一小节的参数。

1. 获得图像数据

即每个像素点的数据值。

因为我是采用 JavaScriptCanvas 来实现的,所以为 ImageData 对象,它的 data 属性为一个数组,数组的数据就是此图像的所有像素点的值,且每 4 个值为一个像素点(RGBA)。

let imageData = getImageData(oRawImg)
// 获得图像数据
function getImageData(raw) {
    ...
    return ctx.getImageData(0, 0, width, height)
}

2. 获得灰度值

通过对 图像数据 每四个值的一次处理,最终获得原 图像数据1/4 长度数组。

grayscale : 灰度值
let grayscale = getGrayscale(imageData)
// 获得灰度值
function getGrayscale(imageData) {
    let grayscale = [],
    data = imageData.data
    for (let i = 0; i < data.length; i += 4) {
         ...
         gray = Math.round((r + g + b) / 3)
        grayscale.push(gray)
    }
    return grayscale
}

3. 获得灰度直方图

一张长宽都只有 200 的图像,就有 40000 个像素点,灰度值数组长度就为 40000

而灰度值只有 256 种,所以我们来统计每个灰度值有多少个像素点,便于后续计算(逐渐走向数学知识)。

histogram:直方图
let histogram = getHistogram(grayscale)
// 获取直方图
function getHistogram(grayscale) {
    ...
    for (let i = 0; i < grayscale.length; i++) {
        histogram[grayscale[i]]++
    }
    return histogram
}

4. 获得概率密度

概率密度,就是对应位置的灰度个数除以所有的灰度个数。

即为此灰度值的概率为多少。

probProbability Density,概率密度
let prob = getProb(histogram, grayscale.length)
// 获得概率密度
function getProb(histogram, n) {
    ...
        prob[i] = histogram[i] / n
    }
    return prob
}

5. 获得阈值

通过 Otsu 算法来获得。套个外套,易理解。

let threshold = getThreshold(prob)
// 套个外套,易理解
function getThreshold(prob) {
    return otsu(prob)
}

6. Otsu 算法

关键在于 ICV = PA * (MA - M) * (MA - M) + PB * (MB - M) * (MB - M) 这个公式,以下逐个解释其意义。

累积分布

cum, 为Cumulative Distribution Function 的代替,通过不断累加概率密度得到,是为了获得 PAPB

PA + PB = 1,这两个数值的意义是,阈值左右两边的比例,A 部分, B 部分。

A 部分里的像素数占总像素数的比例记作 PA,B 部分里的像素数占总像素数的比例记作 PB。
cum = new Array(256)
cum[0] = prob[0]
cum[i] = cum[i - 1] + prob[i]

PA = cum[i]
PB = 1 - PA

灰度总平均值

M ,为 mean 的缩写,平均值,可在获得 累积分布 的同时计算灰度总平均值,mean 数组的最后一个值就是总灰度平均值。

M = (a + b + c) / 3 = a / 3 + b / 3 + c / 3
M = 0
mean = new Array(256)
mean[0] = 0
mean[i] = mean[i - 1] + i * prob[i]
M = mean[255]

类间方差

ICV ,为 inter-class variance 的缩写,类间方差。

MAMB 为:A 部分的灰度平均值, B 部分的灰度平均值。

A, B 两部分各自的平均值为 MA 和 MB。
MA = mean[i] / PA
MB = (M - mean[i]) / PB
ICV = PA * (MA - M) * (MA - M) + PB * (MB - M) * (MB - M)

最后使 ICV 值最大的那个灰度值,就是阈值。

7. 输出图像

将原始图像数据、灰度值、阈值、和目标位置作为参数。

function putImageData(imageData, grayscale, threshold, ctx) {
        ...
        let gray = grayscale[i / 4] > threshold ? 255 : 0
        data[i] = data[i + 1] = data[i + 2] = gray
    }
    ctx.putImageData(imageData, 0, 0)
}

五、代码相关

本是写了非常详细的注释,但因个人失误导致注释丢失。

幸运的是,代码是按照逻辑顺序进行调用、排序的,按照顺序读下去即可;函数名与参数即是其功能。若不太理解单词请翻阅上文内容。

代码地址:https://github.com/evgo2017/algorithm (Otsu 灰度图像的阈值算法文件夹)

六、参考资料

  1. 灰度图像的自动阈值分割(Otsu 法)
  2. 彩色图像怎样转灰度图像
  3. 百度百科-灰度值
  4. Otsu-s-Thresholding
  5. MultiOtsuThresholdJS
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

otsu算法_Otsu 灰度图像阈值算法及实现 的相关文章

随机推荐

  • python文件读写用到的库_python 读写txt文件并用jieba库进行中文分词

    python用来批量处理一些数据的第一步吧 对于我这样的的萌新 这是第一步 encoding utf 8 file test txt fn open file r printfn read fn close 在控制台输出txt文档的内容 注
  • python学习004-----python中%s的各种用法

    在python输出语句中 我们常用到 s 符号 s作用是将对象传到str 方法中进行处理 输出字符串 例如 str 12345 print 下面输出一串数字 s str 运行结果如下 这是 s最基本的用法 s还有很多不太常用的变形如下 1
  • Mybatis plus:Caused by: Error creating bean with name 'sqlSessionFactory' defined in class path reso

    整合springboot mybatisplus时报错 java lang IllegalStateException Failed to load ApplicationContext at org springframework tes
  • Mysql 存在既更新,不存在就添加(sql语句)

    版权声明 本文为勇哥原创文章 转载请注明出处哦 https blog csdn net woshihaiyong168 article details 75082668 INSERT 语句的一部分 如果指定 ON DUPLICATE KEY
  • 官方下载 sqlite 数据库,JDK Java开发工具包,Eclipse 跨平台开源集成开发环境 流程。

    官方下载 sqlite 数据库 JDK Java开发工具包 Eclipse 跨平台开源集成开发环境 流程 这两天下载IT编程的开发工具 开发包等 由于英文不好 在官方网址折腾了一些时间 现 在写出流程来 让后来人不再浪费宝贵的时间下载 1
  • [NOI 2014复习]斜率优化(BZOJ 1096、BZOJ 1010)

    1 BZOJ 1096 仓库建设 题目链接 http www lydsy com JudgeOnline problem php id 1096 思路 令 f i 1 i f i 1 i 区间 在第i个工厂建立仓库 所需最少总花费 DP方程
  • 【C语言】小游戏系列——扫雷(内含详细过程)

    我相信扫雷大家并不陌生 小时候经常玩 深受大家的喜欢 今天我们用c语言来编写一个简单的扫雷小游戏 在C语言的学习中 就应该用一些有趣的代码来激励我们 增加我们对编程的热爱 下面我来讲述如何去实现一个扫雷小游戏 正片开始 目录 1 游戏规则
  • 机器学习中的名词解释(一):监督学习、无监督学习、半监督学习、自监督学习(通俗理解)

    机器学习中有几个带有 监督 二字的名词 易混淆 写篇博客解释一下下 1 监督学习 Supervised Learning 是指从标注数据中学习预测模型的机器学习方法 其本质是学习输入到输出的映射的统计规律 映射 两个集合中元素相互对应的关系
  • 远程注册表访问

    远程注册表访问 注册表访问控件 Registry Access控件 是一个用VC编写的Server Component 它封装了对注册表的所有操作 通常用来扩展VB或其它编程工具的注册表访问功能 系统管理员可以把它嵌入ASP页面中 从而实现
  • QT笔记- 在指定目录创建自定义类型的文件

    函数 过程分为两步 指定包含目录的文件名 和 创建文件 使用的类是QFile类 用到的函数如下 QFile QFile const QString name bool QFile open QIODevice OpenModeFlag mo
  • N元线性函数拟合的C++实现

    一元线性方程可以看做是多元函数的特例 现在用矩阵形式表述多元函数情况下 最小二乘的一般形式 设拟合多项式为 各店到这条曲线的距离之和 即偏差平方和如下 对等式右边求ai的偏导数 得到 把这些等式表示成矩阵的形式 就可以得到下面的矩阵 3 进
  • 【Python开发】Flask开发实战:个人博客(四)

    Flask开发实战 个人博客 四 本篇博客将是 Flask开发实战 个人博客 的最后一篇 本篇文章将会详细介绍博客后台的编写 为了支持管理员管理文章 分类 评论和链接 我们需要提供后台管理功能 通常来说 程序的这一部分被称为管理后台 控制面
  • 程序运行时的存储结构

    程序运行时的存储结构 目标程序在目标机器环境下运行时 只是在自己的运行时的存储空间内完成执行 通常 在有操作系统的情况下 程序在自己的逻辑存储空间内存储和运行 因此 编译程序在生成目标代码时应该明确程序的所有对象在逻辑存储空间是如何存储的
  • 安装完Ubuntu 17.10后要做的几件事

    前几天Ubuntu 17 10终于出来了 正好前几天我电脑重装系统 顺便留了一个分区用来装Linux 所以就在我电脑上安装了Ubuntu 17 10 安装过程就不说了 图形化安装程序 基本安装过几次就熟悉了 所以重点 还是安装完成之后的美化
  • 【Golang 面试算法二叉树 手动建树】

    Golang 面试算法二叉树 手动建树 前言 代码实现 前言 面试中有很多有关二叉树的题目 且需要手动建树 这里记录一下如何用Golang来快速构建一个二叉树 代码实现 我们知道二叉树可以扁平化到数组中 当前节点的左右子节点的在数组中的下标
  • Allegro输出光绘文件规范

    光绘输出操作规范 1 1添加钻孔表 添加钻孔表的具体步骤为 1 通过屏幕右边的Visibility选项的Views列表 将Drill层打开 2 将Visibility选项中的PIN和Via选项都选中 见下图所示 1 2添加钻孔文件 参数设好
  • pyTorch onnx 学习(二)

    添加自定义的onnx operations 在pyTorch中定义的网络图以及其运算 在onnx中不一定支持 因此 需要自定义的添加operators 如果onnx支持则可以直接使用 一下是支持的网络以及运算 add nonzero alp
  • Android定制实现上网限制iptables

    随着智能手机和平板的普及 现在的孩子几乎人手一部手机或平板 所以常常能看到一些孩子抱着手机玩游戏或是浏览网页 一玩就是一整天 家长们不免担心自己的孩子是不是会浏览不适合他们看的网页 是不是玩的时间太长 导致他们对其他的事情 比如运动 学习和
  • Windows pytesseract image_to_osd Invalid resolution 0 dpi. Using 70 instead. Too few characters报错及解决

    Windows pytesseract image to osd Invalid resolution 0 dpi Using 70 instead Too few characters报错及解决 1 安装 python3 7 pip in
  • otsu算法_Otsu 灰度图像阈值算法及实现

    人工智能导论课的第一次作业 文末提供 HTML 文件源码 可直接体验 一 简介 我们要做的 其实就是将一张 彩色 图片 转成黑白图片 二值图 二值图 只有黑色或白色 000 或 fff 0 或 255 看看效果图就基本了解了 左原图 右图经