SLIC超像素分割详解(一):简介_计算机视觉life的博客-CSDN博客_slic超像素分割
机器学习:simple linear iterative clustering (SLIC) 算法_Matrix_11的博客-CSDN博客_简单线性迭代聚类算法
图像处理: 超像素(superpixels)分割 SLIC算法_haoji007的博客-CSDN博客_超像素分割
图像分割:Python的SLIC超像素分割_程序媛一枚~的博客-CSDN博客_python slic
Python实现超像素分割_技术挖掘者的博客-CSDN博客_python 超像素分割
python 自带slic代码分析_北落师门XY的博客-CSDN博客_python slic
SLIC超像素分割并保存分割得到的超像素块,python代码_LarkMi的博客-CSDN博客_python超像素分割代码
超像素分割, 并获取每一个分区 - 默盒 - 博客园 (cnblogs.com)
SLIC Superpixels ‒ IVRL ‐ EPFL
http://github.com/laixintao/slic-python-implementation
https://github.com/LarkMi/SLIC
徐其钰/MyProject - Gitee.com (超像素分割、边缘检测)
超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术,是指具有相似纹理、颜色、亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块。它利用像素之间特征的相似性将像素分组,用少量的超像素代替大量的像素来表达图片特征,很大程度上降低了图像后处理的复杂度,所以通常作为分割算法的预处理步骤。在像素网格上按照一定的方式进行像素局部分组,可得到超像素。
它已经广泛用于图像分割、姿势估计、目标跟踪、目标识别等计算机视觉应用。几种常见的超像素分割方法及其效果对比如下:
其中,SLIC(simple linear iterativeclustering),即简单的线性迭代聚类。它是2010年提出的一种思想简单、实现方便的算法,将彩色图像转化为CIELAB颜色空间和XY坐标下的5维特征向量,然后对5维特征向量构造距离度量标准,对图像像素进行局部聚类的过程。SLIC算法能生成紧凑、近似均匀的超像素,在运算速度,物体轮廓保持、超像素形状方面具有较高的综合评价。
计算效率高、含有更多感知(有意义的)信息、过度分割可减少像素损失、超像素上表示图形更加高效。
在介绍SLIC之前,插播一下Lab颜色空间的介绍。Lab色彩模型是由亮度(L)和有关色彩的a, b三个要素组成。L表示亮度(Luminosity),L的值域由0(黑色)到100(白色)。a表示从洋红色至绿色的范围(a为负值指示绿色而正值指示品红),b表示从黄色至蓝色的范围(b为负值指示蓝色而正值指示黄色)。
Lab颜色空间的优点:
另外,Lab色彩模型的绝妙之处还在于它弥补了RGB色彩模型色彩分布不均的不足,因为RGB模型在蓝色到绿色之间的过渡色彩过多,而在绿色到红色之间又缺少黄色和其他色彩。如果我们想在数字图形的处理中保留尽量宽阔的色域和丰富的色彩,最好选择Lab。
其中,dc代表颜色距离,ds代表空间距离,Ns是类内最大空间距离,定义为Ns=S=sqrt(N/K),适用于每个聚类。最大的颜色距离Nc既随图片不同而不同,也随聚类不同而不同,所以取一个固定常数m(取值范围[1,40],一般取10)代替。最终的距离度量D'。
由于每个像素点都会被多个种子点搜索到,所以每个像素点都会有一个与周围种子点的距离,取最小值对应的种子点作为该像素点的聚类中心。
- from skimage.segmentation import slic,mark_boundaries
- segments = slic(image, n_segments=60, compactness=10)
-
- # 参数说明:
- # n_segments: 分割块的个数。可能最后分割出的块数与实际设置并不一样,可能是slic算法做了后续处理,将小的超像素合并到大的超像素中。
- # compactness:分割块的边界是否压缩,压缩会使分割快的边沿更光滑。
具体SLIC代码附在文章最后。
项目介绍
SLIC超像素分割并保存分割得到的超像素块,python代码_LarkMi的博客-CSDN博客_python超像素分割代码
完整代码
GitHub - LarkMi/SLIC: SLIC分割并存储分割后的超像素块
- # https://github.com/LarkMi/SLIC/blob/main/SLIC.py
-
- import skimage
- from skimage.segmentation import slic,mark_boundaries
- from skimage import io
- import matplotlib.pyplot as plt
- from PIL import Image, ImageEnhance
- import numpy as np
- import cv2
- #
- # np.set_printoptions(threshold=np.inf)
- path = 'C:\\Users\\Administrator\\Desktop\\SLIC\\'
- img_name = 'test.png'
- img = io.imread(path + img_name,as_gray=True) #as_gray是灰度读取,得到的是归一化值
- segments = slic(img, n_segments=10, compactness=0.2,start_label = 1)#进行SLIC分割
- out=mark_boundaries(img,segments)
- out = out*255 #io的灰度读取是归一化值,若读取彩色图片去掉该行
- img3 = Image.fromarray(np.uint8(out))
- img3.show()
- seg_img_name = 'seg.png'
- img3.save(path +'\\' +seg_img_name)#显示并保存加上分割线后的图片
-
- maxn = max(segments.reshape(int(segments.shape[0]*segments.shape[1]),))
- for i in range(1,maxn+1):
- a = np.array(segments == i)
- b = img * a
- w,h = [],[]
- for x in range(b.shape[0]):
- for y in range(b.shape[1]):
- if b[x][y] != 0:
- w.append(x)
- h.append(y)
-
- c = b[min(w):max(w),min(h):max(h)]
- c = c*255
- d = c.reshape(c.shape[0],c.shape[1],1)
- e = np.concatenate((d,d),axis=2)
- e = np.concatenate((e,d),axis=2)
- img2 = Image.fromarray(np.uint8(e))
- img2.save(path +'\\'+str(i)+'.png')
- print('已保存第' + str(i) + '张图片')
-
- wid,hig = [],[]
- img = io.imread(path+'\\'+seg_img_name)
-
- for i in range(1,maxn+1):
- w,h = [],[]
- for x in range(segments.shape[0]):
- for y in range(segments.shape[1]):
- if segments[x][y] == i:
- w.append(x)
- h.append(y)
-
-
- font=cv2.FONT_HERSHEY_SIMPLEX#使用默认字体
- #print((min(w),min(h)))
- img=cv2.putText(img,str(i),(h[int(len(h)/(2))],w[int(len(w)/2)]),font,1,(255,255,255),2)#添加文字,1.2表示字体大小,(0,40)是初始的位置,(255,255,255)表示颜色,2表示粗细
- img = Image.fromarray(np.uint8(img))
- img.show()
- img.save(path +'\\'+seg_img_name+'_label.png')
效果展示:
超像素分割, 并获取每一个分区 - 默盒 - 博客园 (cnblogs.com)
- from skimage.segmentation import slic
- from skimage.segmentation import mark_boundaries
- from skimage.util import img_as_float
- import matplotlib.pyplot as plt
- import numpy as np
- import cv2
-
-
- # args
- args = {"image": './hand_0.png'}
-
- # load the image and apply SLIC and extract (approximately)
- # the supplied number of segments
- image = cv2.imread(args["image"])
- segments = slic(img_as_float(image), n_segments=100, sigma=5)
-
- # show the output of SLIC
- fig = plt.figure('Superpixels')
- ax = fig.add_subplot(1, 1, 1)
- ax.imshow(mark_boundaries(img_as_float(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), segments))
- plt.axis("off")
- plt.show()
- print("segments:\n", segments)
- print("np.unique(segments):", np.unique(segments))
- # loop over the unique segment values
- for (i, segVal) in enumerate(np.unique(segments)):
- # construct a mask for the segment
- print("[x] inspecting segment {}, for {}".format(i, segVal))
- mask = np.zeros(image.shape[:2], dtype="uint8")
- mask[segments == segVal] = 255
-
- # show the masked region
- cv2.imshow("Mask", mask)
- cv2.imshow("Applied", np.multiply(image, cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) > 0))
- cv2.waitKey(0)
-
项目介绍 & 效果展示
python 超像素分割_Afleve的博客-CSDN博客_python超像素
代码
opencv/超像素分割 · 徐其钰/MyProject - 码云 - 开源中国 (gitee.com)
Python实现超像素分割_技术挖掘者的博客-CSDN博客_python 超像素分割
- # import the necessary packages
- from skimage.segmentation import slic
- from skimage.segmentation import mark_boundaries
- from skimage.util import img_as_float
- from skimage import io
- import matplotlib.pyplot as plt
-
-
- # load the image and convert it to a floating point data type
- image = img_as_float(io.imread("image.jpg"))
-
- # loop over the number of segments
- for numSegments in (100, 200, 300):
- # apply SLIC and extract (approximately) the supplied number
- # of segments
- segments = slic(image, n_segments = numSegments, sigma = 5)
-
- # show the output of SLIC
- fig = plt.figure("Superpixels -- %d segments" % (numSegments))
- ax = fig.add_subplot(1, 1, 1)
- ax.imshow(mark_boundaries(image, segments))
- plt.axis("off")
-
- # show the plots
- plt.show()
效果展示:通过超像素分割我们可以将整个图像划分为含有固定个超像素组的感知块,具体如图中的黄色块所示。
- %% Clean up
- clear all
- close all
- clc
-
- %Generate image
- img = imread('test.jpg');
- img = double(rgb2gray(img));
-
- %Invert circle brightness
- img = abs(img-1);
-
- %Blur original image with Gaussian kernel with a blur width (standard
- %deviaion) of 0.9 pixels
- BlurGaussian = 0.9;
- G = fspecial('Gaussian',5,BlurGaussian);
- img = imfilter(img,G,'replicate');
-
- %Blurring occurs from quantization and from Gaussian
- BlurQuantization = 1/sqrt(12);
- BlurWidth = sqrt( BlurQuantization^2 + BlurGaussian^2);
-
- %% Create mask
- %Only consider edges on columns 35-50
- M = true(size(img));
-
- %% Perform edge localization
- %Get pixel-level edges with Sobel operator
- [E] = edge(img,'sobel');
-
- %Refine to subpixel accuracy
- edges = SubpixelEdge(img,E,BlurWidth,M);
-
-
- %% Plot results
- %Show image
- figure(1);
- imshow(uint8(img)),hold on, axis on;
- plot(edges.u,edges.v,'co')
-
- figure(2);
- imshow(uint8(M)),hold on, axis on;
- plot(edges.u,edges.v,'co')
-
- % p1 = [edges.u(1), edges.v(1), 0];
- % p2 = [edges.u(100), edges.v(100), 0];
- % p3 = [edges.u(500), edges.v(500), 0];
- % p = CircleCenter(p1, p2, p3);
- %
- % disp('当前圆的半径为%d', p);
-
- x=edges.u;
- y=edges.v;
- [R,x0,y0]=circ(x,y,edges.NumPts-1);
- disp(['第一个圆的半径是: ' num2str(R),' mm' ]);
- disp(['第一个圆的圆心坐标:( ' num2str(x0) ,',',num2str(y0),')']);
- plot(x0, y0, 'gx');
效果展示:超像素可以准确的检测出齿轮的边缘信息,包括它的内环和外环信息。
详见 superpixels ‒ IVRL ‐ EPFL ,里面列举很多使用超像素算法的论文工作。包括有视频检测、无人机数据对齐、语义分割、目标跟踪、3d重建、数据增强、水印恢复,等等。
IEEE TIP 2014年 的《Robust superpixeltracking》,基于超像素的方法解决外观发生剧烈变化的物体追踪问题。
ICCV 2009年 的《Class segmentation andobject localization with superpixel neighborhoods》,从像素级别的分割迁移到超像素级别的分割。
CVPR 2013年的《Improving an objectdetector and extracting regions using superpixels》,把样本中超像素级的特征通过k-means聚类为超像素级词袋,再结合SVM对难分类样本进一步分类。
IET 2014年的 《Video object segmentation with shape cue based on spatiotemporal superpixel neighbourhood》,用于视频前景分割。
JEI 2015年的《Improving video foreground segmentation with an object-like pool》,在无监督条件下对序列图像中运动目标进行精细的分割。
ECCV 2022年 的 《SPSN: Superpixel Prototype Sampling Network for RGB-D Salient Object Detection》,用超像素分割做显著性检测。
使用超像素对图像进行分割时,设置的超像素数目K比较重要:如果K比较小,每个超像素尺寸会比较大,这样超像素对边界的保持就会变差,如果K比较大,每个超像素的尺寸会比较小,那么会出现类似“过拟合”现象,超像素的形状会变得非常不规则,邻域关系很难保持,而且数目也比较多。
具体分割数目K和具体应用有关,比如如果对上图做主要人物(左边的小魔女)分割的话,100X100大小的超像素就够了,但是如果对两个骑自行的人物也进行分割的话,需要使用30X30的尺寸,但是此时较小人物的分割精度不高,如果有更高要求,则需要使用8X8甚至更小的尺寸。尺寸也需要根据不同场合选择。
封装工具、C++、Matlab代码:SLIC Superpixels ‒ IVRL ‐ EPFL
1、设定期望分割的超像素数目,打开图片。将彩色RGB图片转换为LAB空间及x、y像素坐标共5维空间。
2、DetectLabEdges。求图片中所有点的梯度=dx+dy.其中
dx=(l(x-1)-l(x+1))*(l(x-1)-l(x+1))+(a(x-1)-a(x+1))*(a(x-1)-a(x+1))+(b(x-1)-b(x+1))*(b(x-1)-b(x+1));
dy=(l(y-1)-l(y+1))*(l(y-1)-l(y+1))+(a(y-1)-a(y+1))*(a(y-1)-a(y+1))+(b(y-1)-b(y+1))*(b(y-1)-b(y+1));
3、GetLABXYSeeds_ForGivenK。给定了要分割的超像素总数K,根据LABXY信息获得种子点。
1) 超像素的种子点间步长Step=sqrt(N/K)。初始化种子点。按照步长均匀播撒种子点,初始化后种子点是均匀分布的(图1中的红色点)。
2) PerturbSeeds。扰乱种子点。在每个种子点的3*3邻域内,计算该种子点的8个邻域内像素点的Lab颜色梯度(同上述步骤2),分别与初始种子点梯度进行比较,取梯度值最小(最“平坦”)的点,并记录其LABXY信息作为新的种子点(图1中绿色点为扰乱后的新种子点)。
4、超像素的步长Step=sqrt(N/K)+2。加了一个小偏置2是为了避免Step太小,造成超像素太密集的情况。
5、PerformSuperpixelSegmentation_VariableSandM。对于每个超像素,最大的颜色距离M取值范围[1,40],一般取10。最大空间距离取步长为Step。
6、EnforceLabelConnectivity。该函数主要有几个作用:保证同一个超像素都是单连通区域;去掉尺寸过小的超像素;避免单个超像素被切割的情况。
7、绘制分割结果,退出窗口。
超像素算法将像素组合成感知有意义的原子区域( atomic regions),其可以用于替换像素网格的刚性结构。它们捕获图像冗余,提供计算图像特征的方便原语( primitive ),并且大大降低了后续图像处理任务的复杂性。用下面三点来判断算法的优劣性:
论文列举其他超像素方法,再提出SLIC算法进行对比。
用于生成超像素的算法可以大致分类为基于图或梯度上升的方法。
基于图形的超像素生成方法将每个像素视为图中的节点。两个节点之间的边权重与相邻像素之间的相似性成比例。超像素通过最小化图中定义的成本函数来创建。
NC05,归一化切割算法递归地使用轮廓和纹理线索分割图像中的所有像素的图形,从而全局性地最小化在分割边界处的边缘定义的成本函数。它产生非常规则,视觉上令人愉快的超像素。然而,NC05的边界粘附相对较差,并且它是方法中最慢的(特别是对于大图像),尽管试图加速的算法存在。NC05具有的复杂度,其中N是像素的数量。
GS04,提出了一种替代的基于图形的方法,已被应用于生成超像素。它将像素作为图的节点,使得每个超像素是组成像素的最小生成树。GS04在实践中很好地粘附到图像边界,但是产生具有非常不规则的尺寸和形状的超像素。它的复杂度是,在实践中速度很快。然而,它不提供对超像素的量或其紧凑性的明确控制。
SL08,提出了一种通过确定将图像分割成更小的垂直或水平区域的最佳路径或接缝来生成符合网格的超像素的方法。使用类似于SeamCarving的图切割方法找到最佳路径。复杂的是,但这并不考虑预先计算的边界图,这强烈影响输出的质量和速度。
GCa10和GCb10。使用纹理合成工作的全局优化方法。通过将重叠的图像块拼接在一起来获得超像素,使得每个像素仅属于重叠区域中的一个。这个方法有两个变种,一个用于生成紧凑超像素(GCa10),一个用于恒定强度超像素(GCb10)。
从粗略的像素初始聚类开始,梯度上升法迭代地修改聚类,直到满足一些收敛标准以形成超像素。
MS02,平均偏移,用于定位密度函数的局部最大值的迭代模式寻找过程被应用于图像的颜色或强度特征空间中的第一模式。会聚到相同模式的像素定义超像素。MS02是一种较旧的方法,产生不均匀尺寸的不规则形状的超像素。它是复杂度,使其相对较慢,并且不提供对超像素的量,尺寸或紧密度的直接控制。
QS08,也使用模式查找分割方案。它使用medoid移位过程初始化分割。然后将特征空间中的搜索点移动到最近的邻居,从而增加Parzen密度估计。虽然它具有相对良好的边界粘附,但是QS08的运行速度相当缓慢,具有复杂度(d是一个小常数)。而且QS08不允许对超像素的大小或数量的显式控制。
WS91,从局部最小值开始执行梯度上升以产生分水岭,和分离集水盆地的线条。所得到的超像素在尺寸和形状上通常是高度不规则的,并且不表现出良好的边界粘附。具有的复杂度),但不提供对超像素量或其紧凑性的控制。
TP09,使用基于水平集的几何流动逐渐扩大一组种子位置。几何流依赖于局部图像梯度,目的是在图像平面上规则地分布超像素。与WS91不同,TP09超像素被约束为具有均匀的尺寸,紧凑性和边界粘附。TP09依赖于不同复杂度的算法,但在实践中,如作者所声称的,具有大约的复杂度,是所检查的最慢的算法之一,并且表现出相对较差的边界粘附。
比现有方法更快,更高的记忆效率,展示了目前最优的边界依从性,并提高了分割算法的性能。简单线性迭代聚类(SLIC)采用K均值算法生成超像素,相较与其他算法具有两个重要的区别:
1)通过将搜索空间限制为与超像素大小成比例的区域,显着地减少了优化中的距离计算的数量。这降低了像素数N的线性复杂度,并且与超像素k的数量无关。
2)加权距离度量组合颜色和空间接近度,同时提供对超像素的尺寸和紧凑性的控制。
SLiC使用简单,其唯一的参数是所需的超像素数,是产生超体素的为数不多的方法之一。最后,在现有的方法中,SLIC的独特之处在于它能够通过m来控制超像素紧密性和边界粘着性之间的权衡。
-
- def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=0,
- spacing=None, multichannel=True, convert2lab=None,
- enforce_connectivity=True, min_size_factor=0.5, max_size_factor=3,
- slic_zero=False):
- """Segments image using k-means clustering in Color-(x,y,z) space.
- Parameters
- ----------
- image : 2D, 3D or 4D ndarray
- Input image, which can be 2D or 3D, and grayscale or multichannel
- (see `multichannel` parameter).
- n_segments : int, optional
- The (approximate) number of labels in the segmented output image.
- compactness : float, optional
- 控制颜色和空间之间的平衡,约高越方块,和图关系密切,最好先确定指数级别,再微调
- Balances color proximity and space proximity. Higher values give
- more weight to space proximity, making superpixel shapes more
- square/cubic. In SLICO mode, this is the initial compactness.
- This parameter depends strongly on image contrast and on the
- shapes of objects in the image. We recommend exploring possible
- values on a log scale, e.g., 0.01, 0.1, 1, 10, 100, before
- refining around a chosen value.
- max_iter : int, optional
- 最大k均值迭代次数
- Maximum number of iterations of k-means.
- sigma : float or (3,) array-like of floats, optional
- 图像每个维度进行预处理时的高斯平滑核宽。若给定为标量值,则同一个值运用到各个维度。0意味
- 着不平滑。如果“sigma”是标量的,并且提供了手动体素间距,则自动缩放它(参见注释部分)。
- Width of Gaussian smoothing kernel for pre-processing for each
- dimension of the image. The same sigma is applied to each dimension in
- case of a scalar value. Zero means no smoothing.
- Note, that `sigma` is automatically scaled if it is scalar and a
- manual voxel spacing is provided (see Notes section).
- spacing : (3,) array-like of floats, optional
- 代表沿着图像每个维度的体素空间。默认情况下,slic假定均匀的空间(沿x,y,z轴相同的体素分辨
- 率),这个参数控制在k均值聚类中各轴距离的权重
- The voxel spacing along each image dimension. By default, `slic`
- assumes uniform spacing (same voxel resolution along z, y and x).
- This parameter controls the weights of the distances along z, y,
- and x during k-means clustering.
- multichannel : bool, optional
- 二进制参数,代表图像的最后一个轴代表多通道还是另一个空间维度
- Whether the last axis of the image is to be interpreted as multiple
- channels or another spatial dimension.
- convert2lab : bool, optional
- 二进制参数,判断输入需要在分割之前转到LAB颜色空间。输入必须是RGB。当多通道参数为True,
- 输入图片的通道数为3时,该参数默认为True
- Whether the input should be converted to Lab colorspace prior to
- segmentation. The input image *must* be RGB. Highly recommended.
- This option defaults to ``True`` when ``multichannel=True`` *and*
- ``image.shape[-1] == 3``.
- enforce_connectivity: bool, optional
- 二进制参数,控制生成的分割块连接或不连接
- Whether the generated segments are connected or not
- min_size_factor: float, optional
- 与分割目标数有关的要删去的最小分割块比率,(大概是小于长*宽*高/目标数量 的分割结果会被融
- 合掉)
- Proportion of the minimum segment size to be removed with respect
- to the supposed segment size ```depth*width*height/n_segments```
- max_size_factor: float, optional
- 最大融合比率上限
- Proportion of the maximum connected segment size. A value of 3 works
- in most of the cases.
- slic_zero: bool, optional
- 不知所谓的零参数
- Run SLIC-zero, the zero-parameter mode of SLIC. [2]_
- Returns
- -------
- labels : 2D or 3D array
- Integer mask indicating segment labels.
- Raises
- ------
- ValueError
- If ``convert2lab`` is set to ``True`` but the last array
- dimension is not of length 3.
- Notes
- -----
- * If `sigma > 0`, the image is smoothed using a Gaussian kernel prior to
- segmentation.
- * If `sigma` is scalar and `spacing` is provided, the kernel width is
- divided along each dimension by the spacing. For example, if ``sigma=1``
- and ``spacing=[5, 1, 1]``, the effective `sigma` is ``[0.2, 1, 1]``. This
- ensures sensible smoothing for anisotropic images.
- 如果有平滑参数sigma和体素空间参数spacing,那么空间体素参数会对平滑参数有平分的影响,比如
- 1/[5,1,1]=[0.2,1,1]
- * The image is rescaled to be in [0, 1] prior to processing.
- 图像在预处理之前会被处理为[0,1]之间的标量
- * Images of shape (M, N, 3) are interpreted as 2D RGB images by default. To
- interpret them as 3D with the last dimension having length 3, use
- `multichannel=False`.
- (M,N,3)的图像默认为2维(RGB的图像),要想被理解为3维图需要设置多通道参数=False
- References
- ----------
- .. [1] Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi,
- Pascal Fua, and Sabine Süsstrunk, SLIC Superpixels Compared to
- State-of-the-art Superpixel Methods, TPAMI, May 2012.
- .. [2] http://ivrg.epfl.ch/research/superpixels#SLICO
- Examples
- --------
- >>> from skimage.segmentation import slic
- >>> from skimage.data import astronaut
- >>> img = astronaut()
- >>> segments = slic(img, n_segments=100, compactness=10)
- Increasing the compactness parameter yields more square regions:
- >>> segments = slic(img, n_segments=100, compactness=20)
- """
- ###############################################干正事啦
-
- image = img_as_float(image)
- is_2d = False
- #2D灰度图
- if image.ndim == 2:
- # 2D grayscale image
- image = image[np.newaxis, ..., np.newaxis]
- is_2d = True
-
- #比如2D RGB的图
- elif image.ndim == 3 and multichannel:
- # Make 2D multichannel image 3D with depth = 1
- image = image[np.newaxis, ...]
- is_2d = True
-
-
- #比如3D图
- elif image.ndim == 3 and not multichannel:
- # Add channel as single last dimension
- image = image[..., np.newaxis]
-
- #控制聚类时各轴权重
- if spacing is None:
- spacing = np.ones(3)
- elif isinstance(spacing, (list, tuple)):
- spacing = np.array(spacing, dtype=np.double)
-
- #高斯平滑
- if not isinstance(sigma, coll.Iterable):
- sigma = np.array([sigma, sigma, sigma], dtype=np.double)
- sigma /= spacing.astype(np.double)#有可能发生的体素除
- elif isinstance(sigma, (list, tuple)):
- sigma = np.array(sigma, dtype=np.double)
-
- #高斯滤波处
- if (sigma > 0).any():
- # add zero smoothing for multichannel dimension
- sigma = list(sigma) + [0]
- image = ndi.gaussian_filter(image, sigma)
-
- #多通道RGB图且需要转lab,用rab2lab即可实现
- if multichannel and (convert2lab or convert2lab is None):
- if image.shape[-1] != 3 and convert2lab:
- raise ValueError("Lab colorspace conversion requires a RGB image.")
- elif image.shape[-1] == 3:
- image = rgb2lab(image)
-
- depth, height, width = image.shape[:3]
-
- # initialize cluster centroids for desired number of segments
- #为实现目标分割块数,初始化聚类中心。
- #grid_* 相当于index
- #slices是根据目标数量分的块,有取整需要
- grid_z, grid_y, grid_x = np.mgrid[:depth, :height, :width]
- slices = regular_grid(image.shape[:3], n_segments)
- step_z, step_y, step_x = [int(s.step if s.step is not None else 1)
- for s in slices]
- segments_z = grid_z[slices]
- segments_y = grid_y[slices]
- segments_x = grid_x[slices]
-
- segments_color = np.zeros(segments_z.shape + (image.shape[3],))
- segments = np.concatenate([segments_z[..., np.newaxis],
- segments_y[..., np.newaxis],
- segments_x[..., np.newaxis],
- segments_color],
- axis=-1).reshape(-1, 3 + image.shape[3])
- segments = np.ascontiguousarray(segments)
-
- # we do the scaling of ratio in the same way as in the SLIC paper
- # so the values have the same meaning
- step = float(max((step_z, step_y, step_x)))
- ratio = 1.0 / compactness
-
- #我类个去,分割时方不方的骚操作
- image = np.ascontiguousarray(image * ratio)
-
- labels = _slic_cython(image, segments, step, max_iter, spacing, slic_zero)
-
- #把过小过小的处理一下
- if enforce_connectivity:
- segment_size = depth * height * width / n_segments
- min_size = int(min_size_factor * segment_size)
- max_size = int(max_size_factor * segment_size)
- labels = _enforce_label_connectivity_cython(labels,
- min_size,
- max_size)
-
- if is_2d:
- labels = labels[0]
-
- return labels