-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSLIC_superpixel.py
More file actions
183 lines (128 loc) · 4.6 KB
/
Copy pathSLIC_superpixel.py
File metadata and controls
183 lines (128 loc) · 4.6 KB
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import math
import cv2
import numpy as np
import matplotlib.pyplot as plt
from util.img_show import superpixel_plot, rgb_segment
def init_centroid(img, steps):
centers = []
"""
Randomly generate center coordinates with iteration
Inputs:
- img: A 3 channels numpy array, shape of (h, w, 3)
- S: Avg length of superpixels, could also regard as step distance of each superpixels
"""
h, w, _ = img.shape
for i in range(steps//2, h, steps):
for j in range(steps//2, w, steps):
center_x = j
center_y = i
centers.append([center_x, center_y])
return centers
def gradient(img):
h, w, d = img.shape
# Gradient map
grad = np.zeros((h,w))
# Compute the gradient
for i in range(1, h-1):
for j in range(1, w-1):
for k in range(d):
dx = img[i+1, j, k] - img[i-1, j, k]
dy = img[i, j+1, k] - img[i, j-1, k]
grad[i,j] = np.sqrt(dx**2 + dy**2)
return grad
def perturb2_lowG(img, grad, centers):
h, w, _ = img.shape
num_centers = len(centers) # Number of centers
k = 5 # 5X5 kernal
for i in range(num_centers):
x = centers[i][0]
y = centers[i][1]
# define region of neighbors
kernal = grad[y-k : y+k, x-k : x+k]
min_gradient_idx = np.argwhere(kernal == np.min(kernal))[0]
# Move the center to the lowest gradient of nXn neighbor
idx_y = min_gradient_idx[0] + y
idx_x = min_gradient_idx[1] + x
centers[i] = [idx_x, idx_y]
return centers
def cielab_distance(pt_xy, pt_pixel, cnt_xy, cnt_pixel, S, m):
pt_x = pt_xy[0]
pt_y = pt_xy[1]
pt_l, pt_a, pt_b = pt_pixel
cnt_x = cnt_xy[0]
cnt_y = cnt_xy[1]
c_l, c_a, c_b = cnt_pixel
d_xy = math.sqrt((pt_x-cnt_x)**2 + (pt_y-cnt_y)**2)
d_lab = math.sqrt((pt_l-c_l)**2 + (pt_a-c_a)**2 + (pt_b-c_b)**2)
dist = d_lab + (m*d_xy/S)
return dist
def update_centers(img, segmap):
h, w, _ = img.shape
new_centers = []
num_clusters = int(np.max(segmap)+1)
for i in range(num_clusters):
cluster_pts = np.where(segmap == i)
cluster_y = cluster_pts[0]
cluster_x = cluster_pts[1]
center_y = cluster_y.mean()
center_x = cluster_x.mean()
new_centers.append([int(center_x), int(center_y)])
return new_centers
def SLIC(im, k):
"""
Input arguments:
im: image input
k: number of cluster segments
Compute
S: As described in the paper
m: As described in the paper (use the same value as in the paper)
follow the algorithm..
returns:
segmap: 2D matrix where each value corresponds to the image pixel's cluster number
"""
height, width, depth = im.shape
dist_map = np.ones((height, width))*math.inf
segmap = np.zeros((height, width))
# Initialize Parameters
N = height * width # Image pixels
S = int(math.sqrt(N/k)) # Avg distance length of each cluster centers
m = 10 # Range between 1 and 20
convg_num = 10
# Convert BRG to Lab space
img_lab = cv2.cvtColor(im, cv2.COLOR_BGR2LAB).astype(np.float64)
# Initialize Centers
centers = init_centroid(img_lab, S)
# Compute the Gradient
grad = gradient(img_lab)
# Move the centers to the lowest gradient
centers = perturb2_lowG(img_lab, grad, centers)
iter = 0
while iter < convg_num:
distances = np.full((height, width), np.inf)
# Assigning pixels to cluster
for label in range(len(centers)):
for i in range(height):
for j in range(width):
curr_xy = [j,i]
curr_pixel = img_lab[i,j]
centriod_pixel = img_lab[centers[label][1], centers[label][0]]
# Find pixels within area around pixel center D_s
D_s = cielab_distance(curr_xy, curr_pixel, centers[label], centriod_pixel, S, m)
if D_s < distances[i,j]:
distances[i, j] = D_s
segmap[i,j] = label
centers = update_centers(img_lab, segmap)
iter += 1
return segmap
im_list = ['./data/MSRC_ObjCategImageDatabase_v1/1_22_s.bmp',
'./data/MSRC_ObjCategImageDatabase_v1/1_27_s.bmp']
def main():
for img in im_list:
im = cv2.imread(img)
k = 25
clusters = SLIC(im, k=k)
_ = rgb_segment(clusters,n = k, title = "naive clustering: Pixelwise class plot: Clusters: " + str(k),legend = False)
superpixel_plot(im,clusters,title = "naive clustering: Superpixel plot: Clusters: "+ str(k))
plt.show()
if __name__ == "__main__":
main()