pytorch i2i 图像分割测试集_水平集_图像分割

外文原址:https://wiseodd.github.io/techblog/2016/11/05/levelset-method/

Part 1: Introduction

各位看官,当你关注最近计算机视觉发展趋势时有没有发现一个现象:大家都逐渐放弃了传统的方法,都是将数据一股脑地丢给深度卷积神经网络,当真是‘遇事不决,深度网络来学‘。不管各位看官是否决定要投入深度学习的怀抱,研究经典的计算机视觉算法仍然是入门数字图像处理的关键基础。

我们将要学习一种经典的计算机视觉方法:水平集方法(the level set method,LSM)。本章我们将了解LSM背后的动机、数学描述以及实现一个简单的LSM模型,下一章节,我们将用水平集方法来处理图像分割问题。

水平集方法的感性认识

追忆逝水年华,当我们还在穿开裆裤的年纪时,应该都干过往水里丢石块的游戏。一个石块扑通扔水里会是什么现象?没错,是泛起阵阵涟漪,那优美的波纹肯定逗笑了岸边穿开裆裤的你。别顾着开心 ,那么问题来了,要怎么用数学方法去对逐渐’荡‘开的波纹进行建模呢 ?

我们可以这样做:对涟漪曲线进行建模,并跟踪它的运动。比方说,在时间t=1时刻,涟漪曲线是这个样子的:

图1

现在,我们要对随着时间’荡漾‘开去的涟漪进行建模。因此,我们要跟踪图1所示曲线的运动。一种直观的方法是对曲线 上的点进行采样,然后将采样得到的点按其法线方向移动至’新‘位置,最后用平滑的曲线将所有’新‘点连接起来,即得所求结果:

图2

对于非常简单模型的仿真,上述过程是个很好的解决方案。但是,如果你同时丢了两个石块,形成了两个荡漾的涟漪,此时会发生什么呢?现实中我们会发现,两个涟漪‘荡’到一起,有‘融合’的迹象了,如下图:

图3

假设没有外力,图3中的两条曲线将合并为一条曲线 ,当然,我们也可想象一条曲线分裂为两条甚至多条曲线的情形。那么,我们怎么是表述这种合并和分裂呢?显然继续运用处理图2时的思路是行不通的。

接下来就该LSM大放异彩了。LSM会隐式地对曲线运动进行建模,而不是显式建模。此时聪明的你可能会问 ,LSM是如何对曲线的分割、合并及其运动进行建模的?别急,慢慢来。

我们先作出一个3D曲面和一个2D平面:

图4

通过利用曲面、平面和曲线三者之间的关系,我们可以用3维的曲面隐式地对2维曲线进行建模,我们可以调整曲面,使其与平面相交于一定’高度‘,如下所示:

图5

让我们来仔细瞧瞧图5中曲面与平面相交的结果,没错,聪明的你已经观测到它们的相交结果就是条曲线(圆)。此时,曲线就是水平集函数在特定自变量取值下的函数值集合。这就是水平集背后的思想。我们通过演化曲面,并将其与一个平面相交来隐式地修正我们希望得到的曲线。

但是LSM是如何对曲线的合并和分裂现象进行建模的?我们对曲面做点改动,看看它多水平曲线有何影响:

图6

图6中我们将用有单个极小值的曲面演化到拥有两个局部最小值的曲面。此时将会得到两个圆(两条曲线 ),这就模拟了曲线分裂。曲线合并示意如下:

图7

轻轻松松对不对,原来曲线演化就隐含在曲面演化过程中!

这真是个绝妙的思路,接下来让我们用公式来表述它。

水平集方法的理性表达:

假设我们有一个曲面ϕ(x),该曲面的c水平集为(曲面的c水平集可以 理解为用高度为c的平面去截曲面ϕ(x),所得截面面就是所需曲线,其实一个曲面也可以理解为无数个高度为c的曲线所叠加成的,我们只取高度为特定值的一条。所谓弱水三千只取一瓢嘛):

{x|ϕ(x)=c}{x|ϕ(x)=c} (1)

一般地,我们需要追踪c=0时的曲线变化,即:

{x|ϕ(x)=0} (2)

当我们用曲面的演化来隐式地表达曲线演化的时候,需要将曲面参数化为时间t的函数,即:

ϕ(x(t),t)=0 (3)

请注意:ϕ是t的函数,x亦是t的函数哦 ,后面复合函数的链式求导法则要会用哦。

接下来 ,我们要追踪ϕ的0水平集运动,那如何追踪曲面的瞬时运动状态呢?3维曲面瞬时状态不好理解,那我们就对它进行降维打击嘛。想想我们是怎么描述曲线的瞬时状态的?对,不就是导数嘛(导数就是两个相差微小的点的变化量哦)。另外请记住一点哦,位置的导数是啥?不要怀疑,位置的导数就是速度哦(试想一下,你在参加长跑比赛,对你求导,你的当前位置加上你的导数,就是你下一秒所在的位置呢~,这个导数就是速度哦~)。知道了位置的导数,也即知道了瞬时速度,知道了速度我们就可以 对 曲面进行建模了嘛,式(4):

应用复合函数的链式求导法则,可知,式(5):

众所周知,根据定义,上式最左边的偏导数其实就是曲面的梯度啦,为了更清晰简洁的表达,我们将上式改写为,式(6):

上式第一部分表示ϕ曲面的梯度,第二部分 表示X对t求导,第三部分表示ϕ对t求 导。如上所述,曲线是朝着法线方向运动的,法线N=- ∇ϕ/∥∇ϕ∥,当然光有方向是不行的,还得有推动曲线沿法线方向运动的’力‘,我称之为F,曲线的速度矢量也即,曲线对时间t求导,式(7):

将式(7)代入到式(6)可得:

移项就可得:

ϕt=F∥∇ϕ∥ 式(8)

式(8)就是曲面的演化方程!!!

解偏微分方程 PDE

知道了曲面ϕ的初始状态(0水平状态)和演化速度,我们就能求解运动方程了。也即,我们想知道曲面ϕ随着时间t的变化而变化的形态,这就是偏微分方程的求解问题。

最简单的求解思路就是有限差分了,首先考虑前向差分,式(9):

记住 所谓梯度本质就是导数哦,位置的导数就是变化速度!!!!

对曲面ϕ,计算前向差分,并简化可得,式(10)-(13):

(注意:整个曲面满足这个演化方程时,也就意味着曲面蕴含的0水平集也满足这个方程,那么我们只需要追踪这个0水平集的演化过程即可!!!!!)

搞深度学习的朋友有没有觉得似曾相识呢?让我们 回忆下梯度下降的更新规则,式(14):

x′=x+α∇x

熟悉的配方熟悉 的味道啊~

实际上我们在做曲面ϕ关于时间t的梯度下降啊!!!,式(15):

ϕ′=ϕ+ΔtF∥∇ϕ∥

(理解:ϕ下一时刻的状态=ϕ当前时刻的状态+时间间隔*移动速度*单位法向量)

就这么简单粗暴~。我们只需知道ϕ的初始状态和速度函数F(推动曲面演化的力)就能对曲面的演化进行建模了,F根据 具体应用而定 。

代码实现

式(10)-(13)以及(15)给出了求解LSM的PED(偏微分方程),接下来我们就来实现一个简单LSM模型吧。

首先给出初始轮廓,然后根据F对曲面进行演化,演化的0水平集就是所求曲线。代码如下(F函数取决于具体应用哦):

Import numpy as np

Import matplotlib.pyplot as plt

Phi=np.random.randn(20,20)

F=……. # 速度函数

Dt=1 #时间间隔为1

Iter100 # 迭代次数

for i in range(iter):

# 对初始曲线求导(梯度)

#np.gradient()求导是有方向的哦,返回横向、纵向的求导结果

#结果为2通道哦~

Dphi=np.gradient(phi)

#梯度正则化,将两个方向的梯度归一成一个值哦~,

Dphi_norm=np.sqrt(np.sum(Dphi**2,axis=0)) #

# 下一时刻状态=当前状态+瞬时间隔*速度*单位法向量

Phi=Phi+dt*F*Dphi_norm

您瞧,用少量代码就能实现LSM的核心思想,是不是很酷~。但别骄傲哦,这只是最简单的LSM模型表达,课堂所学与试卷所考还是有巨大差别的~。

总结:

1、本章介绍了用曲面演化来隐式地表达曲线演化的水平集模型——LSM。LSM是强大的,它不用显式地对运动的曲线进行建模(曲线的分裂、合并很难显式表达)

2、然后,我们研究了LSM算法的公式描述以及如何用有限差分法将LSM解为PDE

3、给出了一个简单的LSM模型代码

你可能感兴趣的:(pytorch,i2i,图像分割测试集)