基于阈值的图像分割方法

1. 直方图双峰法(mode 法)

http://www.govyi.com/lunwen/2009/200905/311698.shtml

  Prewitt 等人于六十年代中期提出的直方图双峰法(也称 mode 法) 是典型的全局单阈值分割方法。该方法的基本思想是:假设图像中有明显的目标和背景,则其灰度直方图呈双峰分布,当灰度级直方图具有双峰特性时,选取两峰之间的谷对应的灰度级作为阈值。如果背景的灰度值在整个图像中可以合理地看作为恒定,而且所有物体与背景都具有几乎相同的对比度,那么,选择一个正确的、固定的全局阈值会有较好的效果。例如图4.1所示:

图4.1原始灰度图像

图4.2灰度直方图

选定阈值M为100

算法实现:找到第一个峰值和第二个峰值, 再找到第一和第二个峰值之间的谷值,谷值就是那个阀值了。

2. 固定阈值分割

  就是设定一个固定的值, 像素灰度大于就该像素编程0或者255或者其他的,小于的又等于什么的。

 1 for (int i = 0; i < nWidth; ++i)
 2 {
 3     for (int j = 0; j < nHigh; ++j)
 4     {
 5         if (Image[i][j] >= 阈值)
 6         {
 7             Image[i][j] = 255;
 8         }
 9         else
10         {
11             Image[i][j] = 0;
12         }
13     }
14 }

  这个阈值选什么值呢, 1中的双峰法就是一个阈值产生的方法。

3. 半阈值分割

 1 for (j = 0; j < height; j++)
 2 {
 3     for (i = 0; i < wide; i++)
 4     {
 5         lpSrc = p_data + wide*j + i;
 6         lpDst = temp + wide*j + i;
 7
 8         if ((*lpSrc - 阈值) < 30)
 9             *lpDst = *lpSrc;
10         else
11             *lpDst = 255;
12     }
13 }

  不知道为什么这么做, 为什么这样就叫做半阈值?

4. 迭代阈值图像分割

http://topic.csdn.net/u/20080402/10/d3cb6789-fa60-4758-b232-7a89926f07b9.html

迭代法是基于逼近的思想,其步骤如下:

1. 求出图象的最大灰度值和最小灰度值,分别记为ZMAX和ZMIN,令初始阈值T0=(ZMAX+ZMIN)/2;

2. 根据阈值TK将图象分割为前景和背景,分别求出两者的平均灰度值ZO和ZB

3. 求出新阈值TK+1=(ZO+ZB)/2;

4. 若TK==TK+1,则所得即为阈值;否则转2,迭代计算。

我想问下,ZO和ZB怎么求??

1. 统计图像灰度直方图

2. 找到最大灰度值ZMAX和最小灰度值ZMIN,并计算T0 =(ZMAX+ZMIN)/2

3. 计算小于T0的所有灰度的均值ZO和大于T0的所有灰度的均值ZB(用直方图求就可以)。

例如,你的直方图从10到250有值,则T0 = 260/2 = 130.

ZO = Sum(nHist[i] * i) / Sum(nHist[i]); 10 <= i <= 130

BO = Sum(nHist[i] * i) / Sum(nHist[i]); 131 <= i <= 250

  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 1 ZO = .0, ZB = .0;
 2 int nB = 0, nO = 0;
 3 BYTE bytVal = 0;
 4
 5 while (还有图像数据没读完)
 6 {
 7     bytVal = ReadNextPixel();
 8     if (bytVal > T0)
 9     {
10         ZB += bytVal;
11         ++nB;
12     }
13     else
14     {
15         ZO += bytVal;
16         ++nO;
17     }
18 }
19 ZO /= nO;
20 ZB /= nB;

  //////////////////////////////////////////////////////////////////////////////////////////////////////////

伪代码1

A. 找到灰度图中最大灰度nZmax和最小灰度nZmin(代码略)

B. 求T0。

T0 = (nZmax + nZmin) / 2;

C. 迭代了求出阈值

 1 int i;
 2 while (true)
 3 {
 4     // 计算下一个迭代阀值
 5     for (i = 0; i < T0 + 1; i++)
 6     {
 7         Temp0 += tongji[i] * i;
 8         Temp1 += tongji[i];
 9     }
10     for (i = T0 + 1; i < 256; i++)
11     {
12         Temp2 += tongji[i] * i;
13         Temp3 += tongji[i];
14     }
15     // (大于T0的灰度均值 + 小于T0的灰度均值) / 2
16     T2 = (Temp0 / Temp1 + Temp2 / Temp3) / 2;
17     // 看迭代结果是否已收敛
18     if (T0 == T2)
19         break;
20     else
21         T0 = T2;
22 }

D. 根据上一步求到的T2阈值进行图像分割

// 对各像素进行灰度转换

for (j = 0; j < height; j ++)

{

for (i = 0; i < wide; i ++)

{

// 读取像素

unsigned char temp = *((unsigned char *)p_data + wide * j + i);

// 判断像素灰度值是否超出范围

if (temp < T0)

temp = 0;

else

temp = 255;

// 回写处理完的像素

*((unsigned char *)p_data + wide * j + i) = temp;

}

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////

伪代码2

C. 找到灰度图中最大灰度iMaxGrayValue和最小灰度iMinGrayValue (代码略)

D.求iNewThreshold。

iNewThreshold = (iMaxGrayValue + iMinGrayValue) / 2;

C. 迭代了求出阈值

//迭代求最佳阈值

iNewThreshold = (iMinGrayValue + iMaxGrayValue)/2;

iThreshold = 0;

for(iIterationTimes = 0; iThreshold != iNewThreshold && iIterationTimes < 100;iIterationTimes ++)

{

iThreshold = iNewThreshold;

lP1 =0;

lP2 =0;

lS1 = 0;

lS2 = 0;

//求两个区域的灰度平均值

for (i = iMinGrayValue;i < iThreshold;i++)

{

lP1 += lHistogram[i]*i;

lS1 += lHistogram[i];

}

iMean1GrayValue = (unsigned char)(lP1 / lS1);

for (i = iThreshold+1;i < iMaxGrayValue;i++)

{

lP2 += lHistogram[i]*i;

lS2 += lHistogram[i];

}

iMean2GrayValue = (unsigned char)(lP2 / lS2);

iNewThreshold =  (iMean1GrayValue + iMean2GrayValue)/2;

}

// 这里限制的迭代次数不大于100,考虑到效率吧。

D. 根据上一步求到的iNewThreshold阈值进行图像分割

//根据阈值将图像二值化

for (i = 0;i < lHeight ;i++)

{

for(j = 0;j < lWidth ;j++)

{

// 指向源图像倒数第j行,第i个象素的指针

lpSrc = (char *)lpDIBBits + lLineBytes *i + j;

// 指向目标图像倒数第j行,第i个象素的指针

lpDst = (char *)lpNewDIBBits + lLineBytes *i + j;

pixel = (unsigned char)*lpSrc;

if(pixel <= iThreshold)

{

*lpDst = (unsigned char)0;

}

else

{

*lpDst = (unsigned char)255;

}

}

}

5. 自适应阈值图像分割

在许多情况下,物体和背景的对比度在图象中不是各处一样的,这时很难用统一的一个阈值将物体与背景分开。这时可以根据图象的局部特征分别采用不同的阈值进行分割。实际处理时,需要按照具体问题将图象分成若干子区域分别选择阈值,或者动态地根据一定的邻域范围选择每点处的阈值,进行图象分割。

1). 大津法(OTSU)

最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津

法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差

越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部

分差别变小。因此,使类间方差最大的分割意味着错分概率最小。

对于图像I(x,y),前景(即目标)和背景的分割阈值记作T, 属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均灰度记为μ,类间方差记为g。

假设图像的背景较暗,并且图像的大小为M×N,

图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:

      ω0 = N0/ M×N        (1)

      ω1 = N1/ M×N        (2)

      N0 + N1 = M×N       (3)

      ω0 + ω1 = 1          (4)

      μ= ω0 * μ0 + ω1 * μ1   (5)

      g = ω0 (μ0 -μ) ^ 2 + ω1 (μ1 - μ)^2    (6)

将式(5)代入式(6),得到等价公式:

g = ω0 ω1 (μ0 - μ1) ^ 2    (7)

采用遍历的方法得到使类间方差最大的阈值T,即为所求。

Otus算法使用的是聚类的思想,即把图像的灰度数按灰度级分成2个部分,使2个部分的之间的灰度值差异最大,每个部分之内的灰度差异最小的,找到这样的一个灰度级t划分。通过方差的计算实现,即方差最小的值对应的t即是理想的划分。

http://hi.baidu.com/cwynamespace/blog/item/896ed529955c61f998250a47.html

伪代码1)

FLOAT result;

int cnt0;

int cnt1;

FLOAT max=0.0;

for (thre = 1; thre < 255; thre++)

{

cnt0=0;

cnt1=0;

pixeltotalC0=0.0;

pixeltotalC1=0.0;

// 计算背景与目标的像素数各是多少

// 计算背景与目标的像素值总和各是多少

for (i=0; i<lHeight; i++)

{

for (j=0; j<lWidth; j++)

{

if (ImageSrc[i][j] <= thre)

{

cnt0++;

pixeltotalC0 += ImageSrc[i][j];

}

else

{

cnt1++;

pixeltotalC1 += ImageSrc[i][j];

}

}

}

cnt0=cnt0;

cnt1=cnt1;

rateC0 = 1.0 * cnt0 / (lHeight * lWidth); // 计算背景的面积比例

rateC1 = 1 - rateC0;                           // 计算目标的面积比例

// 计算背景平均灰度

if (cnt0 != 0)

{

pixelaverC0 = pixeltotalC0 / cnt0;

}

else

{

pixelaverC0 = 0;

}

// 计算目标平均灰度

if (cnt1 !=0)

{

pixelaverC1 = pixeltotalC1 / cnt1;

}

else

{

pixelaverC1 = 0;

}

// 计算类间方差

result = rateC0 * rateC1 * (pixelaverC0 - pixelaverC1) * (pixelaverC0 - pixelaverC1);

// 找到最大的类间方差, 就找到最佳的阈值了

if(result > max)

{

max = result;

threbest = thre;

}

}

// 进行二值化

for (i=0; i<lHeight; i++)

{

for (j=0; j<lWidth; j++)

{

if (ImageSrc[i][j] >= threbest)

{

ImageDst[i][j] = (unsigned char)255;

}

else

{

ImageDst[i][j] = (unsigned char)0;

}

}

}

明显这段代码的效率会低一点,它是怎对每一个灰度值在图像中的所有点进行计算。

看下面代码,效率会高一点。

伪代码2)

http://fcwhx007.bokewu.com/blog173376.htm

/*

OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。

算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。划分点就是求得的阈值。

parameter: *image --- buffer for image

rows, cols --- size of image

x0, y0, dx, dy --- region of vector used for computing threshold

vvv --- debug option, is 0, no debug information outputed

*/

/*======================================================================*/

/* OTSU global thresholding routine */

/* takes a 2D unsigned char array pointer, number of rows, and */

/* number of cols in the array. returns the value of the threshold */

/*======================================================================*/

// 这段代码可以针对图像的区域

int otsu (unsigned char *image, int rows, int cols, int x0, int y0, int dx, int dy)

{

unsigned char *np; // 图像指针

int thresholdValue=1; // 阈值

int ihist[256]; // 图像直方图,个点

int i, j, k; // various counters

int n, n1, n2, gmin, gmax;

double m1, m2, sum, csum, fmax, sb;

// 对直方图置零...

memset(ihist, 0, sizeof(ihist));

gmin=255; gmax=0;

// 生成直方图

// 求出最大像素值和最小像素值

// 求出图像中各个灰度值的个数存于数组ihist中

for (i = y0 + 1; i < y0 + dy - 1; i++)

{

np = &image[i*cols+x0+1];

for (j = x0 + 1; j < x0 + dx - 1; j++)

{

ihist[*np]++;

if(*np > gmax) gmax=*np;

if(*np < gmin) gmin=*np;

np++; /* next pixel */

}

}

// set up everything

sum = csum = 0.0;

n = 0;

// 不知道这个有什么用?

for (k = 0; k <= 255; k++)

{

// 图像的总灰度值

sum += (double) k * (double) ihist[k]; /* x*f(x) 质量矩*/

// 总像素点数? 不就是等于宽*高吗

n += ihist[k]; /* f(x) 质量*/

}

if (!n)

{

// if n has no value, there is problems...

fprintf (stderr, "NOT NORMAL thresholdValue = 160/n";

return (160);

}

// do the otsu global thresholding method

fmax = -1.0;

n1 = 0;

for (k = 0; k < 255; k++)

{

n1 += ihist[k];

if (!n1)

{

continue;

}

n2 = n - n1;

if (n2 == 0)

{

break;

}

csum += (double) k *ihist[k];

m1 = csum / n1;

m2 = (sum - csum) / n2;

sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);

/* bbg: note: can be optimized. */

if (sb > fmax)

{

fmax = sb;

thresholdValue = k;

}

}

// at this point we have our thresholding value

return(thresholdValue);

}

http://hi.baidu.com/flyingmooding/blog/item/a434e134e3139bd7a2cc2b63.html

2). 均值法

思想很简单,就是把图像分成m*n块子图,求取每一块子图的灰度均值(就是所有像素灰度值之和除以像素点的数量),这个均值就是阈值了。

这种方法明显不比大津法好,因为均值法和大津法都是从图像整体来考虑阈值的,但是大津法找了一个类间方差最大值来求出最佳阈值的;这两种方法子图越多应该分割效果会好一点,但效率可能会变慢。

6. 最佳阈值

阈值的选择需要根据具体问题来确定,一般通过实验来确定。对于给定的图象,可以通过分析直方图的方法确定最佳的阈值,例如当直方图明显呈现双峰情况时,可以选择两个峰值的中点作为最佳阈值。

所谓最佳阈值就是根据一定的方法(例如双峰法),找出图像中目标与背景的分割最佳阈值就是了。方法多种多样,对不同的图片可以有不同的方法(因为不同的图片有不同的特点)。方法是多种多样的,答案是丰富多彩的。

转自:http://blog.csdn.net/bagboy_taobao_com/article/details/5645425

附:OpenCv中实现了三种跟图像分割相关的算法(http://www.cnblogs.com/xrwang/archive/2010/02/28/ImageSegmentation.html)

时间: 2024-08-29 17:51:44

基于阈值的图像分割方法的相关文章

图像分割—基于图的图像分割(Graph-Based Image Segmentation)

 图像分割-基于图的图像分割(Graph-Based Image Segmentation) Reference: Efficient Graph-Based Image Segmentation,IJCV 2004,MIT Code 图像分割-基于图的图像分割(OpenCV源码) Graph-Based Segmentation 是经典的图像分割算法,作者Felzenszwalb也是提出DPM算法的大牛.该算法是基于图的贪心聚类算法,实现简单,速度比较快,精度也还行.不过,目前直接用它做分

基于图的图像分割(Graph-Based Image Segmentation)

一.介绍 基于图的图像分割(Graph-Based Image Segmentation),论文<Efficient Graph-Based Image Segmentation>,P. Felzenszwalb, D. Huttenlocher,International Journal of Computer Vision, Vol. 59, No. 2, September 2004 论文下载和论文提供的C++代码在这里. Graph-Based Segmentation是经典的图像分割

OpenCV2学习笔记(四):两种图像分割方法比较

此次研究两种图像分割法,分别是基于形态学的分水岭算法和基于图割理论的GrabCut算法.OpenCV均提供了两张算法或其变种.鉴于研究所需,记录一些知识点,开发平台为OpenCV2.4.9+Qt5.3.2. 一.使用分水岭算法进行图像分割 分水岭变换是一种常用的图像处理算法,在网上很容易搜到详细的原理分析.简单来说,这是一种基于拓扑理论的数学形态学的图像分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水

了解移动用户的隐私期望:一种基于推荐的Crowdsourcing方法

应学习之需,最近一段时间阅读了一篇论文,特写下总结,若有纰漏,还望指出. 目录 引言 推荐机制 1.1 为什么要了解移动用户的隐私期望 1.移动设备的广泛使用存在一些潜在的隐私威胁和信息泄漏. 2.系统供应商针对这个问题已经提出了相应措施,例如:苹果的iOS系统可以让用户控制应用是否可以访问特定的敏感数据源.Android平台同样也有类似的细粒度权限控制机制.然而,存在自身缺点:不包括所有的用户都具备知识背景能够正确地进行隐私配置.同时是一项乏味且具有挑战性的工作.用户体验不高. 3.没有一个简

数据库分表和分库的原理及基于thinkPHP的实现方法

为什么要分表,分库: 当我们的数据表数据量,访问量很大,或者是使用频繁的时候,一个数据表已经不能承受如此大的数据访问和存储,所以,为了减轻数据库的负担,加快数据的存储,就需要将一张表分成多张,及将一类数据存入不同的几张表,当分表已经不能满足需求是,我们还可以分库,及用几个数据库存储. 分表会随着需求和功能的不同有不同的实现方法,下面是我做项目中的一个例子: 需求:product,product_price两张表是一对多的关系,及产品和产品每日的价格,一个产品对应几种价格,现在由于产品表数据量很大

基于fMRI生理噪声抑制方法知识的应用研究

第六章 基于fMRI生理噪声抑制方法知识的应用研究 6.1 引言 生理噪声抑制研究的应用可分为两个方向,纵向研究应用和横向研究应用.将生理噪声抑制操作融入fMRI信号分析的预处理环节中,属于纵向研究应用.比如,Kelley等人[74]利用python编程语言编写的生理噪声处理工具包PhysioNoise:牛津大学功能磁共振研究中心推出的FSL(FMRIB Software Library)软件包[75]融入了生理噪声抑制预处理组件PNM(Physiological Noise Modelling

基于区域生长的图像分割法问题(1)

matlab I The input character is not valid in MATLAB statements or expressions. 今天在用基于区域生长的图像分割法时出现了这个问题,总结一下 解决办法 1.保存的文件名是否非法,不要用汉字保存 2.是否使用了汉字输入Editor 3.imread的图片是否是汉字,数字开头等非法内容

机器学习四 -- 基于概率论的分类方法:朴素贝叶斯

基于概率的分类方法:朴素贝叶斯 贝叶斯决策理论 朴素贝叶斯是贝叶斯决策理论的一部分,所以在讲解朴素贝叶斯之前我们先快速简单了解一下贝叶斯决策理论知识. 贝叶斯决策理论的核心思想:选择具有最高概率的决策.比如我们毕业选择就业方向,选择C++方向的概率为0.3,选择Java的概率为0.2,选择机器学习的概率为0.5.那么我们就把这样的一位毕业生就业方向归类为机器学习方向. 条件概率 什么是条件概率?事件A在另一个事件B已知发生条件下的发生概率,记为P(A|B),读作“在B条件下A的概率”. 例子1:

浅谈分词算法(2)基于词典的分词方法

[TOC] 前言 在浅谈分词算法(1)分词中的基本问题中我们探讨了分词中的基本问题,也提到了基于词典的分词方法.基于词典的分词方法是一种比较传统的方式,这类分词方法有很多,如:正向最大匹配(forward maximum matching method, FMM).逆向最大匹配(backward maximum matching method,BMM).双向扫描法.逐词遍历法.N-最短路径方法以及基于词的n-gram语法模型的分词方法等等.对于这类方法,词典的整理选择在其中占到了很重要的作用,本