关于自适应阈值,可参考:Wellner 自适应阈值二值化算法

一、大津法OTSU(最大类间方差法)

参考:非黑即白——图像分割入门篇之Otsu阈值

自适应阈值分割—大津法(OTSU算法)C++实现

灰度图像的自动阈值分割(Otsu 法)

在实际运用过程中,大津法表现得最稳定,且无需参数,对于现实图像保持了最好的均匀性和形状特性,而且被商业软件GIMP 和学术软件Matlab采纳为自动阈值法。

原理:

Otsu分割方法求取阈值是求得使类间方差最大的阈值:

假设待分割图像的像素数为N(就是常说的几百万像素了),它有L个灰度级(0,1,…,L-1),灰度级为i的像素数为ni,那么直方图概率密度pi=ni/N(通俗说法就是这一部分像素所占的比例)。假设阈值t将图像分成两类C0和C1,则C0和C1分别对应具有灰度级{0,1,…,k}和{k+1,k+2,…,L-1}的像素。设σB(k)表示阈值为k时的类间方差,则最佳阈值T可以通过求其最大值而得到,

这是什么意思呢?σB(k)是随着k而变化的,那么在k的变化过程中,σB(k)总有一个最大值,T就等于那个对应的k。

上面一直憋着类间方差没有说,它的定义是这样的:

其中p1(k),p2(k)分别是两类的概率密度,m1(k),m2(k)分别是C0和C1的均值(C0和C1都对应一堆像素值,直接求数学平均值),mg是图像的全局均值。

Otsu方法加权地使用了两类的灰度均值信息和概率密度信息,考虑了两类的分布,在实际的应用中取得了很好的效果,彩色分割都可以哦,不过是经过了灰度变换了,不仅仅是简单的灰度变换,下面分割结果通过叠加轮廓展示。

它尤其适用于前背景的方差相差不大的情况。

Otsu实现思路

1. 计算0~255各灰阶对应的像素个数,保存至一个数组中,该数组下标是灰度值,保存内容是当前灰度值对应像素数;

2. 计算背景图像的平均灰度、背景图像像素数所占比例;

3. 计算前景图像的平均灰度、前景图像像素数所占比例;

4. 遍历0~255各灰阶,计算并寻找类间方差极大值;

使用时可直接调用opencv中的threshold函数,将第五个参数设置为CV_THRESH_OTSU。

C++代码实现:

int OtsuAlgThreshold(const Mat image)
{
if(image.channels()!=)
{
cout<<"Please input Gray-image!"<<endl;
return ;
}
int T=; //Otsu算法阈值;
double varValue=; //类间方差中间值保存 ;
double w0=; //前景像素点数所占比例 ;
double w1=; //背景像素点数所占比例 ;
double u0=; //前景平均灰度 ;
double u1=; //背景平均灰度 ;
double Histogram[]={}; //灰度直方图,下标是灰度值,保存内容是灰度值对应的像素点总数 ;
uchar *data=image.data;
double totalNum=image.rows*image.cols; //像素总数 ; //计算灰度直方图分布,Histogram数组下标是灰度值,保存内容是灰度值对应像素点数 ; for(int i=;i<image.rows;i++) //为表述清晰,并没有把rows和cols单独提出来 ;
{
for(int j=;j<image.cols;j++)
{
Histogram[data[i*image.step+j]]++;
}
} for(int i=;i<;i++)
{
//每次遍历之前初始化各变量 ;
w1=; u1=; w0=; u0=; //***********背景各分量值计算**************************
for(int j=;j<=i;j++) //背景部分各值计算;
{
w1+=Histogram[j]; //背景部分像素点总数 ;
u1+=j*Histogram[j]; //背景部分像素总灰度和 ;
} if(w1==) //背景部分像素点数为0时退出 ;
{
break;
} u1=u1/w1; //背景像素平均灰度;
w1=w1/totalNum; // 背景部分像素点数所占比例;
//***********背景各分量值计算************************** //***********前景各分量值计算**************************
for(int k=i+;k<;k++)
{
w0+=Histogram[k]; //前景部分像素点总数 ;
u0+=k*Histogram[k]; //前景部分像素总灰度和 ;
}
if(w0==) //前景部分像素点数为0时退出 ;
{
break;
}
u0=u0/w0; //前景像素平均灰度 ;
w0=w0/totalNum; // 前景部分像素点数所占比例 ;
//***********前景各分量值计算************************** //***********类间方差计算******************************
double varValueI=w0*w1*(u1-u0)*(u1-u0); //当前类间方差计算 ; if(varValue<varValueI)
{
varValue=varValueI;
T=i;
}
}
return T;
}

大津算法可以从图像直方图上有一个更为直观的理解:大津阈值大致上是直方图两个峰值之间低谷的值。

Otsu 方法也不是万能的。当目标与背景的大小比例悬殊时,类间方差准则函数可能呈现双峰或多峰,此时效果不好。这时就要考虑其他的办法了。

二、最大熵阈值分割

参考:最大熵阈值分割法

OpenCV学习笔记(二)之最大熵阈值分割

原理:

1.频率和概率

直方图每个矩形框的数值描述的是图像中相应灰度值的频率。因此,可以说直方图是一种离散的频率分布。给定一个大小为M*N的图像I,直方图中所有矩形框所代表的数值之和,即为图像中的像素数量,即:

相对应的归一化直方图表示为:

0<=i<K 通常被解释为一个随机过程的概率分布或概率密度函数,表示的是图像中像素灰度值为i所出现的概率。i的累积概率值为1,即概率分布p必须满足以下关系:

与累积概率所所对应的累积直方图H是一个离散的分布函数P(),(通常也称为累积分布函数或cdf):

2.最大熵阈值分割

熵是信息理论中一个重要的概念,这种方法常用于数据压缩领域。熵是一种统计测量方法,用以确定随机数据源中所包含的信息数量。例如,包含有N个像素的图像I,可以解释为包含有N个符号的信息,每一个符号的值都独立获取于有限范围K(e.g.,256)中的不同灰度值。

将数字图像建模为一种随机信号处理,意味着必须知道图像灰度中每一个灰度g所发生的概率,即:

因为所有概率应该事先知道,所以这些概率也称为先验概率。对于K个不同灰度值g=0,…,K-1的概率向量可以表示为:

上述概率向量也称为概率分布或称为概率密度函数(pdf)。实际数字图像处理应用当中,先验的概率通常是不知道的,但是这些概率可以通过在一幅图像或多幅图像中观察对应灰度值所发生的频率,从而估算出其概率。图像概率密度函数p(g)可以通过归一化其对应的直方图获得其概率,即:

3.最大熵

数字图像中给定一个估算的概率密度函数p(g),数字图像中的熵定义为:

4.用图像熵进行图像分割

利用图像熵为准则进行图像分割有一定历史了,学者们提出了许多以图像熵为基础进行图像分割的方法。我们介绍一种由Kapuret al提出来,现在仍然使用较广的一种图像熵分割方法。

给定一个特定的阈值q(0<=q<K-1),对于该阈值所分割的两个图像区域C0,C1,其估算的概率密度函数可表示为:

同样的,背景熵可以改写为:

代码:

//一维最大熵阈值分割;
float caculateCurrentEntropy(Mat hist, int threshold)
{
float backgroundSum=,targetSum=;
float * pDataHist=hist.ptr<float>();
for (int i=;i<;i++)
{
//累积背景值;
if (pDataHist[i]<threshold)
{
backgroundSum+=pDataHist[i];
}
//累积目标值;
else
{
targetSum+=pDataHist[i];
}
}
float BackgroundEntropy = , targetEntropy = ;
for (int i=;i<;i++)
{
//计算背景熵;
if (i < threshold)
{
if (pDataHist[i] == )
continue;
float ratio1 = pDataHist[i] / backgroundSum;
//计算当前能量熵;
BackgroundEntropy += -ratio1*logf(ratio1);
}
else //计算目标熵;
{
if (pDataHist[i] == )
continue;
float ratio2 = pDataHist[i] / targetSum;
targetEntropy += -ratio2*logf(ratio2);
} } return (BackgroundEntropy+targetEntropy);
} void tseg(Mat img,Mat &res)
{//计算原图一维灰度直方图;
int nimages=;
int channels[]={};
Mat outputHist;
int dims=;
int histSize[]={};
float hranges[]={,};
const float *ranges[]={hranges}; calcHist(&img,nimages,channels,Mat(),outputHist,dims,histSize,ranges); float maxentropy = ;
int max_index = ;
for (int i = ; i < ; i++)
{
float cur_entropy = caculateCurrentEntropy(outputHist, i);
if (cur_entropy > maxentropy)
{
maxentropy = cur_entropy;
max_index = i;
}
}
threshold(img, res, max_index, , CV_THRESH_BINARY); }

三、区域生长法

参考:OpenCV - 区域生长算法

其它参考:

七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

OpenCV—使用积分图像统计像素     利用积分图像可以进行自适应阈值分割。

opencv-阈值分割的更多相关文章

  1. opencv——阈值分割图像

    #include "stdafx.h" #include "opencv2\opencv.hpp" using namespace cv; IplImage* ...

  2. 第十四节,OpenCV学习(三)图像的阈值分割

    图像的阈值处理 图像的阈值分割:图像的二值化(Binarization) 阈值分割法的特点是:适用于目标与背景灰度有较强对比的情况,重要的是背景或物体的灰度比较单一,而且总可以得到封闭且连通区域的边界 ...

  3. opencv学习笔记3——图像缩放,翻转和阈值分割

    #图像的缩放操作 #cv.resize(src,dsize,dst=None,,fx=None,fy=None,interpolation=None) #src->原图像,dsize->目 ...

  4. 七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

    http://blog.csdn.net/xw20084898/article/details/17564957 一.工具:VC+OpenCV 二.语言:C++ 三.原理 otsu法(最大类间方差法, ...

  5. 【转】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

    http://blog.csdn.net/xw20084898/article/details/17564957 一.工具:VC+OpenCV 二.语言:C++ 三.原理 otsu法(最大类间方差法, ...

  6. 【图像算法】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)

    图像算法:图像阈值分割 SkySeraph Dec 21st 2010  HQU Email:zgzhaobo@gmail.com    QQ:452728574 Latest Modified Da ...

  7. 自适应阈值分割—大津法(OTSU算法)C++实现

    大津法是一种图像灰度自适应的阈值分割算法,是1979年由日本学者大津提出,并由他的名字命名的.大津法按照图像上灰度值的分布,将图像分成背景和前景两部分看待,前景就是我们要按照阈值分割出来的部分.背景和 ...

  8. python数字图像处理(11):图像自动阈值分割

    图像阈值分割是一种广泛应用的分割技术,利用图像中要提取的目标区域与其背景在灰度特性上的差异,把图像看作具有不同灰度级的两类区域(目标区域和背景区域)的组合,选取一个比较合理的阈值,以确定图像中每个像素 ...

  9. 灰度图像的自动阈值分割(Otsu 法)(转载)

    灰度图像的自动阈值分割(Otsu 法) 机器视觉领域许多算法都要求先对图像进行二值化.这种二值化操作阈值的选取非常重要.阈值选取的不合适,可能得到的结果就毫无用处.今天就来讲讲一种自动计算阈值的方法. ...

  10. 阈值分割与XLD轮廓拼接——第4讲

    一.阈值分割 阈值分割算子众多: threshold :这是最基本最简单的阈值算子. binary_threshold :它是自动阈值算子,自动选出暗(dark)的区域,或者自动选出亮(light)的 ...

随机推荐

  1. 13-MySQL-Ubuntu-数据表的查询-条件查询(二)

    条件查询 1,比较查询(>,<,>=,<=,=)注:SQL查询语句的等于号(=) (1)查询学生表中年龄大于18岁的学生姓名和性别信息 select name,gender f ...

  2. iOS开发系列-UIImageView的contentMode

    typedef NS_ENUM(NSInteger, UIViewContentMode) { UIViewContentModeScaleToFill, UIViewContentModeScale ...

  3. 2019-6-23-win10-uwp-开发-CSDN-访问量统计-源代码

    title author date CreateTime categories win10 uwp 开发 CSDN 访问量统计 源代码 lindexi 2019-6-23 11:2:1 +0800 2 ...

  4. @Formula

    @Formula  计算临时属性. 相当于可以关联查询字段,然后放在实体中当做属性使用. 任务:在User实体层,增加一个额外的属性,来获取Test表中的name字段. 1 表结构 User表 Tes ...

  5. SQL一些记录

    1,2字段约束create unique index [索引名] on 软件信息表(S_SName,S_Edition)

  6. 关于Cadence OrCad 16.6的破解

    相信很多人都知道去老吴的博客上找安装包和破解文件,但是上面的自称一键式破解程序.以及破解图文说明,都是很有问题的. 首先,该一键式破解程序默认的文件后缀与该程序指向的安装压缩包后缀不一致:其次,该程序 ...

  7. Windows 开启win32 控制台

    {     AllocConsole();     FILE *Journal = NULL;     freopen_s(&Journal, "CONOUT$", &qu ...

  8. mysql的卸载重装+导入大量数据失败的解决方案+工具执行和项目执行结果不同

    1.卸载 1>快捷键win+r输入regedit进入注册表 找到3个文件夹,全部删除 . HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eve ...

  9. (转)第05节:Fabric.js的动画设置

    凡是出色的Canvas库都少不了制作动画的方法,Fabric.js也不例外,它有着编写简单且功能强大的动画助手,这就是animate( )方法. animate主要使用代码如下: rect.anima ...

  10. mysql索引原理深度解析

    mysql索引原理深度解析 一.总结 一句话总结: mysql索引是b+树,因为b+树在范围查找.节点查找等方面优化 hash索引,完全平衡二叉树,b树等 1.数据库中最常见的慢查询优化方式是什么? ...