python图像分割算法_SLIC算法分割超像素原理及Python实现
超像素(SuperPixel),就是把原本多个像素点,组合成一个大的像素。比如,原本的图片有二十多万个像素,用超像素处理之后,就只有几千个像素了。后面做直方图等处理就会方便许多。经常作为图像处理的预处理步骤。
在超像素算法方面,SLIC Superpixels Compared to State-of-the-art Superpixel Methods这篇论文非常经典。论文中从算法效率,内存使用以及直观性比较了现有的几种超像素处理方法,并提出了一种更加实用,速度更快的算法——SLIC(simple linear iterative clustering),名字叫做简单的线性迭代聚类。其实是从k-means算法演化的,算法复杂度是O(n),只与图像的像素点数有关。
这个算法突破性的地方有二:
限制聚类时搜索的区域(2Sx2S),这样将k-means算法的复杂度降为常数。整个算法的复杂度为线性。
计算距离时考虑LAB颜色和XY距离,5维。这样就把颜色和距离都考虑进去了。通过M可以调整颜色和距离的比重,灵活性强,超像素更加规则。
SLIC算法原理
整个算法的输入只有一个,即超像素的个数K。
图片原有N个像素,要分割成K个像素,那么每个像素的大小是N/K。超像素之间的距离(即规则情况下超像素的边长)就是S=√N/K。
我们的目标是使代价函数(cost function)最小。具体到本算法中,就是每个像素到所属的中心点的距离之和最小。
首先,将K个超像素种子(也叫做聚类,即超像素的中心),均匀撒到图像的像素点上。
一次迭代的第一步,对每个超像素的中心,2S范围内的所有像素点,判断他们是否属于这个超像素。这样之后,就缩短了像素点到超像素中心的距离。
一次迭代的第二步,对每个超像素,将它的超像素中心移动到这个超像素的中点上。这样也缩短了像素点到超像素中心的距离。
一般来说,迭代10是聚类效果和计算成本折中的次数。
SLIC算法步骤
撒种子。将K个超像素中心分布到图像的像素点上。
微调种子的位置。以K为中心的3×3范围内,移动超像素中心到这9个点中梯度最小的点上。这样是为了避免超像素点落到噪点或者边界上。
初始化数据。取一个数组label保存每一个像素点属于哪个超像素。dis数组保存像素点到它属于的那个超像素中心的距离。
对每一个超像素中心x,它2S范围内的点:如果点到超像素中心x的距离(5维)小于这个点到它原来属于的超像素中心的距离,那么说明这个点属于超像素x。更新dis,更新label。
对每一个超像素中心,重新计算它的位置。
重复4 5 两步。
伪代码(来自论文)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/∗Initialization∗/
InitializeclustercentersCk=[lk,ak,bk,xk,yk]TbysamplingpixelsatregulargridstepsS.
Moveclustercenterstothelowestgradientpositionina3×3neighborhood.
Setlabell(i)=−1foreachpixeli.Setdistanced(i)=∞foreachpixeli.
repeat
/∗Assignment∗/
foreachclustercenterCkdo
foreachpixeliina2S×2SregionaroundCkdo
ComputethedistanceDbetweenCkandi.
ifD
setd(i)=D
setl(i)=k
endif
endfor
endfor
/∗Update∗/
Computenewclustercenters.ComputeresidualerrorE.
untilE≤threshold
Python实现SLIC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
importmath
fromskimageimportio,color
importnumpyasnp
fromtqdmimporttrange
classCluster(object):
cluster_index=1
def__init__(self,h,w,l=0,a=0,b=0):
self.update(h,w,l,a,b)
self.pixels=[]
self.no=self.cluster_index
self.cluster_index+=1
defupdate(self,h,w,l,a,b):
self.h=h
self.w=w
self.l=l
self.a=a
self.b=b
def__str__(self):
return"{},{}:{} {} {} ".format(self.h,self.w,self.l,self.a,self.b)
def__repr__(self):
returnself.__str__()
classSLICProcessor(object):
@staticmethod
defopen_image(path):
"""
Return:
3D array, row col [LAB]
"""
rgb=io.imread(path)
lab_arr=color.rgb2lab(rgb)
returnlab_arr
@staticmethod
defsave_lab_image(path,lab_arr):
"""
Convert the array to RBG, then save the image
"""
rgb_arr=color.lab2rgb(lab_arr)
io.imsave(path,rgb_arr)
defmake_cluster(self,h,w):
returnCluster(h,w,
self.data[h][w][0],
self.data[h][w][1],
self.data[h][w][2])
def__init__(self,filename,K,M):
self.K=K
self.M=M
self.data=self.open_image(filename)
self.image_height=self.data.shape[0]
self.image_width=self.data.shape[1]
self.N=self.image_height*self.image_width
self.S=int(math.sqrt(self.N/self.K))
self.clusters=[]
self.label={}
self.dis=np.full((self.image_height,self.image_width),np.inf)
definit_clusters(self):
h=self.S/2
w=self.S/2
whileh
whilew
self.clusters.append(self.make_cluster(h,w))
w+=self.S
w=self.S/2
h+=self.S
defget_gradient(self,h,w):
ifw+1>=self.image_width:
w=self.image_width-2
ifh+1>=self.image_height:
h=self.image_height-2
gradient=self.data[w+1][h+1][0]-self.data[w][h][0]+\
self.data[w+1][h+1][1]-self.data[w][h][1]+\
self.data[w+1][h+1][2]-self.data[w][h][2]
returngradient
defmove_clusters(self):
forclusterinself.clusters:
cluster_gradient=self.get_gradient(cluster.h,cluster.w)
fordhinrange(-1,2):
fordwinrange(-1,2):
_h=cluster.h+dh
_w=cluster.w+dw
new_gradient=self.get_gradient(_h,_w)
ifnew_gradient
cluster.update(_h,_w,self.data[_h][_w][0],self.data[_h][_w][1],self.data[_h][_w][2])
cluster_gradient=new_gradient
defassignment(self):
forclusterinself.clusters:
forhinrange(cluster.h-2*self.S,cluster.h+2*self.S):
ifh<0orh>=self.image_height:continue
forwinrange(cluster.w-2*self.S,cluster.w+2*self.S):
ifw<0orw>=self.image_width:continue
L,A,B=self.data[h][w]
Dc=math.sqrt(
math.pow(L-cluster.l,2)+
math.pow(A-cluster.a,2)+
math.pow(B-cluster.b,2))
Ds=math.sqrt(
math.pow(h-cluster.h,2)+
math.pow(w-cluster.w,2))
D=math.sqrt(math.pow(Dc/self.M,2)+math.pow(Ds/self.S,2))
ifD
if(h,w)notinself.label:
self.label[(h,w)]=cluster
cluster.pixels.append((h,w))
else:
self.label[(h,w)].pixels.remove((h,w))
self.label[(h,w)]=cluster
cluster.pixels.append((h,w))
self.dis[h][w]=D
defupdate_cluster(self):
forclusterinself.clusters:
sum_h=sum_w=number=0
forpincluster.pixels:
sum_h+=p[0]
sum_w+=p[1]
number+=1
_h=sum_h/number
_w=sum_w/number
cluster.update(_h,_w,self.data[_h][_w][0],self.data[_h][_w][1],self.data[_h][_w][2])
defsave_current_image(self,name):
image_arr=np.copy(self.data)
forclusterinself.clusters:
forpincluster.pixels:
image_arr[p[0]][p[1]][0]=cluster.l
image_arr[p[0]][p[1]][1]=cluster.a
image_arr[p[0]][p[1]][2]=cluster.b
image_arr[cluster.h][cluster.w][0]=0
image_arr[cluster.h][cluster.w][1]=0
image_arr[cluster.h][cluster.w][2]=0
self.save_lab_image(name,image_arr)
defiterate_10times(self):
self.init_clusters()
self.move_clusters()
foriintrange(10):
self.assignment()
self.update_cluster()
name='lenna_M{m}_K{k}_loop{loop}.png'.format(loop=i,m=self.M,k=self.K)
self.save_current_image(name)
if__name__=='__main__':
p=SLICProcessor('Lenna.png',500,30)
p.iterate_10times()
效果如下:
Lenna图像在M=30,K=500时第一次迭代产生的超像素图。
Lenna图像在M=30,K=500时第10次迭代产生的超像素图。
python图像分割算法_SLIC算法分割超像素原理及Python实现相关推荐
- opencv14-图像分割--超像素分割与形态学分割
二值形态学在二值图像上进行运算,二值图像是从其他等级的强度通道产生的.为了进行图像分析,采用的方法是去除形状噪声或异常值以及加强主要特征点.形态学可用于目标识别.细胞生物学.医学.粒子分析和自动显微镜 ...
- python协同过滤算法_协同过滤(ALS)的原理及Python实现
提到ALS相信大家应该都不会觉得陌生(不陌生你点进来干嘛[捂脸]),它是协同过滤的一种,并被集成到Spark的Mllib库中.本文就ALS的基本原理进行讲解,并手把手.肩并肩地带您实现这一算法. 完整 ...
- python云盘搭建教程_超简单!基于Python搭建个人“云盘”,目前最好用的个人云盘...
超简单!基于Python搭建个人"云盘",目前最好用的个人云盘 1. 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码 ...
- Python教程分享,10款超好用的Python开发工具!
学会Python技术后,我们在参加工作的时候如果能有辅助工具的话,那么会很大程度的提高我们的工作效率,那么Python都有哪些好用的开发工具呢?下面小编就为大家详细的介绍一下10款超好用的python ...
- python自制个人网盘_超简单!基于Python搭建个人“云盘”
1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码. 而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类 ...
- python excel 库 知乎_超全整理|Python 操作 Excel 库 xlwings 常用操作详解!
来源:早起Python 作者:陈熹.刘早起 大家好,我是早起. 在之前的文章中我们曾详细的讲解了如何使用openpyxl 操作Excel,其实在Python中还有其他可以直接操作 Excel 文件的库 ...
- python读取txt文件并分割成列表_在python中读取文本文件并将其拆分为单个单词
给定此文件:$ cat words.txt line1 word1 word2 line2 word3 word4 line3 word5 word6 如果一次只需要一个单词(忽略文件中空格和换行符的 ...
- python高斯滤波和降噪_高斯滤波原理及python实现
高斯滤波器时一种线性平滑滤波器,主要适用处理高斯噪声,所以在了解高斯滤波之前,我们首先熟悉一下高斯噪声.噪声在图像中表现的通常是引起视觉效果的孤立像素点和像素块,简单说噪声点就是会给图像带来干扰,让图 ...
- julia 调用python库_Julia调用Python实现超像素分割SLIC算法
最近想要在julia中实现 Simple Linear Iterative Clustering (SLIC) 算法对图像进行超像素分割,关于SLIC超像素分割算法,请参考SLIC Superpixe ...
- 超像素分割(Slic算法)——个人梳理
一.使用背景 我在进行乳腺癌图像识别的学校项目中,参考了山东大学的硕士论文,并希望加以简化复现,此论文会在文末附上.项目要求我们需要对乳腺癌图片进行分类(无肿瘤,良性肿瘤,恶性肿瘤),参照论文所说,我 ...
最新文章
- a href=#与 a href=javascript:void(0) 的差别
- 【Ids4实战】深究配置——用户信息操作篇
- 20150504-日报
- python自动输入_使用Python和pywin32自动输入数据
- JavaScript的排序问题
- Android开源库
- XCODE GDB这个是老版本xcode,新版的是lldb
- 亲测可用|奥维互动地图加载谷歌地图等图源的方法
- python安装第三方库出现问题怎么办_关于Python第三方库安装失败问题的解决方案...
- 家庭必备,轻、快、好用的WIN10自带虚拟机
- C语言如何求球的体积和表面
- LeetCode-自除数
- springIOC原理解析
- [语录]足球解说员贺炜语录
- 怎么在线把图片转成PDF?几个步骤轻松转换
- 官方scratch3.0正式发布,全面支持移动设备在线编程!
- kali2022.1安装google chrome develop 专业版
- 什么是生产管理?制造企业想要做好生产管理应该怎么做?
- cell数据如何删除重复项
- 数据结构第一次上机实验报告