LazySnapping算法详解
LazySnapping 算法
简介
这是一篇和GrabCut同时期的算法,论文名称就叫《Lazy Snapping》,他的作用是用户交互指定前景背景来分割,如图所示。
我还是使用的Eigen库+maxflow库实现,代码库链接如下:MaxtirError/LazySnaping: LazySnaping algorithm with pure C++ and Qt GUI (github.com)
这篇文章仍然用到了两个简单的前置算法:分水岭算法和k-means聚类,下面简单介绍
分水岭算法
这个算法被用于图像预分割,想法非常巧妙。首先,图像转灰度,其次,把灰度看成高度,那么整张图片形成了一张地形图,尝试把水注入地形图中,当两块水域合并的时候,修筑堤坝,分割这两块小区域。实际上就是以每个局部极小值为中心把图像分割成若干块。
我并没有去阅读这个算法的原论文,而是基于上面的想法写了如下算法。
图像转灰度图
从小到大扫描灰度,对于扫描到的新点uuu,考虑和他四相邻的节点viv_ivi:
对于已经被扫描过且满足Gray(u)−Gray(v)<=thred(20)Gray(u)-Gray(v)<=thred(20)Gray(u)−Gray(v)<=thred(20)的viv_ivi,直接把这个新点uuu划分到随便一个viv_ivi所在区域。
如果不存在这样的viv_ivi,把uuu划分到一个新的区域
扫描完所有灰度之后,可以得到一个划分。
如下是某张图划分的结果
原图:
分水岭算法:
可以看到,很多相似的像素区域(比如天空)被很好地划分了。
这个算法最显著的效果就是:优化了参数空间。
原图大小是960*720,优化过后的region只有32298,只有原图的4%左右
k-means聚类
类似GMM的一个聚类算法,但是比GMM简单很多。输入是一堆数据{Xi}\{X_i\}{Xi},希望找到一个大小为k的划分{S1⋯Sk}\{S_1\cdots S_k\}{S1⋯Sk},使得Energy=∑k∑Xi∈Sk∣∣Xi−μk∣∣Energy=\sum_k \sum_{X_i\in S_k} ||X_i-\mu_k||Energy=∑k∑Xi∈Sk∣∣Xi−μk∣∣最小化。也就是每个XiX_iXi到它属于集合的某个中心距离和最小。
算法流程实际上就是一个简单的迭代:
初始化每个集合SiS_iSi的k个质心μi\mu_iμi
计算所有点最近的质心,把这些点划分到对应的集合里面。
对于每个集合,用属于这个集合的所有点的均值作为新的质心。
重复2-3直到能量收敛
这个算法理解起来很简单,就是一个简单的Local/Global模型。但是有一个问题初始值的决定。如果随机k个点作为初始质心的化,很容易出现空簇(也就是某个集合突然没有点离它最近了),这个时候能量会收敛到一个局部极小值。
为了解决上述问题,有一个办法是,先选一个点,对于已经选好的初始点集SSS,每次选择距离这个集合SSS最远的一个点加入SSS作为新的初始点,使得所有初始点的位置尽可能分散在样本点中。这就是kmeans++算法,效果会好一点。
LazySnap主算法
形式化问题
给定一张色彩图数据CiC_iCi,和用户交互数据TB,TFT_B,T_FTB,TF,也就是确定为背景和前景的点集。
求一个“较好”的划分Xi∈{0,1}X_i\in\{0,1\}Xi∈{0,1},分离前景(1)和背景(0)
同样地,我们还是需要定义什么样的划分是优秀的,这里其实也是利用Cut的思想,定义能量函数为
E(x)=∑iE1(xi)+λ∑(i,j)∈CE2(xi,xj)E(x)=\sum_i E_1(x_i)+\lambda \sum_{(i,j)\in C} E_2(x_i,x_j) E(x)=i∑E1(xi)+λ(i,j)∈C∑E2(xi,xj)
也即似然能量E1(xi)E_1(x_i)E1(xi)和边界能量E2(xi,xj)E_2(x_i,x_j)E2(xi,xj),CCC表示(i,j)(i,j)(i,j)相邻
似然(likelihood)能量
字面意思,就是当前像素和用户指定的前景/背景的相似程度。
因此,对于点击TB,TFT_B,T_FTB,TF,分别用kmeans聚类算法得到KnB,KmFK_n^B,K_m^FKnB,KmF,聚类的个数KKK文章用的是64。某个像素点到这两个聚类的距离定义为
dX=mini∣∣C(i)−KiX∣∣d^X=\min_i||C(i)-K^X_i|| dX=imin∣∣C(i)−KiX∣∣
那么,似然能量被定义为
E1(xi)=[xi=0]dBdB+dF+[xi=1]dFdB+dFE_1(x_i)=[x_i=0]\frac{d^B}{d^B+d^F}+[x_i=1]\frac{d^F}{d^B+d^F} E1(xi)=[xi=0]dB+dFdB+[xi=1]dB+dFdF
边界(boundary)能量
也就是两块区域的边界分割产生的能量,具体地,定义g(x)=1x+1g(x)=\frac{1}{x+1}g(x)=x+11,边界能量被定义为
E2(xi,xj)=∣xi−xj∣]g(∣∣C(i)−C(j)∣∣2)E_2(x_i,x_j)=|x_i-x_j|]g(||C(i)-C(j)||^2) E2(xi,xj)=∣xi−xj∣]g(∣∣C(i)−C(j)∣∣2)
也就是越相似的像素相邻像素被分割到不同类所产生的能量越大
我们需要做的就是最小化能量。
算法流程
调用分水岭算法,先预分割图像,并处理出预分割后每个小区域的平均像素,以及小区域之间的连接情况。
把用户交互的前景/背景像素转化成被选中的小区域(区域内只要有一个像素被选中,就视为被选中。
kmeans聚类算法算两类区域的聚类。
根据最小割模型分割图像最小化能量。
注解:
kmeans聚类算法有两种选择,一种是使用原始数据聚类,一种是用平均像素聚类。原文我没有找到用的是那种方法,实测下来,两种方法的效果是类似的,但平均像素聚类速度更快。
原文中边界能量和似然能量用的都是小区域平均像素计算。
最小割集合划分方法在GrabCut算法中有介绍,这里从略。
λ\lambdaλ取100-400效果都差不多。
实验结果与分析总结
速度和效率都很高。
有几个小问题:
边界有一些毛边。
有一些块状小区域分割错误(背景和前景都有错误)
并未实现的解决办法:
边界的毛边,原文中是采取用户交互+算法处理的。具体方法大致是用一个距离阈值和用户拖拽来把边界点集拟合成一个比较平滑的多边形。
关于小区域分割错误的情况,一方面可以通过用户交互来修正,一方面可以设置一个大小阈值把分割错误的区域修正。
事实上,得到了大致的边界结果之后,剩余的处理办法很多,也比较简单。
LazySnapping算法详解相关推荐
- Matlab人脸检测算法详解
这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...
- 图论-最短路Dijkstra算法详解超详 有图解
整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...
- C++中的STL算法详解
1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...
- 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码
粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...
- 基础排序算法详解与优化
文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...
- 目标检测 RCNN算法详解
原文:http://blog.csdn.net/shenxiaolu1984/article/details/51066975 [目标检测]RCNN算法详解 Girshick, Ross, et al ...
- Twitter-Snowflake,64位自增ID算法详解
Twitter-Snowflake,64位自增ID算法详解 from: http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8 ...
- 数据结构与算法详解目录
数据结构与算法详解是一本以实例和实践为主的图书,主要是经典的数据结构与常见算法案例,来自历年考研.软考等考题,有算法思路和完整的代码,最后提供了C语言调试技术的方法. 后续配套微课视频. 第0章 基 ...
- [搜索]波特词干(Porter Streamming)提取算法详解(2)
接[搜索]波特词干(Porter Streamming)提取算法详解(1), http://blog.csdn.net/zhanghaiyang9999/article/details/4162 ...
最新文章
- java继承详解加练习题
- reg类型变量综合电路_verilog中reg和wire类型的区别
- 题目1549:货币问题
- 如何在Ubuntu18.04下安装CUDA10.1和cudnn
- 30多年程序员生涯经验总结(成功源自于失败中的学习;失败则是因为容忍错误的横行)...
- Xshell配置ssh免密码登录-密钥公钥(Public key)
- UVA - 514:Rails
- C++基础06-类与对象之new和malloc
- 程序员面试金典——9.6合法序号序列判断
- ORACLE学习笔记--性能优化3
- 2022年软考高级网络规划设计师备考指南
- 美团O2O供应链系统架构设计解析
- MTTR、MTBF、MTTF、可用性、可靠性傻傻分不清楚?
- 无限极分类php实现—查子孙树、家谱树
- 云计算进化史及服务模式
- asp动态网站编程课程体系
- 菠萝食客与菠萝刀:我们为什么应该重复造轮子
- 华三H3C设备 公司网络外网变慢分析
- vue页面fav icon
- 京东、知乎、天猫等各大平台的K8S架构你知道多少?