图像处理算法 阈值

2018-10-30 22:19:36 Eastmount 阅读数 8397

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

该系列在github所有源代码:https://github.com/eastmountyxz/ImageProcessing-Python
PS:请求帮忙点个Star,哈哈,第一次使用Github,以后会分享更多代码,一起加油。

同时推荐作者的C++图像系列知识:
[数字图像处理] 一.MFC详解显示BMP格式图片
[数字图像处理] 二.MFC单文档分割窗口显示图片
[数字图像处理] 三.MFC实现图像灰度、采样和量化功能详解
[数字图像处理] 四.MFC对话框绘制灰度直方图
[数字图像处理] 五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
[数字图像处理] 六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解
[数字图像处理] 七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

前文参考:
[Python图像处理] 一.图像处理基础知识及OpenCV入门函数
[Python图像处理] 二.OpenCV+Numpy库读取与修改像素
[Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
[Python图像处理] 四.图像平滑之均值滤波、方框滤波、高斯滤波及中值滤波
[Python图像处理] 五.图像融合、加法运算及图像类型转换
[Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移

本篇文章主要讲解Python调用OpenCV实现图像阈值化处理操作,包括二进制阈值化、反二进制阈值化、截断阈值化、反阈值化为0、阈值化为0。全文均是基础知识,希望对您有所帮助。
1.阈值化
2.二进制阈值化
3.反二进制阈值化
4.截断阈值化
5.反阈值化为0
6.阈值化为0

PS:文章参考自己以前系列图像处理文章及OpenCV库函数,同时部分参考网易云视频,推荐大家去学习。同时,本篇文章涉及到《计算机图形学》基础知识,请大家下来补充。

PSS:2019年1~2月作者参加了CSDN2018年博客评选,希望您能投出宝贵的一票。我是59号,Eastmount,杨秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

五年来写了314篇博客,12个专栏,是真的热爱分享,热爱CSDN这个平台,也想帮助更多的人,专栏包括Python、数据挖掘、网络爬虫、图像处理、C#、Android等。现在也当了两年老师,更是觉得有义务教好每一个学生,让贵州学子好好写点代码,学点技术,"师者,传到授业解惑也",提前祝大家新年快乐。2019我们携手共进,为爱而生。

一. 阈值化

(注:该部分参考作者的论文《基于苗族服饰的图像锐化和边缘提取技术研究》)

图像的二值化或阈值化(Binarization)旨在提取图像中的目标物体,将背景以及噪声区分开来。通常会设定一个阈值T,通过T将图像的像素划分为两类:大于T的像素群和小于T的像素群。
灰度转换处理后的图像中,每个像素都只有一个灰度值,其大小表示明暗程度。二值化处理可以将图像中的像素划分为两类颜色,常用的二值化算法如公式1所示:

{Y=0gray<TY=255gray>=T\begin{cases} Y=0,gray<T\\ Y=255,gray>=T\\ \end{cases}
当灰度Gray小于阈值T时,其像素设置为0,表示黑色;当灰度Gray大于或等于阈值T时,其Y值为255,表示白色。
Python OpenCV中提供了阈值函数threshold()实现二值化处理,其公式及参数如下图所示:
retval, dst = cv2.threshold(src, thresh, maxval, type)

常用的方法如下表所示,其中函数中的参数Gray表示灰度图,参数127表示对像素值进行分类的阈值,参数255表示像素值高于阈值时应该被赋予的新像素值,最后一个参数对应不同的阈值处理方法。
对应OpenCV提供的五张图如下所示,第一张为原图,后面依次为:二进制阈值化、反二进制阈值化、截断阈值化、反阈值化为0、阈值化为0。
二值化处理广泛应用于各行各业,比如生物学中的细胞图分割、交通领域的车牌设别等。在文化应用领域中,通过二值化处理将所需民族文物图像转换为黑白两色图,从而为后面的图像识别提供更好的支撑作用。下图表示图像经过各种二值化处理算法后的结果,其中“BINARY”是最常见的黑白两色处理。


二. 二进制阈值化

该方法先要选定一个特定的阈值量,比如127。新的阈值产生规则如下:
dst(x,y)={maxValifsrc(x,y)>thresh0otherwise dst(x,y) = \begin{cases} maxVal, if src(x,y)>thresh\\ 0,otherwise\\ \end{cases}
(1) 大于等于127的像素点的灰度值设定为最大值(如8位灰度值最大为255)
(2) 灰度值小于127的像素点的灰度值设定为0
例如,163->255,86->0,102->0,201->255。

关键字为 cv2.THRESH_BINARY,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#二进制阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_BINARY)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出为两个返回值,r为127,b为处理结果(大于127设置为255,小于设置为0)。如下图所示:



三. 反二进制阈值化

该方法与二进制阈值化方法相似,先要选定一个特定的灰度值作为阈值,比如127。新的阈值产生规则如下:
dst(x,y)={0ifsrc(x,y)>threshmaxValotherwise dst(x,y) = \begin{cases} 0, if src(x,y)>thresh\\ maxVal,otherwise\\ \end{cases}
(1) 大于127的像素点的灰度值设定为0(以8位灰度图为例)
(2) 小于该阈值的灰度值设定为255
例如,163->0,86->255,102->255,201->0。

关键字为 cv2.THRESH_BINARY_INV,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#反二进制阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_BINARY_INV)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:

该方法得到的结果正好与二进制阈值化方法相反,亮色元素反而处理为黑色,暗色处理为白色。

四. 截断阈值化

该方法需要选定一个阈值,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变,比如127。新的阈值产生规则如下:
dst(x,y)={thresholdifsrc(x,y)>threshsrc(x,y)otherwise dst(x,y) = \begin{cases} threshold, if src(x,y)>thresh\\ src(x,y),otherwise\\ \end{cases}
(1) 大于等于127的像素点的灰度值设定为该阈值127
(2) 小于该阈值的灰度值不改变
例如,163->127,86->86,102->102,201->127。

关键字为 cv2.THRESH_TRUNC,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#截断阈值化处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TRUNC)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示::

该处理方法相当于把图像中比较亮(大于127,偏向于白色)的像素值处理为阈值。

五. 反阈值化为0

该方法先选定一个阈值,比如127,接着对图像的灰度值进行如下处理:
dst(x,y)={0ifsrc(x,y)>threshsrc(x,y)otherwise dst(x,y) = \begin{cases} 0, if src(x,y)>thresh\\ src(x,y),otherwise\\ \end{cases}
(1) 大于等于阈值127的像素点变为0
(2) 小于该阈值的像素点值保持不变
例如,163->0,86->86,102->102,201->0。

关键字为 cv2.THRESH_TOZERO_INV,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#反阈值化为0处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TOZERO_INV)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:



六. 阈值化为0

该方法先选定一个阈值,比如127,接着对图像的灰度值进行如下处理:
dst(x,y)={src(x,y)ifsrc(x,y)>thresh0otherwise dst(x,y) = \begin{cases} src(x,y), if src(x,y)>thresh\\ 0,otherwise\\ \end{cases}
(1) 大于等于阈值127的像素点,值保持不变
(2) 小于该阈值的像素点值设置为0
例如,163->163,86->0,102->0,201->201。

关键字为 cv2.THRESH_TOZERO,完整代码如下:

#encoding:utf-8
import cv2  
import numpy as np  

#读取图片
src = cv2.imread('test.jpg')

#灰度图像处理
GrayImage = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)

#阈值化为0处理
r, b = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TOZERO)
print r

#显示图像
cv2.imshow("src", src)
cv2.imshow("result", b)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:

该算法把比较亮的部分不变,比较暗的部分处理为0。

完整五个算法的对比代码如下所示:

#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt

#读取图像
img=cv2.imread('test.jpg')
lenna_img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  

#阈值化处理
ret,thresh1=cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY)  
ret,thresh2=cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY_INV)  
ret,thresh3=cv2.threshold(GrayImage,127,255,cv2.THRESH_TRUNC)  
ret,thresh4=cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO)  
ret,thresh5=cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO_INV)

#显示结果
titles = ['Gray Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']  
images = [GrayImage, thresh1, thresh2, thresh3, thresh4, thresh5]  
for i in xrange(6):  
   plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()

输出结果如下图所示:

希望文章对大家有所帮助,如果有错误或不足之处,还请海涵。最近经历的事情太多,有喜有悲,关闭了朋友圈,希望通过不断学习和写文章来忘记烦劳,将忧郁转换为动力。哎,总感觉自己在感动这个世界,帮助所有人,而自己却…谁有关心秀璋?晚安。
(By:Eastmount 2018-10-30 晚上10点 https://blog.csdn.net/Eastmount/)

2012-02-11 16:18:32 renshengrumenglibing 阅读数 52206

在图像处理时,受外界光线的干扰一般比较大,假如在阈值分割时采用固


定阈值,那么在环境改变时分割效果受影响极大,那么为了避免此影响就


必须采用动态阈值,自动求出合适的阈值进行分割。
本文的介绍几种主要的图像分割方法,并给出自动阈值分割的源代码




图像分割是图像处理与计算机视觉领域低层次视觉中最为基础和重要的领域之一,它是对图像进行视觉分析和模式识别的基本前提.阈值法是一种传统的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术.已被应用于很多的领域。本文是在阅读大量国内外相关文献的基础上,对阈值分割技术稍做总结,分三个大类综述阈值选取方法,然后对阈值化算法的评估做简要介绍。


1.引言
所谓图像分割是指根据灰度、彩色、空间纹理、几何形状等特征把图像划分成若干个互不相交的区域,使得这些特征在同一区域内,表现出一致性或相似性,而在不同区域间表现出明显的不同[37].简单的讲,就是在一幅图像中,把目标从背景中分离出来,以便于进一步处理。图像分割是图像处理与计算机视觉领域低层次视觉中最为基础和重要的领域之一,它是对图像进行视觉分析和模式识别的基本前提.同时它也是一个经典难题,到目前为止既不存在一种通用的图像分割方法,也不存在一种判断是否分割成功的客观标准。
阈值法是一种传统的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术.已被应用于很多的领域,例如,在红外技术应用中,红外无损检测中红外热图像的分割,红外成像跟踪系统中目标的分割;在遥感应用中,合成孔径雷达图像中目标的分割等;在医学应用中,血液细胞图像的分割,磁共振图像的分割;在农业工程应用中,水果品质无损检测过程中水果图像与背景的分割。在工业生产中,机器视觉运用于产品质量检测等等。在这些应用中,分割是对图像进一步分析、识别的前提,分割的准确性将直接影响后续任务的有效性,其中阈值的选取是图像阈值分割方法中的关键技术。


2.阈值分割的基本概念
图像阈值化分割是一种最常用,同时也是最简单的图像分割方法,它特别适用于目标和背景占据不同灰度级范围的图像[1]。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。图像阈值化的目的是要按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,各个区域内部具有一致的属性,而相邻区域布局有这种一致属性。这样的划分可以通过从灰度级出发选取一个或多个阈值来实现。
阈值分割法是一种基于区域的图像分割技术,其基本原理是:通过设定不同的特征阈值,把图像像素点分为若干类.常用的特征包括:直接来自原始图像的灰度或彩色特征;由原始灰度或彩色值变换得到的特征.设原始图像为f(x,y),按照一定的准则在f(x,y)中找到特征值T,将图像分割为两个部分,分割后的图像为


 
若取 :b0=0(黑),b1=1(白),即为我们通常所说的图像二值化。


   
          (原始图像)    (阈值分割后的二值化图像)


一般意义下,阈值运算可以看作是对图像中某点的灰度、该点的某种局部特性以及该点在图像中的位置的一种函数,这种阈值函数可记作
    T(x,y,N(x,y),f(x,y))
式中,f(x,y)是点(x,y)的灰度值;N(x,y)是点(x,y)的局部邻域特性.根据对T的不同约束,可以得到3种不同类型的阈值[37],即
    点相关的全局阈值T=T(f(x,y))  
(只与点的灰度值有关)
区域相关的全局阈值T=T(N(x,y),f(x,y))  
(与点的灰度值和该点的局部邻域特征有关)
    局部阈值或动态阈值T=T(x,y,N(x,y),f(x,y))
(与点的位置、该点的灰度值和该点邻域特征有关)


图像阈值化这个看似简单的问题,在过去的四十年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法[2-9],但是遗憾的是,如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果,甚至也没有一个理论指导我们选择特定方法处理特定图像。
所有这些阈值化方法,根据使用的是图像的局部信息还是整体信息,可以分为上下文无关(non-contextual)方法(也叫做基于点(point-dependent)的方法)和上下文相关(contextual)方法(也叫做基于区域(region-dependent)的方法);根据对全图使用统一阈值还是对不同区域使用不同阈值,可以分为全局阈值方法(global thresholding)和局部阈值方法(local thresholding,也叫做自适应阈值方法adaptive thresholding);另外,还可以分为双阈值方法(bilever thresholding)和多阈值方法(multithresholding)
本文分三大类对阈值选取技术进行综述:
1) 基于点的全局阈值方法;
2) 基于区域的全局阈值方法
3) 局部阈值方法和多阈值方法




3.基于点的全局阈值选取方法
3.1  p-分位数法
1962年Doyle[10]提出的p-分位数法(也称p-tile法)可以说是最古老的一种阈值选取方法。该方法使目标或背景的像素比例等于其先验概率来设定阈值,简单高效,但是对于先验概率难于估计的图像却无能为力。
例如,根据先验知识,知道图像目标与背景象素的比例为PO/PB,则可根据此条件直接在图像直方图上找到合适的阈值T,使得f(x,y)>=T的象素为目标,f(x,y)<T的象素为背景。


3.2  迭代方法选取阈值[11]
初始阈值选取为图像的平均灰度T0,然后用T0将图像的象素点分作两部分,计算两部分各自的平均灰度,小于T0的部分为TA,大于T0的部分为TB
计算   ,将T1 作为新的全局阈值代替T0,重复以上过程,如此迭代,直至TK 收敛,即TK+1 =TK 
经试验比较,对于直方图双峰明显,谷底较深的图像,迭代方法可以较快地获得满意结果。但是对于直方图双峰不明显,或图像目标和背景比例差异悬殊,迭代法所选取的阈值不如最大类间方差法。


3.3  直方图凹面分析法
从直观上说,图像直方图双峰之间的谷底,应该是比较合理的图像分割阈值,但是实际的直方图是离散的,往往十分粗糙、参差不齐,特别是当有噪声干扰时,有可能形成多个谷底。从而难以用既定的算法,实现对不同类型图像直方图谷底的搜索。
Rosenfeld和Torre[12]提出可以构造一个包含直方图 的最小凸多边形 ,由集差 确定 的凹面。若 和 分别表示 与 在灰度级之处的高度,则 取局部极大值时所对应的灰度级可以作为阈值。也有人使用低通滤波的方法平滑直方图,但是滤波尺度的选择并不容易[13]。
但此方法仍然容易受到噪声干扰,对不同类型的图像,表现出不同的分割效果。往往容易得到假的谷底。但此方法对某些只有单峰直方图的图像,也可以作出分割。如:
 


3.4 最大类间方差法
由Otsu[14]于1978年提出的最大类间方差法以其计算简单、稳定有效,一直广为使用。从模式识别的角度看,最佳阈值应当产生最佳的目标类与北京类的分离性能,此性能我们用类别方差来表征,为此引入类内方差 、类间方差 和总体方差 ,并定义三个等效的准则测量:
 ,  ,  .                 (3)
鉴于计算量的考量,人们一般通过优化第三个准则获取阈值。此方法也有其缺陷,kittler和Illingworth[15]的实验揭示:当图像中目标与背景的大小之比很小时方法失效。
 在实际运用中,往往使用以下简化计算公式:
   (T) = WA(μa-μ)2  + Wb(μb-μ)2 
其中, 为两类间最大方差,WA 为A类概率,μa为A类平均灰度,Wb 为B类概率,μb为B类平均灰度,μ为图像总体平均灰度。
即阈值T将图像分成A,B两部分,使得两类总方差 (T)取最大值的T,即为最佳分割阈值。


3.5 熵方法
八十年代以来,许多学者将Shannon信息熵的概念应用于图像阈值化,其基本思想都是利用图像的灰度分布密度函数定义图像的信息熵,根据假设的不同或视角的不同提出不同的熵准则,最后通过优化该准则得到阈值。Pun[16]通过使后验熵的上限最大来确定阈值。Kapur等人[17]的方法假定目标和背景服从两个不同的概率分布 和 定义
                 (4)
使得熵
                           (5)
达到最大求得最佳阈值。
此方法又称为KSW熵方法。


3.6 最小误差阈值
此方法来源于Bayes最小误差分类方法。
 
Eb(T)是目标类错分到背景类的概率,Eo(T)是背景类错分到目标类的概率
总的误差概率 E(T) = Eb(T) + Eo(T)
使E(T)取最小值,即为最优分类方法。


在Kittler和Illingworth[18]于1986年提出的最小误差法中,直方图被视为目标与背景混合集概率密度函数 的估计
                 (9)
其中, 为先验概率, ,求解下列方程可得到Bayes最小误差阈值
                        (10)
遗憾的是上式中 , 和 通常是未知的,Nakagawa和Rosenfeld[19]提倡用拟合方法从直方图中估计这些参数,但是算法相当复杂,不易实现。




3.7 矩量保持法
矩量保持(moment-preserving)法[20] ,即矩守恒阈值法,是1985年提出的,其基本思想是最佳的阈值应该使分割前后图像的矩量保持不变,由此可以得到一组矩量保持方程,求解该方程组就可以得到最佳阈值。


3.8 模糊集方法
模糊集理论较好的描述了人类视觉中的模糊性和随机性,因此在图像阈值化领域受到了广泛的关注。模糊集阈值化方法的基本思想是,选择一种S状的隶属度函数定义模糊集,隶属度为0.5的灰度级对应了阈值,当然在上述隶属度函数的表达式中阈值是一个未知的参数;然后在此模糊集上定义某种准则函数(例如整个图像的总体模糊度),通过优化准则函数来确定最佳阈值。
Pal等[21]首先,他们把一幅具有 个灰度级的 图像看作一个模糊集 ,其中隶属函数 定义如下:
               (11)
参数 称之为交叉点(即 )。由此从图像 的空间 平面得到模糊特性 平面。然后,基于此模糊集定义了图像的线性模糊度 、二次模糊度 和模糊熵 ,使这三个量取最小值时的交叉点 即为最佳阈值。
文献[21]指出模糊隶属度函数在该算法中的作用仅在于将图像由灰度数据空间转换为模糊空间 ,其函数的形式对增强结果几乎没有影响。这就使我们有理由使用一些形式简单的函数形式。例如国内学者发表的一种模糊阈值方法[22]:
 
隶属度μ(x)表示灰度x具有明亮特性的程度,c为隶属函数窗宽,q对应隶属度为0.5的灰度级。设灰度级 的模糊率为:
  = min{μ(l),1-μ(l)}
则得到整幅图像的模糊率[44] 
 
其中,MN为图像尺寸,L为图像总灰度级, 图像中灰度为 的象素个数。
对应于不同的q值,就可以计算出相应的图像模糊率,选取使得 最小的q值,作为图像分割的最佳阈值即可。


3.9 小结
对于基于点的全局阈值选取方法,除上述主要几种之外还许多,但大多都是以上述基本方法为基础,做出的改进方法或者对算法的优化,如使用递推方法以降低算法复杂性。
例如在文献[42]中,提出一种使目标和背景差距最大的阈值求取方法,类似于最大类间方差阈值法。是它的一种简化算法。
又如1984年Dunn等人[23]提出了均匀化误差阈值选取方法,这种方法实质上是要使将背景点误分为目标点的概率等于将目标点误分为背景点的概率。类似于最小误差阈值法。
近年来有一些新的研究手段被引入到阈值选取中。比如人工智能,在文献[24] 中,描述了如何用人工智能的方法,寻找直方图的谷底点,作为全局阈值分割。其它如神经网络,数学形态学[39][46],小波分析与变换[40]等等。
总的来说,基于点的全局阈值算法,与其它几大类方法相比,算法时间复杂度较低,易于实现,适合应用于在线实时图像处理系统。由于我的研究方向为机器视觉,所作的项目要求算法具有良好的实时性,因此针对基于点的全局阈值方法,阅读了较多的文献,在综述里叙述也相对比较详细。


4 基于区域的全局阈值选取方法
对一幅图像而言,不同的区域,比如说目标区域或背景区域,同一区域内的象素,在位置和灰度级上同时具有较强的一致性和相关性。
而在上述基于点的全局阈值选取方法中,有一个共同的弊病,那就是它们实际上只考虑了直方图提供的灰度级信息,而忽略了图像的空间位置细节,其结果就是它们对于最佳阈值并不是反映在直方图的谷点的情况会束手无策,不幸我们通常遇到的很多图像恰恰是这种情况。另一方面,完全不同的两幅图片却可以有相同的直方图,所以即使对于峰谷明显的情况,这些方法也不能保证你得到合理的阈值。于是,人们又提出了很多基于空间信息的阈值化方法。
可以说,局域区域的全局阈值选取方法,是基于点的方法,再加上考虑点领域内象素相关性质组合而成,所以某些方法常称为“二维xxx方法”。由于考虑了象素领域的相关性质,因此对噪声有一定抑止作用[41]。
4.1 二维熵阈值分割方法[25]
使用灰度级-局域平均灰度级形成的二维灰度直方图[43]进行阈值选取,这样就得到二维熵阈值化方法。
 
(二维灰度直方图: 灰度-领域平均灰度)
如图,在0区和1区,象素的灰度值与领域平均灰度值接近,说明一致性和相关性较强,应该大致属于目标或背景区域;2区和3区一致性和相关性较弱,可以理解为噪声或边界部分。二维熵阈值分割,就是选择(S,T)对,使得目标类和背景类的后验熵最大。(具体方法是一维熵阈值分割的推广,可参见上一节)
Abutaleb[26],和Pal]结合Kapur]和Kirby的方法,分别提出了各自的二维熵阈值化方法,其准则函数都是使目标熵和背景熵之和最大化。Brink[27]的方法则是使这两者中的较小者最大化,该方法的计算复杂度为 ,后来有人改进为递推快速算法将时间复杂度降为 (其中 为最大灰度级数)。 


4.2  简单统计法
Kittler等人[28],[29]提出一种基于简单的图像统计的阈值选取方法。使用这种方法,阈值可以直接计算得到,从而避免了分析灰度直方图,也不涉及准则函数的优化。该方法的计算公式为
                         (19)
其中, 
    
    
因为e(x,y)表征了点(x,y)领域的性质,因此本方法也属于基于区域的全局阈值法。


4.3  直方图变化法
从理论上说,直方图的谷底是非常理想的分割阈值,然后在实际应用中,图像常常受到噪声等的影响而使其直方图上原本分离的峰之间的谷底被填充,或者目标和背景的峰相距很近或者大小差不多,要检测他们的谷底就很难了。
在上一节基于点的全局阈值方法中,我们知道直方图凹面分析法的弊病是容易受到噪声干扰,对不同类型的图像,表现出不同的分割效果。往往容易得到假的谷底。这是由于原始的直方图是离散的,而且含噪声,没有考虑利用象素领域性质。
而直方图变化法,就是利用一些象素领域的局部性质变换原始的直方图为一个新的直方图。这个新的直方图与原始直方图相比,或者峰之间的谷底更深,或者谷转变成峰从而更易于检测。这里的象素领域局部性质,在很多方法中经常用的是象素的梯度值。
 例如,由于目标区的象素具有一定的一致性和相关性,因此梯度值应该较小,背景区也类似。而边界区域或者噪声,就具有较大的梯度值。最简单的直方图变换方法,就是根据梯度值加权,梯度值小的象素权加大,梯度值大的象素权减小。这样,就可以使直方图的双峰更加突起,谷底更加凹陷。


4.4 其它基于区域的全局阈值法
松弛法利用邻域约束条件迭代改进线性方程系统的收敛特性,当用于图像阈值化时其思想是:首先根据灰度级按概率将像素分为“亮”和“暗”两类,然后按照领域像素的概率调整每个像素的概率,调整过程迭代进行,使得属于亮(暗)区域的像素“亮(暗)”的概率变得更大。
其它还有许多方法利用灰度值和梯度值散射图,或者利用灰度值和平均灰度值散射图。


5 局部阈值法和多阈值法


5.1 局部阈值(动态阈值)
当图像中有如下一些情况:有阴影,照度不均匀,各处的对比度不同,突发噪声,背景灰度变化等,如果只用一个固定的全局阈值对整幅图像进行分割,则由于不能兼顾图像各处的情况而使分割效果受到影响。有一种解决办法就是用与象素位置相关的一组阈值(即阈值使坐标的函数)来对图像各部分分别进行分割。这种与坐标相关的阈值也叫动态阈值,此方法也叫变化阈值法,或自适应阈值法。这类算法的时间复杂性可空间复杂性比较大,但是抗噪能力强,对一些用全局阈值不易分割的图像有较好的效果。
例如,一幅照度不均(左边亮右边暗)的原始图像为:

如果只选择一个全局阈值进行分割,那么将出现下面两种情况,都不能得到满意的效果。


                
(阈值低,对亮区效果好,则暗区差)          (阈值高,对暗区效果好,则亮区差)


若使用局部阈值,则可分别在亮区和暗区选择不同的阈值,使得整体分割效果较为理性。


 
(按两个区域取局部阈值的分割结果)
进一步,若每个数字都用不同的局部阈值,则可达到更理想的分割效果。

/************************************************************************/
/* 全局阈值分割  自动求取阈值        */
/************************************************************************/
//自动求取阈值,增加对场景的适应性
//只需求取一次,之后就可以一直使用
#include<cv.h>
#include <highgui.h>
#include <iostream>
#include <math.h>
using namespace std;
int main(){
	IplImage * image,* image2;
	image = cvLoadImage("E:\\image\\dowels.tif",0);
	cvNamedWindow("image",1);
	cvShowImage("image",image);
	image2 = cvCreateImage(cvSize(image->width,image->height),image->depth,1);
	double T = 0;
	double dT0 = 1.0;//阈值求取结束标志
	double dT = 255.0;

	//求取平均灰度,作为阈值T的初始值T0
	  int i, j;
     double T0 = 0,T1 = 0,T2 = 0;//初始阈值
	 int count1,count2;
	 unsigned char * ptr,*dst;
	 for (i = 0 ; i< image->height ; i++)
	 {
		 for (j =0 ; j < image->width;j++)
		 {
			 ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
			 T0 += ((double)(*ptr))/image->width/image->height;
		 }
	 }
	 cout<<"T0:     "<<T0<<endl;
	 T = (int)(T0 + 0.5); 
	 //计算T两侧的灰度平均值,然后把二者的均值赋值给T
	 while (dT > dT0)
	 {

		 T1 = 0;
		 T2 = 0;
		 count1 = 0;
		 count2 = 0;
		 for (i = 0 ; i< image->height ; i++)
		 {
			 for (j =0 ; j < image->width;j++)
			 {
				 ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
				if (*ptr > T)
				{
					T1 += ((double)(*ptr))/image->width/image->height;
					count1++;
				} 
				else if(*ptr < T)
				{
					T2 +=  ((double)(*ptr))/image->width/image->height;
					count2++;
				}
			 }
		 }

		 T1 = T1*image->width*image->height/count1;
		 T2 = T2*image->width*image->height/count2;
		 dT = fabs(T - (T1 + T2)/2);
		  
		 cout<<"T1"<<T1<<endl;
		 cout<<"T2"<<T2<<endl;
		 cout<<"dT  " << dT<<endl;
		 T = (T1 + T2)/2;
		 cout<<"T:     "<<T<<endl;
	 }
	 


	 //根据求取的阈值进行分割
	 for (i = 0 ; i< image2->height ; i++)
	 {
		 for (j =0 ; j < image2->width;j++)
		 {
			 ptr = (unsigned char *)image->imageData + i*image->widthStep + j;
			  dst = (unsigned char *)image2->imageData+i*image2->widthStep+j;
			if (*ptr > T)
			{
				*dst = 255;
			} 
			else
			{
				*dst =0;
			}
		 }
	 }

	 cvNamedWindow("image2",1);
	 cvShowImage("image2",image2);
	 cvSaveImage("E:\\image\\dowels2.tif",image2);
	 cvWaitKey(0);
	 return 0;
}




5.1.1 阈值插值法
 首先将图像分解成系列子图,由于子图相对原图很小,因此受阴影或对比度空间变化等带来的问题的影响会比较小。然后对每个子图计算一个局部阈值(此时的阈值可用任何一种固定阈值选取方法)。通过对这些子图所得到的阈值进行插值,就可以得到对原图中每个象素进行分割所需要的合理阈值。这里对应每个象素的阈值合起来构成的一个曲面,叫做阈值曲面。


5.1.2 水线阈值算法
水线(也称分水岭或流域,watershed)阈值算法可以看成是一种特殊的自适应迭代阈值方法,它的基本思想是:初始时,使用一个较大的阈值将两个目标分开,但目标间的间隙很大;在减小阈值的过程中,两个目标的边界会相向扩张,它们接触前所保留的最后像素集合就给出了目标间的最终边界,此时也就得到了阈值。


5.1.3 其它的局部阈值法
文献[30]提出了一种基于阈值曲面的二维遗传算法。遗传算法是基于进化论中自然选择机理的、并行的、统计的随机化搜索方法,所以在图像处理中常用来确定分割阈值。
 文献[31] [32]中提出一种基于局部梯度最大值的插值方法。首先平滑图像,并求得具有局部梯度最大值的像素点,然后利用这些像素点的位置和灰度在图像上内插,得到灰度级阈值表面。
除此之外,典型的局部阈值方法还有White和Rohrer[33]的加权移动平均阈值方法,Perez和Gonzalez[34]的适用于非均匀照射下图像的局部阈值方法以及Shio[35]的与照射无关的对比度度量阈值方法等。总的来说,这类算法的时间和空间复杂度都较大,但是抗噪能力强,对一些使用全局阈值法不宜分割的图像具有较好的效果。


5.2 多阈值法
很显然,如果图像中含有占据不同灰度级区域的几个目标,则需要使用多个阈值才能将它们分开。其实多域值分割,可以看作单阈值分割的推广,前面讨论的大部分阈值化技术,诸如Otsu的最大类间方差法, Kapur的最大熵方法、矩量保持法和最小误差法等等都可以推广到多阈值的情形。以下介绍另外几种多阈值方法。
5.2.1 基于小波的多域值方法。
小波变换的多分辨率分析能力也可以用于直方图分析[36],一种基于直方图分析的多阈值选取方法思路如下:首先在粗分辨率下,根据直方图中独立峰的个数确定分割区域的类数,这里要求独立峰应该满足三个条件:(1)具有一定的灰度范围;(2)具有一定的峰下面积;(3)具有一定的峰谷差。然后,在相邻峰之间确定最佳阈值,这一步可以利用多分辨的层次结构进行。首先在最低分辨率一层进行,然后逐渐向高层推进,直到最高分辨率。可以基于最小距离判据对在最低层选取的所有阈值逐层跟踪,最后以最高分辨率层的阈值为最佳阈值。
5.2.2 基于边界点的递归多域值方法。
这是一种递归的多阈值方法。首先,将象素点分为边界点和非边界点两类,边界点再根据它们的邻域的亮度分为较亮的边界点和较暗的边界点两类,然后用这两类边界点分别作直方图,取两个直方图中的最高峰多对应的灰度级作为阈值。接下去,再分别对灰度级高于和低于此阈值的像素点递归的使用这一方法,直至得到预定的阈值数。


5.2.3 均衡对比度递归多域值方法。
首先,对每一个可能阈值计算它对应于它的平均对比度
                                         
其中, 是阈值为 时图像总的对比度, 是阈值 检测到的边界点的数目。然后,选择 的直方图上的峰值所对应的灰度级为最佳阈值。对于多阈值情形,首先用这种方法确定一个初始阈值,接着,去掉初始阈值检测到的边界点的贡献再做一次 的直方图,并依据新的直方图选择下一个阈值。这一过程可以这样一直进行下去,直到任何阈值的最大平均对比度小于某个给定的限制为止。


6 阈值化算法评价简介
尽管人们在图像分割方面做了许多研究工作,但由于尚无通用的分割理论,现已提出的分割算法大都是针对具体问题的,并没有一种适合于所有图像的通用的分割算法。另一方面,给定一个实际图像分割问题要选择合用的分割算法也还没有标准的方法。为解决这些问题需要研究对图像分割的评价问题。分割评价是改进和提高现有算法性能、改善分割质量和指导新算法研究的重要手段。
 然而,如同所有的图像分割方法一样,阈值化结果的评价是一个比较困难的问题。事实上对图像分割本身还缺乏比较系统的精确的研究,因此对其评价则更差一些。人们先后已经提出了几十个评价准则。这些准则中又有定性的,也有定量的;有分析算法的,也有检测实验结果的,文献[37]将它们大致分为13类。
文献[4] 中选择摄影师、建筑物和模特三幅图像作为标准图像,并采用趋于一致性度量和形状参数对几种常用的全局阈值方法的分割结果进行了评价。结果表明对于这三幅图像,如果希望得到的二值图像比较均匀且目标的形状较好,推荐使用最大熵方法、矩量保持方法和最大类间方差法。
文献[38] 中以磁盘及鹤模型作标准图像,在噪声条件下用错分概率、形状和均匀性度量作为标准评估了五种常见的整体阈值选取方法的性能。这五种方法是四元树方法、矩量保持法、最大类间方差法、最大熵方法和简单统计法。结果表明各种方法的性能不仅与所处理的图像有关,而且也和所选用的准则有关。该文献也指出,对于一般实时应用来说,可以选择最大类间方差方法和简单统计法。
最后,评价的目的是为了能指导、改进和提高分割,如何把评价和分割应用联系起来尚有许多工作要做。一个可能的方法是结合人工智能技术,建立分割专家系统[45],以有效的利用评价结果进行归纳推理,从而把对图像的分割由目前比较盲目的试验阶段推进到系统地实现的阶段。
2018-12-02 10:55:25 shanwenkang 阅读数 3274

阈值

我们将图像分块最简单的方法就是设定一个阈值对图像进行二值化处理,那么这个阈值我们应该如何选择呢

对于图像的直方图存在明显边界的图像,我们可以很容易找到这个阈值,但是如果图像直方图分界不明显,那么这个阈值的寻找将变得十分困难。因此我们存在全局阈值与局部阈值两种

全局阈值

全局阈值就是在整幅图像中我们只有一个阈值来对图像进行二值化,但是其存在其局限性,例如图像中存在高斯噪声的情况下,我们无法找到一个很好的阈值将图像的边界分开

另外如果图像的边界是在局部对比下出现的,即不同位置阈值不同,那么全局阈值的效果也非常不好

我们先不管全局阈值的缺点,我们来看看我们如何通过计算来获得这个全局阈值T呢?我们又OTSU'S算法

下面是一些数学概念在图像上的体现

OTSU算法就是想把图像分为两个块,然后使得这两个块之间的方差最大,也就是最大化两个块的均值与全局均值的差的平方

由于只存在这么一个阈值,那么我们在计算的时候可以简单地让这个值遍历0-255,然后找到σB最大的值,这个值就是我们要的阈值。我们可以理解为这个值把图像分为了相距最远的两块。我们在matlab中有graythresh这个函数来实现这个过程

下图就显示了一个OTSU算法不是很理想的例子

为了克服以上缺点我们有两点解决方法:1.先通过低通滤波器去噪再用OTSU 2.只在考虑边缘部分的像素来计算阈值,这样可以大大减少其他不重要部分对阈值计算过程的影响

局部阈值

下面让我们来看看局部阈值/自适应阈值。它的原理就是将图像分块,对于不同的部分应用不同的阈值,在matlab中我们有blockproc这个函数来实现这个过程

我们看到相比于之前,效果确实有很大的提升,但是缺点也特别明显,就是图像会出现分块化

我们可以调小块的大小,但是这样的话会出现如果块内像素值变化不大的话,块内像素被全部分作黑或白而缺失了边界(例如右上角窗户的上方黑色的窗框内有白色的像素块)。因此块的选择是十分重要的

更好的方式是我们在每个像素周围的一个区域内来计算阈值,根据这个块内的均值方差来计算这个像素的值是1还是0

RGB图阈值

除了将阈值在灰度图上应用,我们还可以将其应用在RGB图中,我们可以设定一种颜色,来得到与这种颜色相近颜色的物体

例如我们取下图丝带的颜色可以得到如右图的结果

 

 

2018-12-23 13:18:06 lx_xin 阅读数 1980

基本概念

图像阈值分割是图像处理中最基本也是最常用的方法之一,主要用于将图像中的像素点划分为两个或者多个类别,从而得到便于处理的目标对象。

类别划分

按照阈值作用范围分:全局阈值分割,局部阈值分割;
按照阈值选取准则函数分:最大熵法,类间方差法,交叉熵法,最小误差法,模糊熵法;
按照阈值个数分:单阈值法和多阈值法;

2019-01-07 10:21:04 u010608296 阅读数 10582

数字图像处理中常用图像分割算法有哪些?

1.多数的图像分割算法

2.图像边缘分割

3.图像阈值分割

4.基于区域的分割

5.形态学分水岭算法

多数的图像分割算法 均是基于灰度值的不连续相似的性质。在前者中,算法以灰度突变为基础分割一幅图像,如图像边缘分割。假设图像不同区域的边界彼此完全不同,且与背景不同,从而允许基于灰度的局部不连续性来进行边界检测。后者是根据一组预定义的准则将一幅图像分割为相似区域,如阈值处理、区域生长、区域分裂区域聚合都是基于这种方法形成的。下面将对每类算法进行详细说明。

 

图像边缘分割:边缘是图像中灰度突变像素的集合,一般用微分进行检测。基本的边缘检测算法有:Roberts算子、Prewitt算子、Sobel算子。稍高级的算法有:Marr-Hilderth边缘检测器、Canny边缘检测器。

图像阈值分割:由于阈值处理直观、实现简单且计算速度快,因此阈值处理在分割应用中处于核心地位。阈值处理可以分为单阈值处理与多阈值处理。在单阈值处理中最常用且分割效果也不错的算法是Otsu(最大类间方差算法)算法。多阈值处理:K类由K-1个阈值来分离,即计算图像的多个类间方差,多阈值处理的分割结果相较于单阈值的结果虽然会更好一些,但分类数量增加时它会开始失去意义,因为我们仅仅处理一个变量(灰度),此时可以通过增加变量如彩色来进行解决。

基于区域的分割:区域生长算法和区域分裂与聚合都是属于基于区域的分割算法。

区域生长算法是根据预先定义的生长准则将像素或子区域组合为更大的区域的过程。

基本方法是从一组“种子”点开始,将与种子预先定义的性质相似的那些邻域像素添加到每个种子上来形成这些生长区域(如特定范围的灰度或颜色)。区域分裂与聚合是首先将一幅图像细分为一组任意的不相交区域,然后按照一定规则聚合、分裂这些区域。

形态学分水岭算法:分水岭的概念是以三维形象化一幅图像为基础的。

在图中,我们主要考虑三种类型的点:

(1)属于一个区域最小值的点;

(2)把一点看成是一个水滴,如果把这些点放在任意位置上,水滴一定会下落到一个单一的最小值点;

(3)处在该点的水会等可能性地流向不止一个这样的最小值点。

对于一个特定的区域最小值,满足条件(2)的点的集合称为该最小值的汇水盆地分水岭

满足条件(3)的点形成地表面的峰线,称之为分割线分水线

为了达到更好的分割效果,常常将分水岭算法应用到梯度图像上,而不是图像本身。

 

(二)

个人认为图像分割的算法可以从分割目标入手:通常是要将图像分成目标区域和背景。

需要从图像的特征入手,以灰度图像为例(其余类型的图像处理均类似),图像图形很明显的特征有:

图像灰度值特征、目标边界特征、纹理特征、形态学特征等等;

还有一些基于这些特征所计算提取出的特征,比如信息熵、能量泛函等等。

最为简单的就是灰度值特征了,一幅图中有时候目标区域与背景区域有很明显的亮度区别,基于这个认识,只要试图找到某个亮度的值,我们假设低于该值的认为是背景,高于该值的认为是目标。关于找这个值的算法就是阈值分割算法了,像OTSU、迭代法、最大熵法等等都是属于这一范畴。

同时也可以注意到,在空域内,目标的边界是区分目标与背景的重要依据,因此区分边界也是一个重要的手段,通常边界点周围灰度值变化率很高,因此可以基于图像灰度梯度来识别。这就有一些sobel算子、canny算子等等方式,都是通过找到边界来确定目标区域背景的。

在有些图像中,目标区域具有一定的连续性,基于区域连续性的一些方法像区域生长法、分水岭算法等(本人对这一块不是很熟悉)。

另外,基于图像原始的特征进行提取获得“精炼”的二级特征,并据此分割也是一种好的方法。像SNAKE算法,该算法认为目标区域的边界是“外力”,内力共同作用的结果,因此当外力内力平衡时找到边界,基于这种平衡,提出了判断能量泛函最小的判断原则。此外,还有基于几何活动轮廓模型的水平集方法,该方法是借助于目标区域的几何度量参数,可以比较好的处理一些拓扑变化。

除去经典的阈值分水岭分割算法外,有主动轮廓及衍生的水平集,图割及相关算法(例如GrabCut),交互式分割,以及Cosegmentation。

所有分割算法的核心目的是解决目标区域语义合并难题。例如交互式分割,通过精准交互来解决该问题。Cosegmentation通过分割相同或相似目标来处理该问题。

(三)

(1)基于阈值的分割方法:可在各种颜色空间或不同通道中完成阈值、自适应阈值、

(2)基于边缘的分割方法:各种边缘检测算子

(3)基于区域的分割方法:分水岭、区域归并与分裂

(4)图割分割:最大流(最小割)算法

(5)基于深度信息的分割

(6)基于先验信息的分割

 

基于特定理论的分割方法等。

特定理论大概有:聚类分析、模糊集理论、基因编码、小波变换等。