SILC超像素分割算法详解(附Python代码)
SILC算法详解
⼀、原理介绍
SLIC算法是simple linear iterative cluster的简称,该算法⽤来⽣成超像素(superpixel)
算法步骤:
已知⼀副图像⼤⼩M*N,可以从RGB空间转换为LAB空间,LAB颜⾊空间表现的颜⾊更全⾯
假如预定义参数K,K为预⽣成的超像素数量,即预计将M*N⼤⼩的图像(像素数⽬即为M*N)分隔为K个超像素块,每个超像素块范围⼤⼩包含[(M*N)/K]个像素
假设每个超像素区域长和宽都均匀分布的话,那么每个超像素块的长和宽均可定义为S,S=sqrt(M*N/K)
遍历操作,将每个像素块的中⼼点的坐标(x,y)及其lab的值保存起来,加⼊到事先定义好的集合中
每个像素块的中⼼点默认是(S/2,S/2)进⾏获取的,有可能落在噪⾳点或者像素边缘(所谓像素边缘,即指像素突变处,⽐如从⿊⾊过渡到⽩⾊的交界处),这⾥,利⽤差分⽅式进⾏梯度计算,调
整中⼼点:
算法中,使⽤中⼼点的8领域像素点,计算获得最⼩梯度值的像素点,并将其作为新的中⼼点,差分计算梯度的公式:
Gradient(x,y)=dx(i,j) + dy(i,j);
dx(i,j) = I(i+1,j) - I(i,j);
dy(i,j) = I(i,j+1) - I(i,j);
遍历现中⼼点的8领域像素点,将其中计算得到最⼩Gradient值的像素点作为新的中⼼点
调整完中⼼点后即需要进⾏像素点的聚类操作
通过聚类的⽅式迭代计算新的聚类中⼼;
⾸先,需要借助K-means聚类算法,将像素点进⾏归类,通过变换的欧⽒聚距离公式进⾏,公式如下(同时参考像素值和坐标值提取相似度):
通过两个参数m和S来协调两种距离的⽐例分配。参数S即是上⾯第③步计算得出的每个像素块的长度值,⽽参数M为LAB空间的距离可能最⼤值,其可取的范围建议为[1,40]
为了节省时间,只遍历每个超像素块中⼼点周边的2S*2S区域内的像素点,计算该区域内每个像素点距离哪⼀个超像素块的中⼼点最近,并将其划分到其中;完成⼀次迭代后,重新计算每个超像素块的中⼼点坐标,并重新进⾏迭
⼆、代码实现
1import math
2from skimage import io, color
3import numpy as np
4
5class Cluster(object):
6
7    cluster_index = 1
8
9def__init__(self, row, col, l=0, a=0, b=0):
10        self.update(row, col, l, a, b)
11        self.pixels = []
12        = self.cluster_index
13        Cluster.cluster_index += 1
14
15def update(self, row, col, l, a, b):
16        w = row
17        l = col
18        self.l = l
19        self.a = a
20        self.b = b
21
22
23class SLICProcessor(object):
24    @staticmethod
25def open_image(path):
26        rgb = io.imread(path)
27        lab_arr = b2lab(rgb)
28return lab_arr
29
30    @staticmethod
31def save_lab_image(path, lab_arr):
32        rgb_arr = color.lab2rgb(lab_arr)
33        io.imsave(path, rgb_arr)
34
35def make_cluster(self, row, col):
36        row=int(row)
37        col=int(col)
38return Cluster(row, col,
39                        self.data[row][col][0],
40                        self.data[row][col][1],
41                        self.data[row][col][2])
42
43def__init__(self, filename, K, M):
44        self.K = K
45        self.M = M
46
47        self.data = self.open_image(filename)
48        ws = self.data.shape[0]
49        ls = self.data.shape[1]
50        self.N = ws * ls
51        self.S = int(math.sqrt(self.N / self.K))
52
53        self.clusters = []
54        self.label = {}
55        self.dis = np.full((ws, ls), np.inf)
56
57def init_clusters(self):
58        row = self.S / 2
59        col = self.S / 2
60while row < ws:
61while col < ls:
62                self.clusters.append(self.make_cluster(row, col))
63                col+= self.S
64            col = self.S / 2
65            row += self.S
66
67def get_gradient(self, row, col):
68if col + 1 >= ls:
69            col = ls - 2
70if row + 1 >= ws:
71            row = ws - 2
72
73        gradient = (self.data[row + 1][col][0] +self.data[row][col+1][0]-2*self.data[row][col][0])+ \
74                    (self.data[row + 1][col][1] +self.data[row][col+1][1]-2*self.data[row][col][1]) + \
75                    (self.data[row + 1][col][2] +self.data[row][col+1][2]-2*self.data[row][col][2])
76
77return gradient
78
79def move_clusters(self):
80for cluster in self.clusters:
81            cluster_gradient = _w, l)
82for dh in range(-1, 2):
83for dw in range(-1, 2):
84                    _row = w + dh
85                    _col = l + dw
86                    new_gradient = _gradient(_row, _col)
87if new_gradient < cluster_gradient:
88                        cluster.update(_row, _col, self.data[_row][_col][0], self.data[_row][_col][1], self.data[_row][_col][2])
89                        cluster_gradient = new_gradient
90
91def assignment(self):
92for cluster in self.clusters:
93for h in w - 2 * self.S, w + 2 * self.S):
94if h < 0 or h >= ws: continue
95for w in l - 2 * self.S, l + 2 * self.S):
96if w < 0 or w >= ls: continue
97                    L, A, B = self.data[h][w]
98                    Dc = math.sqrt(
99                        math.pow(L - cluster.l, 2) +
100                        math.pow(A - cluster.a, 2) +
101                        math.pow(B - cluster.b, 2))
102                    Ds = math.sqrt(
103                        math.pow(h - w, 2) +
104                        math.pow(w - l, 2))
105                    D = math.sqrt(math.pow(Dc / self.M, 2) + math.pow(Ds / self.S, 2))
106if D < self.dis[h][w]:
107if (h, w) not in self.label:
108                            self.label[(h, w)] = cluster
109                            cluster.pixels.append((h, w))
110else:
111                            self.label[(h, w)].ve((h, w))
112                            self.label[(h, w)] = cluster
113                            cluster.pixels.append((h, w))
114                        self.dis[h][w] = D
115
116def update_cluster(self):
117for cluster in self.clusters:
118            sum_h = sum_w = number = 0
119for p in cluster.pixels:
120                sum_h += p[0]
121                sum_w += p[1]
122                number += 1
123                _h =int( sum_h / number)
124                _w =int( sum_w / number)
125                cluster.update(_h, _w, self.data[_h][_w][0], self.data[_h][_w][1], self.data[_h][_w][2])
126
127def save_current_image(self, name):
128        image_arr = np.copy(self.data)
129for cluster in self.clusters:
130for p in cluster.pixels:
131                image_arr[p[0]][p[1]][0] = cluster.l
132                image_arr[p[0]][p[1]][1] = cluster.a
133                image_arr[p[0]][p[1]][2] = cluster.b
134            image_w][l][0] = 0
135            image_w][l][1] = 0
136            image_w][l][2] = 0
137        self.save_lab_image(name, image_arr)
138
139def iterates(self):
140        self.init_clusters()
141        ve_clusters()
142#考虑到效率和效果,折中选择迭代10次
143for i in range(10):
144            self.assignment()
145            self.update_cluster()
146        self.save_current_image("output.jpg")
147
148
149if__name__ == '__main__':
150    p = SLICProcessor('beauty.jpg', 200, 40)
151    p.iterates()
python代码转换三、运⾏效果截图
(原图)
(效果图)
代码参考了github/laixintao/slic-python-implementation,且做了改进
作为⼀枚技术⼩⽩,写这篇笔记的时候参考了很多博客论⽂,在这⾥表⽰感谢,转载请注明出处......

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。