大津阈值分割(OSTU)
文章首发于我的个人博客
大津法是一种灰度图像自适应阈值分割算法,是日本学者Ostu于1979年提出,又称类间方差阈值分割法。大津法根据图像的灰度分布将图像分为前景和背景两部分,前景是我们分割出来的部分。前景和背景的分割值就是我们要通过类间方差法求出的阈值。
一、算法原理
设图像灰度级为L,灰度级为i的像素点数为ni,那么直方图分布为:
pi=ni/N,∑i=0L−1pi=1p_i = n_i /N, \sum_{i=0}^{L-1}p_i=1 pi=ni/N,i=0∑L−1pi=1
按灰度级用阈值t划分为两类:C_0=(0,1,…,t)和C_1=(t+1,t+2…,L-1)。因此C_0类和C_1类的概率级均值分别由一下各式给出:
w0=Pr(C0)=∑i=0kpiw_0=Pr(C_0)=\sum_{i=0}^{k}p_i w0=Pr(C0)=i=0∑kpi
w1=Pr(C1)=∑i=k+1L−1pi=1−w0w_1=Pr(C_1)=\sum_{i=k+1}^{L-1}p_i = 1-w_0 w1=Pr(C1)=i=k+1∑L−1pi=1−w0
u0=∑i=0kiPr(i∣C0)=∑i=0kipi/w0u_0=\sum_{i=0}^{k}iPr(i|C_0)=\sum_{i=0}^{k}ip_i/w_0 u0=i=0∑kiPr(i∣C0)=i=0∑kipi/w0
u1=∑i=k+1L−1iPr(i∣C1)=∑i=k+1L−1ipi/w1u_1=\sum_{i=k+1}^{L-1}iPr(i|C_1)=\sum_{i=k+1}^{L-1}ip_i/w_1 u1=i=k+1∑L−1iPr(i∣C1)=i=k+1∑L−1ipi/w1
uT=∑i=0L−1ipiu_T=\sum_{i=0}^{L-1}ip_i uT=i=0∑L−1ipi
可以看出,对任何t值,下式都能成立:
wou0+w1u1=uT,w0+w1=1w_ou_0+w_1u_1=u_T,w_0+w_1=1 wou0+w1u1=uT,w0+w1=1
C_0和C_1类的方差可由下式求得:
σ02=∑i=0t(i−u0)2pi/w0\sigma_0^2=\sum_{i=0}^{t}(i-u_0)^2p_i/w_0 σ02=i=0∑t(i−u0)2pi/w0
σ12=∑i=t+1L−1(i−u1)2pi/w1\sigma_1^2=\sum_{i=t+1}^{L-1}(i-u_1)^2p_i/w_1 σ12=i=t+1∑L−1(i−u1)2pi/w1
由此便可定义,类内方差(within):
σw2=w0σ02+w1σ12\sigma_w^2=w_0\sigma_0^2+w_1\sigma_1^2 σw2=w0σ02+w1σ12
类间方差(Between):
σB2=w0(u0−uT)2+w1(u1−uT)2=w0w1(u1−u0)2\sigma_B^2=w_0(u_0-u_T)^2+w_1(u_1-u_T)^2=w_0w_1(u_1-u_0)^2 σB2=w0(u0−uT)2+w1(u1−uT)2=w0w1(u1−u0)2
总体方差:
σT2=σB2+σw2\sigma_T^2=\sigma_B^2+\sigma_w^2 σT2=σB2+σw2
何为类间方差?我们将灰度级L按t非为两类,反应在直方图上就是两类灰度。我们要做的就是找到能使两边灰度差的最大的阈值,根据这个阈值对灰度图像进行分割。因此我们要做的就是找到能使类间方差最大的t值。
二、类间方差推导
σB2=w0(μ0−μT)2+w1(μ1−μT)2=w0[μ0−w0μ0−w1μ1]2+w1[μ1−w0μ0−w1μ1]2=w0[(1−w0)μ0−w1μ1]2+w1[(1−w1)μ1−w0μ0]2=w0[w1μ0−w1μ1]2+w1[w0μ1−w0μ0]2=w0w1(μ0−μ1)2+w0w1(μ1−μ0)2=(μ1−μ0)2w0w1(w0+w1)=w0w1(μ1−μ0)2{\sigma_B}^2=w_0(\mu_0-\mu_T)^2+w_1(\mu_1-\mu_T)^2 \\ = w_0[\mu_0-w_0\mu_0-w_1\mu_1]^2+w_1[\mu_1-w_0\mu_0-w_1\mu_1]^2 \\ = w_0[(1-w_0)\mu_0-w_1\mu_1]^2+w_1[(1-w_1)\mu_1-w_0\mu_0]^2 \\ =w_0[w_1\mu_0-w_1\mu_1]^2+w_1[w_0\mu_1-w_0\mu_0]^2 \\ =w_0w_1(\mu_0-\mu_1)^2+w_0w_1(\mu_1-\mu_0)^2 \\ =(\mu_1-\mu_0)^2w_0w_1(w_0+w_1)\\ =w_0w_1(\mu_1-\mu_0)^2 σB2=w0(μ0−μT)2+w1(μ1−μT)2=w0[μ0−w0μ0−w1μ1]2+w1[μ1−w0μ0−w1μ1]2=w0[(1−w0)μ0−w1μ1]2+w1[(1−w1)μ1−w0μ0]2=w0[w1μ0−w1μ1]2+w1[w0μ1−w0μ0]2=w0w1(μ0−μ1)2+w0w1(μ1−μ0)2=(μ1−μ0)2w0w1(w0+w1)=w0w1(μ1−μ0)2
三、c++实现(核心代码)
auto tempImage = originImage.clone();std::vector<int> countPixel(256, 0);//直方图灰度分布概率std::vector<float> pixelProb;std::vector<int> pixel(256);for(int i = 0; i < 256; i++){pixel[i] = i;}for(int i = 0; i < tempImage.rows; i++){for(int j = 0; j < tempImage.cols; j++){countPixel[tempImage.at<uchar>(i, j)]++;}}//计算直方图分布float sum_pixel = tempImage.rows * tempImage.cols;for(auto iter = countPixel.begin(); iter != countPixel.end(); iter++){pixelProb.push_back(*iter / sum_pixel);}//类内方差std::vector<float> class_within_variance_vec;//类间方差std::vector<float> class_between_variance_vec;for(int k = 0; k < 256; k++){//类0的概率float class_0_prob = 0;//类1的概率float class_1_prob = 0;for(int i = 0; i <= k; i++){class_0_prob += pixelProb[i];}class_1_prob = 1 - class_0_prob;//std::cout<<"class_0_prob:"<<class_0_prob<<" class_1_prob:"<<class_1_prob<<std::endl;//类0(前景)灰度均值float class_0_average = 0;//类1(背景)灰度均值float class_1_average = 0;for(int i = 0; i <= k; i++){class_0_average += i * (pixelProb[i] / (class_0_prob+0.000001));}for(int i = k+1; i <= 255; i++){class_1_average += i * (pixelProb[i] / (class_1_prob+0.000001));}//类0(前景)方差float class_0_variance = 0;//类1(背景)方差float class_1_variance = 0;for(int i = 0; i <= k; i++){class_0_variance += std::pow((i-class_0_average),2)*(pixelProb[i]/(class_0_prob+0.000001));}for(int i = k+1; i <= 255; i++){class_1_variance += std::pow((i-class_1_average),2)*(pixelProb[i]/(class_1_prob+0.000001));}//类内方差float class_within_variance = class_0_prob*std::pow(class_0_variance,2) + class_1_prob*std::pow(class_1_variance,2);class_within_variance_vec.push_back(class_within_variance);//类间方差float class_between_variance = class_0_prob * class_1_prob * std::pow((class_1_average-class_0_average),2);class_between_variance_vec.push_back(class_between_variance);}auto max_value_iter = std::max_element(class_between_variance_vec.begin(), class_between_variance_vec.end());//得到类间方差最大值int k_value = std::distance(class_between_variance_vec.begin(), max_value_iter);std::cout<<"k_value:"<< k_value<<" max_var:"<<*max_value_iter<<std::endl;/* auto min_value_iter = std::min_element(class_within_variance_vec.begin(), class_within_variance_vec.end());int kk_value = std::distance(class_within_variance_vec.begin(), min_value_iter);std::cout<<"kk_value:"<< kk_value<<" max_var:"<<*min_value_iter<<std::endl;*/for(int i = 0; i < tempImage.rows; i++){for(int j = 0; j < tempImage.cols; j++){if(tempImage.at<uchar>(i, j) <= k_value)tempImage.at<uchar>(i, j) = 0;elsetempImage.at<uchar>(i, j) = 255;}}
四、效果对比
下图从左到右依次为,原灰度图、OpenCV提供OSTU算法分割结果、自己实现的OSTU分割效果。
下图为调用matlab函数实现的大津法阈值分割效果
必不可少的Lenna。
大津阈值分割(OSTU)相关推荐
- matlab大津法函数,matlab 大津阈值分割【相关词_ 大津法阈值分割matlab】
阈值法 阈值分割程序 Otsu Thresholding 赞(0) 踩(0) 收藏(0) 说明:大津法实现图像阈值分割的matlab源程序代码 (Otsu Thresholding Image sou ...
- Opencv中的大津阈值分割算法
大津阈值分割算法,返回的阈值可以用于分割图像,对图像进行二值化处理.边缘检测等. 输入: Mat 类型的地址(如Otsu(&src);) 输出: 返回一个int类型的阈值. int Otsu( ...
- 大津阈值分割matlab实验,OTSU(大津法)分割源程序(MATLAB版)
接下来介绍OTSU方法的原理: ************************************************************************************ ...
- 利用阈值分割原理,对给定图像编程实现二值、反二值、截断、反截断、大津阈值、自适应阈值等类型阈值图像分割,给出实现源码和结果图像。
程序 import cv2 import numpy as np from matplotlib import pyplot as pltimg = cv2.imread('1.jpg', 0) # ...
- OpenCV与图像处理学习七——传统图像分割之阈值法(固定阈值、自适应阈值、大津阈值)
OpenCV与图像处理学习七--传统图像分割之阈值法(固定阈值.自适应阈值.大津阈值) 一.固定阈值图像分割 1.1 直方图双峰法 1.2 OpenCV中的固定阈值分割 二.自动阈值图像分割 2.1 ...
- Retinex、log对数变换、直方图均衡化区别,边缘增强Retinex算法与拉普拉斯算法联系、均衡化与亮度调节算法、大津阈值计算
1.其中Retinex算法具有的功能:动态范围压缩(即滤掉了低频部分,提取了高频).色调再现(即还有图像色彩):具有锐化.颜色恒常性.动态范围压缩大.色彩保真度高等特点. 从算法公式上的个人理 ...
- 大津阈值法(OTSU)功能实现
具体的公式推导参见冈萨雷斯 <数字图像处理> Otsu方法又称最大类间方差法,通过把像素分配为两类或多类,计算类间方差,当方差达到最大值时,类分割线(即灰度值)就作为图像分割阈值.Otsu ...
- 具有掩膜功能的大津阈值法(Otsu)
学习记录- 前文说到大津阈值法是一种自适应的基于全局的阈值分割算法,只有在图像直方图分布为双峰的情况下才会呈现出一种比较好的分割效果,但是待分割图像直方图分布并不是每次都是理想的结果.可能会是光照的影 ...
- 自适应阈值算法(大津阈值法)
最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU.它是按图像的灰度特性,将图像分成背景和目标2部分.背景和目标之间的类间方差越大,说明构成图像的 ...
- ostu阈值分割python实现_opencv python 图像二值化/简单阈值化/大津阈值法
1简单的阈值化 cv2.threshold第一个参数是源图像,它应该是灰度图像. 第二个参数是用于对像素值进行分类的阈值, 第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值则要给出的值. ...
最新文章
- [c#基础]ICloneable接口
- 【swjtu】数字电路实验3_1位十进制计数器
- ios Runloop
- android listview下拉动画效果,Android开发中利用ListView实现一个渐变式的下拉刷新动画...
- CentOS 6上配置安装MariaDB,二进制文件,非源码
- org.json.JSONException: Value of type java.lang.String cannot be converted to JSONArra
- HoloLens 2开发:使用Gaze开发,视线小球不停向眼端移动
- Android——selector背景选择器的使用详解(二)
- 一篇个人认为对RNN写的比较好的文章
- C++中将数据(或图像数据)写到txt
- educoder平台答案Java_不会吧!不会还有人没有《java程序设计》学堂在线答案吧...
- 使用C++实现克拉默法则(Cramer‘s law)
- Java开发实习生面试—附简历以及面试题
- 【CFD之道】2018年原创文章汇总
- 北京链家网租房信息的数据分析项目实战
- win10装win7进入不了bios的解决方法
- Python用最简单的代码画出一箭穿心
- txt改成java没反应_为什么我的TXT文档后戳换成java就打不开呢
- 企业网站建设改版的未来方向
- 电子商务平台入驻宁夏
热门文章
- mysql无法修改表字段
- git 某个文件回退到指定版本
- JS/VUE 自定义效验 统一社会信用代码 营业执照注册号
- 写大数据简历的黄金法则及项目经验
- 数据库知识点总结归纳
- [C++] [FLTK] 很久以前写的FLTK计算器
- 服务器主板型号详解,服务器电脑主板科普:各种接口介绍,如何选?
- 使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课...
- FRAGSTATS.4中用移动窗口算法计算景观指标步骤
- 一篇文章搞懂什么是测试,测试是干什么的?