基于图像的灰度特征来计算一个或多个灰度阈值,并将图像中每个像素的灰度值与阈值相比较,根据比较结果把像素分到合适的类别中。该类方法的关键是按照某个准则函数来求解最佳灰度阈值。
Otsu(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。所以可以在二值化的时候采用ostsu算法来自动选取阈值进行二值化。Otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。
边缘是图像中两个不同区域的边界线上连续的像素点的集合,是图像局部特征不连续性的反映,体现了灰度、颜色、纹理等图像特性的突变。基于边缘的分割方法是基于灰度值的边缘检测,建立在边缘灰度值会呈现出阶跃型或屋顶型变化这一观测基础上的方法。阶跃型边缘两边像素点的灰度值存在着明显的差异,而屋顶型边缘则位于灰度值上升或下降的转折处。可以使用微分算子进行边缘检测,使用一阶导数的极值与二阶导数的过零点来确定边缘,具体实现可以使用图像与模板进行卷积来完成。
按照图像相似性准则分成不同的区域,主要 包括种子区域生长法、区域分裂合并法和分水岭法等几种类型。
种子区域生长法是从一组代表 不同生长区域的种子像素开始,将种子像素邻域里符合条件的像素合并到种子像素所代表的生长区域中,并将新添加的像素作为新的种子像素继续合并过程,直到找到符合条件的新像素为止。该方法的关键是选择合适的初始种子像素以及合理的生长准则。
区域分裂合并法的基本思想是首先将图像任意分成若干互不相交的区域,然后再按照相关准则对这些区域进行分裂或者合并从而完成分割任务。该方法既适用于灰度图像分割也适用于纹理图像分割。
分水岭法是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。该算法的实现可以模拟成洪水淹没的过程,图像的最低点首先被淹没,然后水逐渐淹没整个山谷。当水位到达一定高度的时候将会溢出,这时在水溢出的地方修建堤坝,重复这个过程直到整个图像上的点全部被淹没,这时所建立的一系列堤坝就成为分开各个盆地的分水岭。分水岭算法对微弱的边缘有着良好的响应,但图像中的噪声会使分水岭算法产生过分割的现象。
把图像分割问题与图的最小分割问题相关联。首先将图像映射为带权无向图 G = < V , E > G=<V,E> G=<V,E>,图中每个节点 N ∈ V N \in V N∈V对应于图像中的每个像素,每条边 ∈ E \in E ∈E连接着一对相邻的像素,边的权值表示了相邻像素之间在灰度、颜色或纹理方面的非负相似度。对图像的一个分割 S S S就对应图的一个剪切,被分割的每个区域 C ∈ S C \in S C∈S对应这图中的一个子图。而分割的最优原则就是使划分后的子图在内部保持相似度最大,而子图之间的相似度保持最小。基于图论的分割方法的本质就是移除特定的边,将图划分为若干子图从而实现分割。基于图论的方法有GraphCut、GrabCut和Random Walk等。
初始化一个聚类,使用迭代的方式将颜色、亮度、纹理等特征相似的像素点聚类到同一超像素,迭代直至收敛,从而得到最终的图像分割结果。基于像素聚类的代表方法有K-menas(K均值)、谱聚类、Meanshift和SLIC等。
基于能量泛函的分割方法主要指的是活动轮廓模型(active contour model)以及在其基础上发展出来的算法,其基本思想是使用连续曲线来表达目标边缘,并定义一个能量泛函使得其自变量包括边缘曲线,因此分割过程就转变为求解能量泛函的最小值的过程,一般可通过求解函数对应的欧拉(Euler.Lagrange)方程来实现,能量达到最小时的曲线位置就是目标的轮廓所在。
主动轮廓线模型是一个自顶向下定位图像特征的机制,通过事先在感兴趣目标附近放置一个初始轮廓线,在内部能量(内力)和外部能量(外力)的作用下变形,外部能量吸引活动轮廓朝物体边缘运动,而内部能量保持活动轮廓的光滑性和拓扑性,当能量达到最小时,活动轮廓收敛到所要检测的物体边缘。
按照模型中曲线表达形式的不同,活动轮廓模型可以分为两大类:参数活动轮廓模型(parametric active contour model)和几何活动轮廓模型(geometric active contour model)。
参数活动轮廓模型是基于lagrange框架,直接以曲线的参数化形式来表达曲线,如snake模型,该类模型分割结果受初始轮廓的设置影响较大,难以处理曲线拓扑结构变化等缺点,此外其能量泛函只依赖于曲线参数的选择,与物体的几何形状无关。
几何活动轮廓模型的曲线运动过程是基于曲线的几何度量参数而非曲线的表达参数,因此可以较好的处理拓扑结构的变化,如水平集方法。
曲线存在曲率,曲率有正负,在法向曲率力的推动下,曲线的运动方向之间有所不同:有些部分朝外扩展,而有些部分朝内运动。简单曲线在曲率力(也就是曲线的二次导数)的驱动下演化所具有的一种非常特殊的数学性质:一切简单曲线,无论被扭曲的多么严重,只要还是一种简单曲线,那么在曲率力的推动下最终将退化成一个圆,然后消逝(圆的所有点的曲率力都向着圆心,所以它将慢慢缩小,以致最后消逝)。
描述曲线几何特征的两个重要参数是单位法向量和曲率,单位法向量描述曲线的方向,曲率则表述曲线弯曲的程度。曲线演化理论就是利用曲线的单位法向量和曲率等几何参数来研究曲线随时间的变形。曲线的演变过程可以认为是表述曲线在作用力 F F F的驱动下,朝法向量方向 N N N以速度 v v v演化。如果速度 v v v为负,表示活动轮廓演化过程是朝外部方向的,如果为正,则表示朝内部方向演化,活动曲线是单方向演化的,不可能同时往两个方向演化。
所以曲线的演变过程,就是不同力在曲线上的作用过程,力也可以表达为能量。世界万物都趋向于能量最小而存在。在图像分割里面,在目标轮廓这个地方,整个轮廓的能量是最小的,那么曲线在图像任何一个地方,都可以因为力朝着这个能量最小的轮廓演变,当演变到目标轮廓的时候,因为能量最小,力平衡了,速度为0了,也就不动了,这时候目标就被分割出来了。
snake方法是基于能量泛函的方法,核心思想就是,在感兴趣区域的附近给出一条初始曲线,在曲线固有内力(控制曲线的弯曲和拉伸)和图像外力(控制收敛到局部特征)的作用下收敛到目标的边界轮廓。但是snake方法需要将曲线进行参数化,这是个非常困难的问题,而且它还不能处理曲线的拓扑变换。
简单的来讲,snake模型就是一条可变形的参数曲线及相应的能量函数,以最小化能量目标函数为目标,控制参数曲线变形,具有最小能量的闭合曲线就是目标轮廓。
构造snake模型是为了调和上层知识和底层图像特征这一矛盾。无论是亮度、梯度、角点、纹理还是光流,所有的图像特征都是局部的。所谓局部性就是指图像上某一点的特征只取决于这一点所在的邻域,而与物体的形状无关。但是人们对物体的认识主要是来自于其外形轮廓。如何将两者有效的融合在一起是snake模型的长处。snake模型的轮廓线承载了上层知识,而轮廓线与图像的匹配又融合了底层特征。这两项分别表示为snake模型中能量函数的内部力和图像力。
模型的形变受到同时作用在模型上的许多不同的力所控制,每一种力所产生一部分能量,这部分能量表示为活动轮廓模型的能量函数的一个独立的能量项。
用Level Set来表示Snakes,想法很简单:一个平面上的曲线可以表示成一个二元函数 z = f ( x , y ) z=f(x,y) z=f(x,y)的零点集合(Zero Level Set),集这个二元函数 z = f ( x , y ) z=f(x,y) z=f(x,y)所表示的三维曲面与 x y xy xy平面的交线。更一般的,任何 N N N维曲面都可以表示为一个 N + 1 N+1 N+1维曲面与一个 N N N维超平面的交集,或称为 N + 1 N+1 N+1维曲面在 N N N维超平面上的投影。相对最早的Snake(用参数化的曲线,所以也叫parametric active contour),用level set表示的活动曲线叫Geometric Active Contours。
用二维曲面与二维平面的交线表示曲线,当描述曲线运动的时候,用level set表示曲线就有很明显的优势,例如:几条曲线在运动中merge成一条曲线,或者一条曲线分裂成几条曲线,这样的拓扑变化是不可能表示成一条连续的参数化曲线的运动。原因很简单,一条连续的参数化曲线是用一个一元连续函数来表示的,它显然不能表示几条分开的曲线(这与连续性矛盾)。
水平集(LevelSet)是一种基于能量泛函的图像分割算法,即把图像分割的问题,转换为最小化一个能量函数的问题。主要应用于医学图像分割。
水平集算法的核心思想是将要研究的问题,看做是更高一维空间的函数(也就是水平集函数)的零水平集。因此,研究某一曲线(曲面)的演化过程,实际上就等于研究更高一维曲面的演化过程。
如上图所示,对红色曲线建立一个随时间而变换的模型,是很困难的,因为发生了拓扑结构变化(一条曲线变成了两条),但是如果只是对蓝色的曲面建立随时间变化的过程,则是可行的,而红色曲线就是取其 Z = 0 Z=0 Z=0的水平集。这就是隐函数的思想,当无法显示写出x为自变量的函数 y,但是可以得到y和x的某种关系时,就能通过另外一种方法来表达。
假设曲线为 C C C,它是随时间变化的,那么曲面(也就是水平集函数)的描述式如下:
φ ( C ( t ) , t ) = 0 \varphi(C(t),t)=0 φ(C(t),t)=0
偏微分求解后就是一个如下的式子:
∂ φ ∂ t = F ∣ ▽ φ ∣ \frac{\partial \varphi}{\partial t}=F|\bigtriangledown \varphi| ∂t∂φ=F∣▽φ∣
给 φ \varphi φ一个初始值,它就可以在 F F F的作用下进行演化,然后令其等于0,就得到了 C C C。所以最关键的问题是求取 F F F,也就是演化函数,这就是水平集方法的核心思想。
Active Contours Without Edges是一种基于曲线演化,Mumford-Shah函数和水平集的新的活动轮廓模型来检测图像中的目标。无论边界是否由梯度定义,模型均可检测目标。最小化能量函数可以作为最小化问题的一种特例。在水平集方程中,最小化问题则变为平均曲率流问题,就像活动轮廓的演化一样,可以在所需要的边界停止演化。但是停止的条件不像经典的活动轮廓模型一样依赖与图像的梯度,而是与相关的分割参数有关。
假定给定一张特殊图片 u 0 u_{0} u0,这张图片由两块区域构成,区域一所有的像素点取值都为 u 0 i u_{0}^{i} u0i,区域二中所有的像素点取值都为 u 0 o u_{0}^{o} u0o。现在希望得到区域一的轮廓。考虑控制着曲线最终拟合至物体边缘停止的fitting项。
F ( C ) = ∫ i n s i d e ( C ) ∣ u 0 ( x , y ) − c 1 ∣ 2 d x d y + ∫ o u t s i d e ( C ) ∣ u 0 ( x , y ) − c 2 ∣ 2 d x d y F(C) = \int _{inside(C)}|u_{0}(x,y)-c_{1}|^{2}dxdy+\int_{outside(C)}|u_{0}(x,y)-c_{2}|^{2dxdy} F(C)=∫inside(C)∣u0(x,y)−c1∣2dxdy+∫outside(C)∣u0(x,y)−c2∣2dxdy
其中常数 c 1 c_{1} c1和 c 2 c_{2} c2分别是曲线 C C C内部像素点的均值和 C C C外部像素点的均值。对于该特殊图片 u 0 u_{0} u0,使得这个能量函数值最小的曲线 C C C就是希望得到的区域一的轮廓,此时能量值为0(可以验证曲线 C C C不是区域一轮廓的其他几种情况,对应的能量值都大于0)。作者提出的模型就是上面的能量函数,另外还加上了曲线的长度、曲线的内区域的面积等正则项:
F ( C ) = μ ⋅ L e n g t h ( C ) + ν ⋅ A r e a ( i n s i d e ( C ) ) + λ 1 ∫ i n s i d e ( C ) ∣ u 0 ( x , y ) − c 1 ∣ 2 d x d y + λ 2 ∫ o u t s i d e ( C ) ∣ u 0 ( x , y ) − c 2 ∣ 2 d x d y \begin{aligned} F(C) =\mu \centerdot Length(C) + \nu \centerdot Area(inside(C)) & +\lambda_{1} \int _{inside(C)}|u_{0}(x,y)-c_{1}|^{2}dxdy \\ & +\lambda_{2} \int_{outside(C)}|u_{0}(x,y)-c_{2}|^{2}dxdy \\ \end{aligned} F(C)=μ⋅Length(C)+ν⋅Area(inside(C))+λ1∫inside(C)∣u0(x,y)−c1∣2dxdy+λ2∫outside(C)∣u0(x,y)−c2∣2dxdy
其中, μ ≥ 0 \mu \geq0 μ≥0, ν ≥ 0 \nu \geq0 ν≥0, λ 1 , λ 2 ≥ 0 \lambda_{1},\lambda_{2} \geq0 λ1,λ2≥0。因为 c 1 c_{1} c1和 c 2 c_{2} c2也是 C C C的函数,所以 F ( c 1 , c 2 , C ) F(c_{1},c_{2},C) F(c1,c2,C)即 F ( C ) F(C) F(C)。
能量函数是Mumford-Shah的特例,因为Mumford-Shah有极小值,所以能量函数也有极小值。
为了求解能量函数的极小值问题,作者把关于曲线 C C C的能量函数写成关于水平集函数 ϕ \phi ϕ的能量函数(函数的函数—泛函),求解水平集函数。
要用 ϕ \phi ϕ替换能量函数中的曲线 C C C,需要引入两个函数,简称为 H H H函数和 D e l t a Delta Delta函数:
H ( z ) = { 1 , z ≥ 0 0 , z < 0 H(z) = \begin{cases} 1, & z \geq 0 \\ 0, & z < 0 \end{cases} H(z)={1,0,z≥0z<0
δ 0 ( z ) = d d z H ( z ) \delta_{0} (z)= \frac{d}{dz}H(z) δ0(z)=dzdH(z)
能量公式重新写成:
F ( c 1 , c 2 , ϕ ) = μ ∫ Ω δ ( ϕ ( x , y ) ) ∣ ▽ ϕ ( x , y ) ∣ d x d y + ν ∫ Ω H ( ϕ ( x , y ) ) d x d y + λ 1 ∫ ∣ u 0 ( x , y ) − c 1 ∣ 2 H ( ϕ ( x , y ) ) d x d y + λ 1 ∫ ∣ u 0 ( x , y ) − c 2 ∣ 2 ( 1 − H ( ϕ ( x , y ) ) ) d x d y \begin{aligned} F(c_{1}, c_{2}, \phi) = \mu \int _{\Omega} \delta(\phi(x,y))|\bigtriangledown \phi(x,y)|dxdy & + \nu \int _{\Omega}H(\phi(x,y))dxdy \\ & + \lambda_{1} \int |u_{0}(x,y)-c_{1}|^{2}H(\phi (x,y))dxdy \\ & + \lambda_{1} \int |u_{0}(x,y)-c_{2}|^{2}(1-H(\phi (x,y)))dxdy \end{aligned} F(c1,c2,ϕ)=μ∫Ωδ(ϕ(x,y))∣▽ϕ(x,y)∣dxdy+ν∫ΩH(ϕ(x,y))dxdy+λ1∫∣u0(x,y)−c1∣2H(ϕ(x,y))dxdy+λ1∫∣u0(x,y)−c2∣2(1−H(ϕ(x,y)))dxdy
c 1 c_{1} c1和 c 2 c_{2} c2通过 ϕ \phi ϕ求出:
{ c 1 = a v e r a g e ( u 0 ) i n { ϕ ≥ 0 } c 2 = a v e r a g e ( u 0 ) i n { ϕ < 0 } \begin{cases} c_{1} = average(u _{0} ) in \{\phi \geq 0 \} \\ c_{2} = average(u _{0} ) in \{\phi < 0 \} \end{cases} {c1=average(u0)in{ϕ≥0}c2=average(u0)in{ϕ<0}
针对泛函极值问题,可以得到 ϕ \phi ϕ的欧拉-拉格朗日公式,即一个偏微分方程:
∂ ϕ ∂ t = δ ϵ ( ϕ ) [ μ ⋅ d i v ( ▽ ϕ ∣ ▽ ϕ ∣ ) − ν − λ 1 ( u 0 − c 1 ) 2 + λ 2 ( u 0 − c 2 ) 2 ] = 0 \frac{\partial \phi}{\partial t}=\delta_{\epsilon}(\phi)[\mu \centerdot div(\frac{\bigtriangledown \phi}{|\bigtriangledown \phi|})-\nu-\lambda_{1}(u_{0}-c_{1})^{2}+\lambda_{2}(u_{0}-c_{2})^{2}]=0 ∂t∂ϕ=δϵ(ϕ)[μ⋅div(∣▽ϕ∣▽ϕ)−ν−λ1(u0−c1)2+λ2(u0−c2)2]=0
ϕ ( 0 , x , y ) = ϕ 0 ( x , y ) i n Ω \phi(0,x,y)=\phi_{0}(x,y) in \Omega ϕ(0,x,y)=ϕ0(x,y)inΩ
δ ϵ ( ϕ ) ∣ ▽ ϕ ∣ ∂ ϕ ∂ n ⃗ = 0 o n ∂ Ω \frac{\delta_{\epsilon}(\phi)}{|\bigtriangledown \phi|} \frac{\partial \phi}{\partial \vec{n}}=0 on \partial \Omega ∣▽ϕ∣δϵ(ϕ)∂n∂ϕ=0on∂Ω
其中, n ⃗ \vec{n} n是边界 ∂ Ω \partial \Omega ∂Ω的外法线。因为原来的 ∂ δ 0 \partial \delta_{0} ∂δ0基本上处处为0,没办法求欧拉-拉格朗日方程,所以在得到的欧拉-拉格朗日方程中并没有使用上面的 H H H函数以及对应的 D e l t a Delta Delta函数,而使用下面的函数,现在 ∂ δ ∈ \partial \delta_{\in} ∂δ∈的支撑集是整个实数集 R R R,所以不管初始曲线是什么样的,都可以得到全局最优解,还可以检测到内部的轮廓。
H ϵ = 1 2 ( 1 + 2 π a r c t a n ( z ϵ ) ) H_{\epsilon}=\frac{1}{2}(1+\frac{2}{\pi}arctan(\frac{z}{\epsilon})) Hϵ=21(1+π2arctan(ϵz))
δ ϵ = H ϵ ′ = ϵ π 1 z 2 + ϵ 2 \delta_{\epsilon}=H_{\epsilon ^{'}}=\frac{\epsilon}{\pi} \frac{1}{z^{2}+\epsilon^{2}} δϵ=Hϵ′=πϵz2+ϵ21
当 ϵ → 0 \epsilon \rightarrow 0 ϵ→0时,分别收敛到 H H H和 δ 0 \delta_{0} δ0。
经过对偏微分方程离散化,得到水平集函数 ϕ \phi ϕ的迭代形式:
ϕ i , j n + 1 − ϕ i , j n △ t = δ h ( ϕ i , j n ) [ μ c u r v a t u r e i , j − ν − λ 1 ( u 0 , i , j − c 1 ) 2 + λ 2 ( u 0 , i , j − c 2 ) 2 ] \frac{\phi_{i,j}^{n+1}-\phi_{i,j}^{n}}{\bigtriangleup t}=\delta_{h}(\phi_{i,j}^{n})[\mu curvature_{i,j}-\nu -\lambda_{1}(u_{0,i,j}-c_{1})^{2}+\lambda_{2}(u_{0,i,j}-c_{2})^{2}] △tϕi,jn+1−ϕi,jn=δh(ϕi,jn)[μcurvaturei,j−ν−λ1(u0,i,j−c1)2+λ2(u0,i,j−c2)2]
(1)随机初始化 ϕ 0 = ϕ 0 \phi^{0}=\phi_{0} ϕ0=ϕ0, n = 0 n = 0 n=0
(2) 计算两个均值 c 1 c_{1} c1和 c 2 c_{2} c2
(3)根据迭代公式计算 ϕ n + 1 \phi^{n+1} ϕn+1
(4) 重新初始化 ϕ \phi ϕ,这一步可用可以不用
(5)检查是否收敛,收敛则停止,否则跳到步骤(2),直到收敛停止
在实际场景的图片中,一些物体的结构比较复杂,内部差异性较大,仅利用像素点的颜色、亮度、纹理等较低层次的内容信息不足以生成好的分割效果,容易产生错误的分割。因此需要更多的结合图像提供的中高层内容信息辅助图像分割。
根据实际分割应用任务的不同,可以分为三个研究方向:语义分割、实例分割、全景分割。
算法理解:
算法缺点:
SCIKit Image是一个专门用于图像处理的Python包。
pip install scikit-image
from skimage import data
# 灰度图像
image = data.bianry_blobs()
#彩色图像
image = data.astronaut()
from skimage import io
#单张图像
image = io.imread('skimage_logo.png')
#多张图像
images = io.ImageCollection('../images/*.png:../images/*.jpg')
# 读取图像数量
print(len(images))
#显示第一张图像
io.imshow(images[0])
#保存图像
io.imsave('logo.png', images[0])
图像分割本质上是将数字图像分割成多个片段的过程,以简化或将图像的表示方式更改为更有意义和更易于分析的内容。
阈值法分割图像
阈值分割是一种非常基本的分割算法,但是它在高对比图像中效果不是很好,需要采用更加先进的算法。
snake=seg.active_contour(image_gray, points, alpha=0.06,beta=0.3)
alpha和beta可以调整,alpha值越高,轮廓的收缩速度越快,beta越大收缩越慢。image_segmented=seg.random_walker(image_gray, image_labels, beta=3000)
image_slic=seg.slic(image, n_segments=200)
,将图像的每个子图像或子区域像素设置为该区域像素的平均值color.label2rgb(image_slic, image,kind='avg)
image_felzenszwalb=seg.felzenszwalb(image)
,可以通过np.unique(image_felzenszwalb).size
计算相互独立的区域数。使用区域像素平均值对子区域重新着色color.label2rgb(image_felzenszwalb, image, kind='avg')
。计算机视觉之图像分割—水平集方法_ACWE2001
水平集—那些我膜拜过的牛人2
水平集算法原理介绍
Level set method:Explanation
水平集函数演化方程的推导细节
水平集算法总结
图像分割之(一)概述
图像分割之(五)活动轮廓模型之Snake模型简介
基于深度学习的图像分割总结
图像分割(一)——原理概念
图像分割技术介绍
单张图片的无监督语义分割,理解算法,并改良原始代码(从30秒改到5秒)
一文概述Python的scikit-image模块进行图像分割