一、level set相关理论
基于水平集的图像分割算法是一种进化版的Snake算法,也是需要给定初始的轮廓曲线,然后根据泛函能量最小化,进行曲线演化。水平集的方法,用的是一种隐式函数的方法,这个算法比较难理解,我一年前开始搞这个算法的时候,虽然知道代码怎么写,但是它的原理推导完全不懂,因为这个算法比较难理解,所以我这边将讲的稍微详细一点。
跟传统的snake算法相比,思想完全不一样,snake算法曲线演化的时候,是曲线上离散点显示坐标的位置更新移动,只要懂得能量最小化的曲线演化规则,就可以很快理解算法,并写出代码。然而水平集的方法,更新的不是曲线离散点的坐标,而是更新整张图片像素点到曲线的有向距离场。因此算法最关键的是理解这个距离场的更新规则,当然这个更新规则跟能量最小化相关。
开始这个算法之前,我们需要非常熟悉,显式二维的曲线与隐式曲线(水平集函数)的相互转换公式。给定初始的轮廓曲线C,我们怎么把它转换成水平集函数,这个是实现算法的第一步。水平集函数的定义:
公式1:
也就是说,如果给你一条初始封闭轮廓曲线C,进行水平集图像分割,我们需要写的第一个函数就是计算图像的每个像素点p(x,y)到曲线的最短距离d,如果该像素点p位于曲线C的内部,那么有向距离为-d;反之为d。这样遍历图像每个像素点,每个像素点都可以求得对应的有向距离u(x,y)。反过来,如果我已经知道了图像上每个像素点的有向距离u(x,y),那么我要怎么把这个隐式函数转换成显示函数呢?
其实很简单,只要求出满足u(x,y)=0 的像素点,就是曲线上的点,因为如果该像素点到曲线C的最短距离为0,那么这个像素点肯定在这条曲线上,据此我们就可以把所有满足u(x,y)=0的像素点全部提取出来,获得这些像素点的坐标p(x,y),而这些点便是曲线C的离散点,这样就完成了从隐式距离场到显式离散曲线的转换。
据此我们可以得到算法的大体流程:
输入:给定离散的初始轮廓曲线C,待分割图像T
输出:分割结果曲线C’
Algorithm:
Begin:
1、根据公式1,计算每个像素点到离散曲线C的最短有向距离u(x,y)
2、根据图像梯度等信息,对u(x,y)进行演化,使得其沿着能量最小化的方向演化,这个过程说的简单一点,就是更新每个像素点的u(x,y)值。
3、根据第2步的演化结果,遍历每个像素点(x,y),判断其水平集函数值是否为零。
If u(x,y)==0:
保存像素点坐标(x,y)(因为这个点就是曲线C’上的点)
得到所有u(x,y)==0的点,就是最后我们想要的图像分割结果曲线C’
End
二、算法实现:
这里我选择Mean Separation (MS) Energy能量最小化为例,讲解局部活动轮廓图像分割,具体的参考文献为:《Localizing Region-Based Active Contours》。这里为直接把文中最后算法实现需要使用的公式,截出来,以便学习。
水平集总演化公式为:
其中:
dt是一个较小的数,选择范围为0.1~40都可以,当然迭代步长还是选择的越小效果越好,就是需要的迭代次数越多。然后下面的公式为公式(17)对应的参数求解公式:
其中:
公式3是一个卷积核,上面的大部分过程的计算都涉及到用B(x,y)进行卷积,卷积半径在我的项目使用的时候,我是选择R=8,而且B(x,y)是一个均值滤波的卷积核,因此如果要对算法用快速均值滤波,算法可提高五六倍的速度。具体算法代码实现如下:
个人观点:我觉得传统的snake算法,只能用烂来解释,基本上以遇到一点噪声,就不行了,分割精度真不是一般的差。而水平集的分割只能用高大上来形容,可以进行自动分裂合并等,就是速度有点慢,因为每次都要对水平集函数进行更新,更新一次就相当于遍历一张图片,因此速度可想而知,当然还有很多加速版的水平集方法,有待测试学习。本文地址:http://blog.csdn.net/hjimce/article/details/45586727 作者:hjimce 联系qq:1393852684 更多资源请关注我的博客:http://blog.csdn.net/hjimce 原创文章,版权所有,转载请保留本行信息