• 超像素经典 SLIC 算法 python 实现
千次阅读
2020-02-10 09:17:50

# 摘要

本文是研究生课程图像处理期末作业，内容是了解并入门超像素算法原理，主要介绍了超像素的评测标准，经典算法 SLIC，讨论了 SLIC 算法中的不足之处，以及 SLIC 的两个有效的改进算法 SEEDS 和 ETPS。
文章内容见我的码云

# python3 代码

运算速度慢但是便于理清 SLIC 算法的参考实现

import math
from skimage import io, color
import numpy as np
from tqdm import trange
from tqdm import tqdm

class Cluster(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
Cluster.cluster_index += 1

def update(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):
return self.__str__()

class SLICProcessor(object):
@staticmethod
def open_image(path):
"""
Return:
3D array, row col [LAB]
"""
lab_arr = color.rgb2lab(rgb)
return lab_arr

@staticmethod
def save_lab_image(path, lab_arr):
"""
Convert the array to RBG, then save the image
:param path:
:param lab_arr:
:return:
"""
rgb_arr = color.lab2rgb(lab_arr)
io.imsave(path, rgb_arr)

def make_cluster(self, h, w):
h = int(h)
w = int(w)
return Cluster(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)

def init_clusters(self):
h = self.S // 2
w = self.S // 2
while h < self.image_height:
while w < self.image_width:
self.clusters.append(self.make_cluster(h, w))
w += self.S
w = self.S // 2
h += self.S

if w + 1 >= self.image_width:
w = self.image_width - 2
if h + 1 >= self.image_height:
h = self.image_height - 2

gradient = self.data[h + 1][w + 1][0] - self.data[h][w][0] + \
self.data[h + 1][w + 1][1] - self.data[h][w][1] + \
self.data[h + 1][w + 1][2] - self.data[h][w][2]

def move_clusters(self):
for cluster in self.clusters:
for dh in range(-1, 2):
for dw in range(-1, 2):
_h = cluster.h + dh
_w = cluster.w + dw
cluster.update(_h, _w, self.data[_h][_w][0], self.data[_h][_w][1], self.data[_h][_w][2])

def assignment(self):
for cluster in tqdm(self.clusters):
for h in range(cluster.h - 2 * self.S, cluster.h + 2 * self.S):
if h < 0 or h >= self.image_height: continue
for w in range(cluster.w - 2 * self.S, cluster.w + 2 * self.S):
if w < 0 or w >= 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))
if D < self.dis[h][w]:
if (h, w) not in self.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

def update_cluster(self):
for cluster in self.clusters:
sum_h = sum_w = number = 0
for p in cluster.pixels:
sum_h += p[0]
sum_w += p[1]
number += 1
_h = int(sum_h / number)
_w = int(sum_w / number)
cluster.update(_h, _w, self.data[_h][_w][0], self.data[_h][_w][1], self.data[_h][_w][2])

def save_current_image(self, name):
image_arr = np.copy(self.data)
for cluster in self.clusters:
for p in cluster.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)

def iterate_10times(self):
self.init_clusters()
self.move_clusters()
for i in trange(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('kemomimi.png', 500, 40)
p.iterate_10times()



将上面缓慢的循环体转化成 numpy 高速矩阵运算的参考实现，很有 python 优化计算的学习意义。
作者原本是有一段合并不连续的超像素的函数（ SLIC 可选的后期处理），发现并没有用到，就去掉了。

# Aleena Watson
# Final Project - Computer Vision Simon Niklaus
# Winter 2018 - PSU

import numpy as np
import sys
from skimage import io, color
import tqdm

# using algorithm in 3.2 apply image gradients as computed in eq2:
# G(x,y) = ||I(x+1,y) - I(x-1,y)||^2+ ||I(x,y+1) - I(x,y-1)||^2

# SLIC implements a special case of k-means clustering algorithm.
# Was recommended to use an off the shelf algorithm for clustering but
# because this algorithm is based on this special case of k-means,
# I kept this implementation to stay true to the algorithm.

def generate_pixels():
indnp = np.mgrid[0:SLIC_height,0:SLIC_width].swapaxes(0,2).swapaxes(0,1)
for i in tqdm.tqdm(range(SLIC_ITERATIONS)):
SLIC_distances = 1 * np.ones(img.shape[:2])
for j in range(SLIC_centers.shape[0]):
x_low, x_high = int(SLIC_centers[j][3] - step), int(SLIC_centers[j][3] + step)
y_low, y_high = int(SLIC_centers[j][4] - step), int(SLIC_centers[j][4] + step)

if x_low <= 0:
x_low = 0
#end
if x_high > SLIC_width:
x_high = SLIC_width
#end
if y_low <=0:
y_low = 0
#end
if y_high > SLIC_height:
y_high = SLIC_height
#end

cropimg = SLIC_labimg[y_low : y_high , x_low : x_high]
color_diff = cropimg - SLIC_labimg[int(SLIC_centers[j][4]), int(SLIC_centers[j][3])]
color_distance = np.sqrt(np.sum(np.square(color_diff), axis=2))

yy, xx = np.ogrid[y_low : y_high, x_low : x_high]
pixdist = ((yy-SLIC_centers[j][4])**2 + (xx-SLIC_centers[j][3])**2)**0.5

# SLIC_m is "m" in the paper, (m/S)*dxy
dist = ((color_distance/SLIC_m)**2 + (pixdist/step)**2)**0.5

distance_crop = SLIC_distances[y_low : y_high, x_low : x_high]
idx = dist < distance_crop
distance_crop[idx] = dist[idx]
SLIC_distances[y_low : y_high, x_low : x_high] = distance_crop
SLIC_clusters[y_low : y_high, x_low : x_high][idx] = j
#end

for k in range(len(SLIC_centers)):
idx = (SLIC_clusters == k)
colornp = SLIC_labimg[idx]
distnp = indnp[idx]
SLIC_centers[k][0:3] = np.sum(colornp, axis=0)
sumy, sumx = np.sum(distnp, axis=0)
SLIC_centers[k][3:] = sumx, sumy
SLIC_centers[k] /= np.sum(idx)
#end
#end
#end

def display_contours(color):
rgb_img = img.copy()
is_taken = np.zeros(img.shape[:2], np.bool)
contours = []

for i in range(SLIC_width):
for j in range(SLIC_height):
nr_p = 0
for dx, dy in [(-1,0), (-1,-1), (0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1)]:
x = i + dx
y = j + dy
if x>=0 and x < SLIC_width and y>=0 and y < SLIC_height:
if is_taken[y, x] == False and SLIC_clusters[j, i] != SLIC_clusters[y, x]:
nr_p += 1
#end
#end
#end

if nr_p >= 2:
is_taken[j, i] = True
contours.append([j, i])
#end
#end
#end
for i in range(len(contours)):
rgb_img[contours[i][0], contours[i][1]] = color
# for k in range(SLIC_centers.shape[0]):
#     i,j = SLIC_centers[k][-2:]
#     img[int(i),int(j)] = (0,0,0)
#end
io.imsave("SLIC_contours.jpg", rgb_img)

return rgb_img
#end

def display_center():
'''
将超像素用聚类中心颜色代替
'''
import matplotlib.pyplot as plt

lab_img = np.zeros([SLIC_height,SLIC_width,3]).astype(np.float64)
for i in range(SLIC_width):
for j in range(SLIC_height):
k = int(SLIC_clusters[j, i])
lab_img[j,i] = SLIC_centers[k][0:3]
rgb_img = color.lab2rgb(lab_img)
io.imsave("SLIC_centers.jpg",rgb_img)
return (rgb_img*255).astype(np.uint8)

def find_local_minimum(center):
loc_min = center
for i in range(center[0] - 1, center[0] + 2):
for j in range(center[1] - 1, center[1] + 2):
c1 = SLIC_labimg[j+1, i]
c2 = SLIC_labimg[j, i+1]
c3 = SLIC_labimg[j, i]
if ((c1[0] - c3[0])**2)**0.5 + ((c2[0] - c3[0])**2)**0.5 < min_grad:
min_grad = abs(c1[0] - c3[0]) + abs(c2[0] - c3[0])
loc_min = [i, j]
#end
#end
#end
return loc_min
#end

def calculate_centers():
centers = []
for i in range(step, SLIC_width - int(step/2), step):
for j in range(step, SLIC_height - int(step/2), step):
nc = find_local_minimum(center=(i, j))
color = SLIC_labimg[nc[1], nc[0]]
center = [color[0], color[1], color[2], nc[0], nc[1]]
centers.append(center)
#end
#end

return centers
#end

# global variables
print(img.max(),img.min())
step = int((img.shape[0]*img.shape[1]/int(sys.argv[2]))**0.5)
SLIC_m = int(sys.argv[3])
SLIC_ITERATIONS = 4
SLIC_height, SLIC_width = img.shape[:2]
SLIC_labimg = color.rgb2lab(img)
SLIC_distances = 1 * np.ones(img.shape[:2])
SLIC_clusters = -1 * SLIC_distances
SLIC_center_counts = np.zeros(len(calculate_centers()))
SLIC_centers = np.array(calculate_centers())

# main
generate_pixels()
calculate_centers()
img_contours = display_contours([0.0, 0.0, 0.0])
img_center = display_center()

print(img,img_center,img_contours)
result = np.hstack([img,img_contours,img_center])
io.imsave("my_slic.jpg",result)

更多相关内容
• 在介绍SLIC之前，先来介绍以下Lab颜色空间的介绍。 Lab色彩模型是由亮度(L)要素和与有关色彩的a,b要素组成，L的值由0(黑色)到100(白色)，a表示从洋红色至绿色的范围(a为负值表示绿色而正值表示品红)，b表示从黄色至...

# 基础知识

在介绍SLIC之前，先来介绍以下Lab颜色空间的介绍。

Lab色彩模型是由亮度(L)要素和与有关色彩的a,b要素组成，L的值由0(黑色)到100(白色)，a表示从洋红色至绿色的范围(a为负值表示绿色而正值表示品红)，b表示从黄色至蓝色的范围(b为负值表示蓝色而正值表示黄色)。

Lab颜色空间的优点：
1）不像RGB和CMYK色彩空间，Lab颜色被设计来接近人类生理视觉。它致力于感知均匀性，它的L分量密切匹配人类亮度感知。因此可以被用来通过修改a和b分量的输出色阶来做精确的颜色平衡，或使用L分量来调整亮度对比。这些变换在RGB或CMYK种是困难的或不可能的。
2）色域宽广。它不仅包含了RGB、CMYK的所有色域，还能表现他们不能表现得色彩。人的肉眼能感知的色彩，都能通过Lab模型表现出来。另外，Lab色彩模型的绝妙之处还在于它弥补了RGB色彩模型色彩分布不均的不足，因为RGB模型在蓝色到绿色之间的过渡色彩过多，而在绿色到红色之间又缺少黄色和其他色彩。
3）Lab空间内的很多“颜色”超出了人类视觉的视域，因此纯粹是假想的；这些“颜色”不能在物理世界中再生。通过颜色管理软件，比如内置于图象编辑应用程序中的那些软件，可以选择最接近的色域内近似，在处理中变换亮度、彩度甚至色相。Dan Margulis称，在图象操作的多个步骤之间使用假想色是很有用的。

# 算法思想

SLIC算法时simple linear iterative cluster的简称，主要是将图像从RGB颜色空间转换到CIE-Lab颜色空间，对应每个像素的(L,a,b)颜色值和(x,y)坐标组成一个5维向量V[I,a,b,x,y]，两个像素的相似性即可由他们的向量距离来度量，距离越大，相似性越小。

该算法与K-means聚类算法思路类似，首先生成K个种子点，然后在每个种子点的周围空间里搜索距离该种子点最近的若干像素，将他们归为与该种子点一类，直到所有像素点都归类完毕。然后计算这K个超像素里所有像素点的平均向量值，重新得到K个聚类中心，然后再以这K个中心去搜索其周围与其最为相似的若干像素，所有像素都归类完重新得到K个超像素，更新聚类中心，在此迭代，如此反复直到收敛。

# 具体算法步骤

1.初始化聚类中心：按照预先设定的超像素个数，在图像内均匀的分配聚类中心。如果图像有N个像素点，预分割为K个相同尺寸的超像素，那么每个超像素的大小为N/K，则相邻聚类中心的距离（步长）近似为 S = sqrt(N/K)；
2.在聚类中心的n×n邻域内重新选择聚类中心(一般n取3)。具体方法为：计算该邻域内所有像素点的梯度值，将聚类中心移动到该邻域内梯度最小的地方。这样做的目的是为了避免中心点落在梯度较大1的轮廓边界上，以免影响后续聚类效果；
3.在每个聚类中心周围的邻域内为每个像素点分配类标签(即属于哪个聚类中心)。（期望的超像素尺寸为S×S,但其搜索范围为2S×2S)；
4.计算搜索点到聚类中心的距离度量（包括颜色距离和空间距离）；

其中，d c c 代表颜色距离，d s s 代表空间距离，N s s 是类内最大空间距离，定义N s s =sqrt(N/K),适用于每个聚类，最大颜色距离N c c 随图片不同而不同，也随聚类不同而不同，所以一般取一个固定常数(取值范围[1-40]，一般取10)代替。最终的距离测度D‘如下：

由于每个像素点都会被多个种子点搜索到，所以每个像素点都会有一个与周围种子点的距离，取最小值对应的种子点作为该像素点的聚类中心。
5.直到每个像素点聚类中心不再发生变化停止迭代(实践发现10次迭代绝大部分图片都可以得到较理想效果)；
6.增强连通性：经过上述迭代优化可能会出现出现多连通、超像素尺寸过小，单个超像素被切割为多个不连续超像素等等问题，而这些情况可以通过增强连通性来解决。主要思路在于:新建一张标记表，表内元素均为-1，按照“Z”型走向(从左到右、从上到下顺序)将不连续的超像素、尺寸过小超像素重新分配给临近的超像素，遍历果的像素点分配给相应的标签，直到所有点遍历完毕为止。

# SLIC主要优点

1）生成的超像素如同细胞一般紧凑整齐，邻域特征比较容易表达。这样基于像素的方法可以比较容易的改造为基于超像素的方法。
2）不仅可以分割彩色图，也可以兼容分割灰度图。
3）需要设置的参数非常少，默认情况下只需要设置一个预分割的超像素的数量。
4）相比其他的超像素分割方法，SLIC在运行速度、生成超像素的紧凑度、轮廓保持方面都比较理想。

以下是论文中的效果图

自己实现的效果图：

展开全文
• 本文是研究生课程图像处理期末作业，内容是了解并入门超像素算法原理，主要介绍了超像素的评测标准，经典算法 SLIC，讨论了 SLIC 算法中的不足之处，以及 SLIC 的两个有效的改进算法 SEEDS 和 ETPS。
• SLIC.m为SLIC算法的实现 是一个function函数 FindAroundLine.m是用来将超像素块画边界线的function函数 SLIC.m和FindAroundLine.m都不用运行，把他放在和RunMe同一个路径下就行 注意在运行RunMe.m脚本时，要将...
• 通过OpenCV实现SLIC超分辨率图像重建，极其简单，极其方便，道理浅显易懂。

超像素由一系列位置相邻且颜色、亮度、纹理等特征相似的像素点组成的小区域。这些小区域大多保留了进一步进行图像分割的有效信息，且一般不会破坏图像中物体的边界信息，用少量的超像素代替大量像素表达图像特征，降低了图像处理的复杂度，一般作为分割算法的预处理步骤。

SLIC算法生成的像素块相对紧凑，领域特征容易表达；同时需要设置调整的参数少，操作简单，速度快，对于图像的紧凑度、轮廓保持拥有很好的效果；兼容灰度图和彩色图的分割。

代码如下：

import cv2 as cv

# 初始化slic项，region_size设置分割图片尺寸大小 ruler设置平滑因子
slic = cv.ximgproc.createSuperpixelSLIC(img,region_size=10, ruler=20.0)
slic.iterate(10)    # 设置迭代次数，迭代次数相对来说越大越好
cv.imshow("img_slic", img_slic)
cv.waitKey(0)
cv.imwrite('./SLIC.jpg', img_slic)
cv.destroyAllWindows()



运行结果如下：

代码如下：

import cv2 as cv

# 初始化slic项，region_size设置分割图片尺寸大小 ruler设置平滑因子
slic = cv.ximgproc.createSuperpixelSLIC(img,region_size=10, ruler=20.0)
slic.iterate(10)    # 设置迭代次数，迭代次数相对来说越大越好

cv.waitKey(0)
cv.destroyAllWindows()

cv.waitKey(0)
cv.destroyAllWindows()

cv.imshow("img_slic", img_slic)
cv.waitKey(0)
cv.imwrite('./SLIC.jpg', img_slic)
cv.destroyAllWindows()



其实在我理解OpenCV实现SLIC算法的过程就是先对图像绘制出分割图像，在进行逻辑运算绘制在原图上，对原图实现SLIC超分辨率重建算法。

展开全文
• SLIC算法.pptx
• SLIC图像superpixel的C++代码
• 包括SLIC框架、相关论文介绍、关于SLIC的学习笔记、SLIC分割代码以及示例。
• 超像素（SuperPixel），就是把原本多个像素点，组合成一个大的像素。...在超像素算法方面，SLIC Superpixels Compared to State-of-the-art Superpixel Methods这篇论文非常经典。论文中从算法效率，内存使用以...

超像素（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.

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]

"""

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

ifw+1>=self.image_width:

w=self.image_width-2

ifh+1>=self.image_height:

h=self.image_height-2

self.data[w+1][h+1][1]-self.data[w][h][1]+\

self.data[w+1][h+1][2]-self.data[w][h][2]

defmove_clusters(self):

forclusterinself.clusters:

fordhinrange(-1,2):

fordwinrange(-1,2):

_h=cluster.h+dh

_w=cluster.w+dw

cluster.update(_h,_w,self.data[_h][_w][0],self.data[_h][_w][1],self.data[_h][_w][2])

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次迭代产生的超像素图。

展开全文
• 优化加权核K-means聚类初始中心点的SLIC算法.pdf
• SLIC（simple linear iterative clustering）算法介绍与Python实现 本文转载自：https://blog.csdn.net/shinian1987/article/details/78618917 图像分割是图像处理，计算机视觉领域里非常基础，非常重要的一个...
• MATLAB中有超像素分割算法superpixels函数，https://ww2.mathworks.cn/help/images/ref/superpixels.html?s_tid=doc_ta#bu1_lce-4，原理就是SLIC超像素分割。 1.SLIC超像素分割论文（翻译版） ...
• VLFeat库中SLIC算法代码解读 原作者：Andrea Vedaldi
• 超像素（SuperPixel），就是把原本多个像素点，组合成一个大的像素。...在超像素算法方面，SLIC Superpixels Compared to State-of-the-art Superpixel Methods这篇论文非常经典。论文中从算法效率，内...
• 超像素SLIC算法源码阅读超像素SLIC算法源码阅读SLIC简介源码阅读实验结果 超像素SLIC算法源码阅读 SLIC简介 SLIC的全称Simple Linear Iterative Clustering，即简单线性迭代聚类，论文和代码链接如下： 论文传送...
• 之前有关于SLIC Superpixel算法的个人理解请戳这里，这篇文章是对其改进算法Improved SLIC算法的理解。改进点： sigma filter 用来避免错误分割； 聚类结束后，会基于颜色相似度将小聚类融入临近的聚类中。 改进聚类...
• skimage作为图像处理库，包括多种图像分割算法。其中超像素slic目前表现较好，该部分代码如下。 from skimage.segmentation import slic,mark_boundaries from skimage import io import matplotlib.pyplot as plt ...
• 简介：最近项目使用到了超像素分割，因此顺道研究了以下SLIC这一算法。超像素分割这类low-level vision问题已经在CVPR，ICCV这种顶级会议上逐渐销声匿迹，越来越流行的learning method渐渐占据了这些顶级会议90%的...
• SLIC算法求superpixels的Windows软件，可自行设定superpixels的分割数目
• 前言 像素风最早出现在8bit的电子游戏中，受制于电脑内存大小以及显示色彩单一， 只能使用少量像素来呈现内容，却成就了不少经典的像素游戏。随着内存容量与屏幕...什么是SLIC算法 像素画的绘制之所以不简单，是因
• SLIC算法作为Superpixel中的聚类算法，简单高效，很多算法在预处理都会使用SLIC先对像素进行简单分类，方便之后的操作。
• 其次结合图像的纹理特征提出了一种自适应K值方法,并对图像利用SLIC算法进行粗分割,描绘出乳腺肿块的初始轮廓;最后,利用GVF Snake算法加大对轮廓边缘信息的捕捉范围,进行细分割得到分割结果图。实验验证表明,该分割...
• 读书笔记： http://blog.csdn.net/wishchin/article/details/17415785 转载于:https://www.cnblogs.com/muxiaoruo/p/3630438.html
• 使用超像素的进行图像分割的matlab代码, 若体验良好可以给个好评
• ## fast slic算法

千次阅读 2022-03-07 18:37:19
fast slic算法，速度更快，性能更强的一种边缘检测算法
• 这一篇文章主要介绍了SLIC算法的大致分析和理解，提供了源码，供大家复制下载。 目录 部分代码分析 1.RGB -> XYZ 大致分析： 详细代码： 2.RGB -> LAB 大致分析： 具体代码： 3.将一个图像中的全部点进行二次转化 ...
• 一、算法步骤 1.将输入图像转化为CEILAB空间 2.输入k并计算出S： 3.创造一个以s为间距的网格 4.移动边缘的平均值 5.对图像中的每个像素在2s的邻域内进行搜索，并将该平均值分配给该像素 6.取分配给一个平均数的像素...
• SLIC算法是simple linear iterative cluster的简称，该算法用来生成超像素（superpixel）。 目录 基本思想 实现SLIC算法 1.图像的预处理 2.初始化聚类中心 3.优化初始聚类中心 4.计算像素点与聚类中心的距离 ...

...