【第二部分 图像处理】第3章 Opencv图像处理进阶【5图像分割】

5.1图像分割概述

图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像索赋予相同的编号。
图像分割是图像识别和计算机视觉至关重要的预处理。没有正确的分割就不可能有正确的识别。但是,进行分割仅有的依据是图像中像素的亮度及颜色,由计算机自动处理分割时,将会遇到各种困难。例如,光照不均匀、噪声的影响、图像中存在不清晰的部分,以及阴影等,常常发生分割错误。因此图像分割是需要进一步研究的技术。人们希望引入一些人为的知识导向和人工智能的方法,用于纠正某些分割中的错误,是很有前途的方法,但是这又增加了解决问题的复杂性。
图像分割算法从大的方面讲可以分为两类:
 全自动图像分割:一般采用聚类算法来最大化前景与背景的差。
 用户互动式图像分割:用户提供前景和背景的种子,然后对前景背景建立概率分布模型。

5.2图像分割方法

5.2.1阈值分割

图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
图像阈值化的目的是要按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,各个区域内部具有一致的属性,而相邻区域不具有这种一致属性。这样的划分可以通过从灰度级出发选取一个或多个阈值来实现。
阈值分割的优点是计算简单、运算效率较高、速度快。在重视运算效率的应用场合(如用于硬件实现),它得到了广泛应用。人们发展了各种各样的阈值处理技术,包括全局阈值、自适应阈值、最佳阈值等等。
 基本原理
基本原理是:通过设定不同的特征阈值,把图像象素点分为若干类。
常用的特征包括:直接来自原始图像的灰度或彩色特征;由原始灰度或彩色值变换得到的特征。设原始图像为 fx,y f ( x , y ) ,按照一定的准则 f(x,y) f ( x , y ) 中找到特征值T,将图像分割为两个部分,分割后的图像为:若取: b0=0 b 0 = 0 (黑), b1=1 b 1 = 1 (白),即为我们通常所说的图像二值化。
 方法
阈值分割方法实际上是输入图像 到输出图像 的如下变换:
这里写图片描述
其中,T为阈值,对于物体的图像元素 g(i,j)=1 g ( i , j ) = 1 ,对于背景的图像元素 g(i,j)=0 g ( i , j ) = 0
由此可见,阈值分割算法的关键是确定阈值,如果能确定一个合适的阈值就可准确地将图像分割开来。阈值确定后,将阈值与像素点的灰度值逐个进行比较,而且像素分割可对各像素并行地进行,分割的结果直接给出图像区域。
关于阈值分割请参考笔者的另外的文章。

阈值化

5.2.2区域分割

区域分割是讲图像按照相似性准则分成不同的区域,主要包括区域增长,区域分裂合并和分水岭等几种类型。
 区域生长
区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于初始点(种子点)的选取,生长准则,终止条件。区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取。
区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当作新的种子像素继续进行上面的过程,直到再没有满足条件的像素可被包括进来。这样一个区域就长成了。
区域生长需要选择一组能正确代表所需区域的种子像素,确定在生长过程中的相似性准则,制定让生长停止的条件或准则。相似性准则可以是灰度级、彩色、纹理、梯度等特性。选取的种子像素可以是单个像素,也可以是包含若干个像素的小区域。大部分区域生长准则使用图像的局部性质。生长准则可根据不同原则制定,而使用不同的生长准则会影响区域生长的过程。
 区域分裂合并
区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标提取。分裂合并差不多是区域生长的逆过程:从整个图像出发,不断分裂得到各个子区域,然后再把前景区域合并,实现目标提取。分裂合并的假设是对于一幅图像,前景区域由一些相互连通的像素组成的,因此,如果把一幅图像分裂到像素级,那么就可以判定该像素是否为前景像素。当所有像素点或者子区域完成判断以后,把前景区域或者像素合并就可得到前景目标。
在这类方法中,最常用的方法是四叉树分解法。设R代表整个正方形图像区域,P代表逻辑谓词。基本分裂合并算法步骤如下:
(1)对任一个区域,如果H(Ri)=FALSE就将其分裂成不重叠的四等份;
(2)对相邻的两个区域Ri和Rj,它们也可以大小不同(即不在同一层),如果条件H(Ri∪Rj)=TRUE满足,就将它们合并起来。
(3)如果进一步的分裂或合并都不可能,则结束。
分裂合并法的关键是分裂合并准则的设计。这种方法对复杂图像的分割效果较好,但算法较复杂,计算量大,分裂还可能破坏区域的边界。
 分水岭分割
分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
关于分水岭分割请参看笔者的另一篇博文。
分水岭算法

5.2.3边缘分割

图像分割的一种重要途径是通过边缘检测,即检测灰度级或者结构具有突变的地方,表明一个区域的终结,也是另一个区域开始的地方。这种不连续性称为边缘。不同的图像灰度不同,边界处一般有明显的边缘,利用此特征可以分割图像。
图像中边缘处像素的灰度值不连续,这种不连续性可通过求导数来检测到。对于阶跃状边缘,其位置对应一阶导数的极值点,对应二阶导数的过零点(零交叉点)。因此常用微分算子进行边缘检测。常用的一阶微分算子有Roberts算子、Prewitt算子和Sobel算子,二阶微分算子有Laplace算子和Kirsh算子等。在实际中各种微分算子常用小区域模板来表示,微分运算是利用模板和图像卷积来实现。这些算子对噪声敏感,只适合于噪声较小不太复杂的图像。
由于边缘和噪声都是灰度不连续点,在频域均为高频分量,直接采用微分运算难以克服噪声的影响。因此用微分算子检测边缘前要对图像进行平滑滤波。LoG算子和Canny算子是具有平滑功能的二阶和一阶微分算子,边缘检测效果较好,
 步骤
第一步:滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数的计算对噪声很敏感,因此必须使用滤波器来改善与噪声有关的边缘检测器的性能.需要指出,大多数滤波器在降低噪声的同时也导致了边缘强度的损失,因此,增强边缘和降低噪声之间需要折衷.
第二步:增强:增强边缘的基础是确定图像各点邻域强度的变化值.增强算法可以将邻域(或局部)强度值有显著变化的点突显出来.边缘增强一般是通过计算梯度幅值来完成的.
第三步:检测:在图像中有许多点的梯度幅值比较大,而这些点在特定的应用领域中并不都是边缘,所以应该用某种方法来确定哪些点是边缘点.最简单的边缘检测判据是梯度幅值阈值判据.
第四步:定位:如果某一应用场合要求确定边缘位置,则边缘的位置可在子像素分辨率上来估计,边缘的方位也可以被估计出来.
在边缘检测算法中,前三个步骤用得十分普遍。这是因为大多数场合下,仅仅需要边缘检测器指出边缘出现在图像某一像素点的附近,而没有必要指出边缘的精确位置或方向.边缘检测误差通常是指边缘误分类误差,即把假边缘判别成边缘而保留,而把真边缘判别成假边缘而去掉.边缘估计误差是用概率统计模型来描述边缘的位置和方向误差的.我们将边缘检测误差和边缘估计误差区分开,是因为它们的计算方法完全不同,其误差模型也完全不同。
关于边缘分割请参考笔者的另一篇文章。
边缘检测

5.2.4图论分割

此类方法把图像分割问题与图的最小割(min cut)问题相关联。首先将图像映射为带权无向图G=

5.2.4.1 grabCut()函数

 grabCut()函数讲解

C++:void grabCut( InputArray img, 
                  InputOutputArray mask, 
                  Rect rect,
                  InputOutputArray bgdModel, 
                  InputOutputArray fgdModel,
                  int iterCount, 
                  int mode = GC_EVAL );

【参数】
第一个参数,img,待分割的源图像,必须是8位3通道(CV_8UC3)图像,在处理的过程中不会被修改;
第二个参数,mask,掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:
GCD_BGD(=0),背景;
GCD_FGD(=1),前景;
GCD_PR_BGD(=2),可能的背景;
GCD_PR_FGD(=3),可能的前景。
如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGD或GCD_PR_FGD;
第三个参数,rect用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
第四个参数,bgdModel,背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
第五个参数,fgdModel,前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
第六个参数, iterCount,迭代次数,必须大于0;
第七个参数, mode,用于指示grabCut函数进行什么操作,可选的值有:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
GC_EVAL(=2),执行分割。

 grabCut()函数源代码

/*【grabCut( )源代码】*************************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)  
 * @源码路径:…\opencv\sources\modules\imgproc\src\ grabcut.cpp
 * @起始行数:528行   
********************************************************************************/
void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect,
                  InputOutputArray _bgdModel, InputOutputArray _fgdModel,
                  int iterCount, int mode )
{
    Mat img = _img.getMat();
    Mat& mask = _mask.getMatRef();
    Mat& bgdModel = _bgdModel.getMatRef();
    Mat& fgdModel = _fgdModel.getMatRef();

    if( img.empty() )
        CV_Error( CV_StsBadArg, "image is empty" );
    if( img.type() != CV_8UC3 )
        CV_Error( CV_StsBadArg, "image mush have CV_8UC3 type" );

    GMM bgdGMM( bgdModel ), fgdGMM( fgdModel );
    Mat compIdxs( img.size(), CV_32SC1 );

    if( mode == GC_INIT_WITH_RECT || mode == GC_INIT_WITH_MASK )
    {
        if( mode == GC_INIT_WITH_RECT )
            initMaskWithRect( mask, img.size(), rect );
        else // flag == GC_INIT_WITH_MASK
            checkMask( img, mask );
        initGMMs( img, mask, bgdGMM, fgdGMM );
    }

    if( iterCount <= 0)
        return;

    if( mode == GC_EVAL )
        checkMask( img, mask );

    const double gamma = 50;
    const double lambda = 9*gamma;
    const double beta = calcBeta( img );

    Mat leftW, upleftW, upW, uprightW;
    calcNWeights( img, leftW, upleftW, upW, uprightW, beta, gamma );

    for( int i = 0; i < iterCount; i++ )
    {
        GCGraph<double> graph;
        assignGMMsComponents( img, mask, bgdGMM, fgdGMM, compIdxs );
        learnGMMs( img, mask, compIdxs, bgdGMM, fgdGMM );
        constructGCGraph(img, mask, bgdGMM, fgdGMM, lambda, leftW, upleftW, upW, uprightW, graph );
        estimateSegmentation( graph, mask );
    }
}
5.2.4.2 grabCut实例

参考附件【demo1】

这里写图片描述

图1

5.2.5能量泛函分割

基于能量泛函的分割方法主要指的是活动轮廓模型(active contour model)以及在其基础上发展出来的算法,其基本思想是使用连续曲线来表达目标边缘,并定义一个能量泛函使得其自变量包括边缘曲线,因此分割过程就转变为求解能量泛函的最小值的过程,一般可通过求解函数对应的欧拉(Euler.Lagrange)方程来实现,能量达到最小时的曲线位置就是目标的轮廓所在。按照模型中曲线表达形式的不同,活动轮廓模型可以分为两大类:参数活动轮廓模型(parametric active contour model)和几何活动轮廓模型(geometric active contour model)。
参数活动轮廓模型是基于Lagrange框架,直接以曲线的参数化形式来表达曲线,最具代表性的是由Kasset a1(1987)所提出的Snake模型。该类模型在早期的生物图像分割领域得到了成功的应用,但其存在着分割结果受初始轮廓的设置影响较大以及难以处理曲线拓扑结构变化等缺点,此外其能量泛函只依赖于曲线参数的选择,与物体的几何形状无关,这也限制了其进一步的应用。
几何活动轮廓模型的曲线运动过程是基于曲线的几何度量参数而非曲线的表达参数,因此可以较好地处理拓扑结构的变化,并可以解决参数活动轮廓模型难以解决的问题。而水平集(Level Set)方法(Osher,1988)的引入,则极大地推动了几何活动轮廓模型的发展,因此几何活动轮廓模型一般也可被称为水平集方法。

5.2.6直方图分割

与其他图像分割方法相比,基于直方图的方法是非常有效的图像分割方法,因为他们通常只需要一个通过像素。在这种方法中,直方图是从图像中的像素的计算,并在直方图的波峰和波谷是用于定位图像中的簇。颜色和强度可以作为衡量。
这种技术的一种改进是递归应用直方图求法的集群中的形象以分成更小的簇。重复此操作,使用更小的簇直到没有更多的集群的形成。
基于直方图的方法也能很快适应于多个帧,同时保持他们的单通效率。直方图可以在多个帧被考虑的时候采取多种方式。同样的方法是采取一个框架可以应用到多个,和之后的结果合并,山峰和山谷在以前很难识别,但现在更容易区分。直方图也可以应用于每一个像素的基础上,将得到的信息被用来确定的像素点的位置最常见的颜色。这种方法部分基于主动对象和一个静态的环境,导致在不同类型的视频分割提供跟踪。
对于直方图分割方法,也可以归结为基于阈值的分割方法。关于直方图更多相关知识请参考笔者的一些列文章。
直方图A
直方图B
直方图C
直方图D

5.2.7其他分割方法

随着人工智能的不断发展,最近的分割方法及本都是基于深度学习的方法,主要有DeepMask,FCN,FCN+CRF,SSD,Deeplib等以深度学习为基础的算法为主流。
值得注意的是,如果是要做专有的图像分割,这类算法使用前要稍微慎重些。主要原因就是这些算法都需要大量标注样本的支持。
由于笔着水平有限,而且该专栏是基于OpenCV的讲解,其他分割方法请感兴趣的朋友自行学习吧!

本章参考附件

点击进入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruceoxl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值