都不说原理了网上一搜一大堆 关键是你要复现哇
SLIC
两个代码实现,如果你想换图只要改一下自己图片的路径就行直接跑
第一个:
import math
from skimage import io, color
import numpy as np
from tqdm import trange
#少了那个库 自己pip install 安装
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]
"""
rgb = io.imread(path)
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
def get_gradient(self, h, w):
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]
return gradient
def move_clusters(self):
for cluster in self.clusters:
cluster_gradient = self.get_gradient(cluster.h, cluster.w)
for dh in range(-1, 2):
for dw in range(-1, 2):
_h = cluster.h + dh
_w = cluster.w + dw
new_gradient = self.get_gradient(_h, _w)
if new_gradient < cluster_gradient:
cluster.update(_h, _w, self.data[_h][_w][0], self.data[_h][_w][1], self.data[_h][_w][2])
cluster_gradient = new_gradient
def assignment(self):
for cluster in 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): #这个就迭代了十次每次结果都保存在当前路径下的png文件了
self.assignment()
self.update_cluster()
name = 'M{m}_K{k}_loop{loop}.png'.format(loop=i, m=self.M, k=self.K)
self.save_current_image(name)
p = SLICProcessor('路径', 200, 40)
p.iterate_10times()
第二个方法:
这个 是python自带的库写的,需要改什么参数可以自己百度slic函数查询
from skimage.segmentation import slic,mark_boundaries
from skimage import io
import matplotlib.pyplot as plt
img = io.imread("图片路径X01_1_0000000250.jpg")
segments = slic(img, n_segments=60, compactness=10)
out=mark_boundaries(img,segments)
plt.title("n_segments=60")
plt.imshow(out)
plt.show()
我结果 我在jupyter notebook 跑的
FCM
import random
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#from sklearn import datasets
m=2
class FCM:
def __init__(self, data, clust_num,iter_num=10):
self.data = data
self.cnum = clust_num
self.sample_num=data.shape[0]
self.dim = data.shape[-1] # 数据最后一维度数
Jlist=[] # 存储目标函数计算值的矩阵
U = self.Initial_U(self.sample_num, self.cnum)
for i in range(0, iter_num): # 迭代次数默认为10
C = self.Cen_Iter(self.data, U, self.cnum)
U = self.U_Iter(U, C)
print("第%d次迭代" %(i+1) ,end="")
print("聚类中心",C)
J = self.J_calcu(self.data, U, C) # 计算目标函数
Jlist = np.append(Jlist, J)
self.label = np.argmax(U, axis=0) # 所有样本的分类标签
self.Clast = C # 最后的类中心矩阵
self.Jlist = Jlist # 存储目标函数计算值的矩阵
# 初始化隶属度矩阵U
def Initial_U(self, sample_num, cluster_n):
U = np.random.rand(sample_num, cluster_n) # sample_num为样本个数, cluster_n为分类数
row_sum = np.sum(U, axis=1) # 按行求和 row_sum: sample_num*1
row_sum = 1 / row_sum # 该矩阵每个数取倒数
U = np.multiply(U.T, row_sum) # 确保U的每列和为1 (cluster_n*sample_num).*(sample_num*1)
return U # cluster_n*sample_num
# 计算类中心
def Cen_Iter(self, data, U, cluster_n):
c_new = np.empty(shape=[0, self.dim]) # self.dim为样本矩阵的最后一维度
for i in range(0, cluster_n): # 如散点的dim为2,图片像素值的dim为1
u_ij_m = U[i, :] ** m # (sample_num,)
sum_u = np.sum(u_ij_m)
ux = np.dot(u_ij_m, data) # (dim,)
ux = np.reshape(ux, (1, self.dim)) # (1,dim)
c_new = np.append(c_new, ux / sum_u, axis=0) # 按列的方向添加类中心到类中心矩阵
return c_new # cluster_num*dim
# 隶属度矩阵迭代
def U_Iter(self, U, c):
for i in range(0, self.cnum):
for j in range(0, self.sample_num):
sum = 0
for k in range(0, self.cnum):
temp = (np.linalg.norm(self.data[j, :] - c[i, :]) /
np.linalg.norm(self.data[j, :] - c[k, :])) ** (
2 / (m - 1))
sum = temp + sum
U[i, j] = 1 / sum
return U
# 计算目标函数值
def J_calcu(self, data, U, c):
temp1 = np.zeros(U.shape)
for i in range(0, U.shape[0]):
for j in range(0, U.shape[1]):
temp1[i, j] = (np.linalg.norm(data[j, :] - c[i, :])) ** 2 * U[i, j] ** m
J = np.sum(np.sum(temp1))
print("目标函数值:%.2f" %J)
return J
# 打印聚类结果图
def plot(self):
mark = ['or', 'ob', 'og', 'om', 'oy', 'oc'] # 聚类点的颜色及形状
if self.dim == 2:
#第一张图
plt.subplot(221)
plt.plot(self.data[:, 0], self.data[:, 1],'ob',markersize=2)
plt.title('未聚类前散点图')
#第二张图
plt.subplot(222)
j = 0
for i in self.label:
plt.plot(self.data[j:j + 1, 0], self.data[j:j + 1, 1], mark[i],
markersize=2)
j += 1
plt.plot(self.Clast[:, 0], self.Clast[:, 1], 'k*', markersize=7)
plt.title("聚类后结果")
# 第三张图
plt.subplot(212)
plt.plot(self.Jlist, 'g-', )
plt.title("目标函数变化图",)
plt.show()
elif self.dim==1:
plt.subplot(221)
plt.title("聚类前散点图")
for j in range(0, self.data.shape[0]):
plt.plot(self.data[j, 0], 'ob',markersize=3) # 打印散点图
plt.subplot(222)
j = 0
for i in self.label:
plt.plot(self.data[j:j + 1, 0], mark[i], markersize=3)
j += 1
plt.plot([0]*self.Clast.shape[0],self.Clast[:, 0], 'k*',label='聚类中心',zorder=2)
plt.title("聚类后结果图")
plt.legend()
# 第三张图
plt.subplot(212)
plt.plot(self.Jlist, 'g-', )
plt.title("目标函数变化图", )
plt.show()
elif self.dim==3:
# 第一张图
fig = plt.figure()
ax1 = fig.add_subplot(221, projection='3d')
ax1.scatter(self.data[:, 0], self.data[:, 1],self.data[:,2], "b")
ax1.set_xlabel("X 轴")
ax1.set_ylabel("Y 轴")
ax1.set_zlabel("Z 轴")
plt.title("未聚类前的图")
# 第二张图
ax2 = fig.add_subplot(222, projection='3d')
j = 0
for i in self.label:
ax2.plot(self.data[j:j+1, 0], self.data[j:j+1, 1],self.data[j:j+1,2], mark[i],markersize=5)
j += 1
ax2.plot(self.Clast[:, 0], self.Clast[:, 1], self.Clast[:, 2], 'k*', label='聚类中心', markersize=8)
plt.legend()
ax2.set_xlabel("X 轴")
ax2.set_ylabel("Y 轴")
ax2.set_zlabel("Z 轴")
plt.title("聚类后结果")
# # 第三张图
plt.subplot(212)
plt.plot(self.Jlist, 'g-', )
plt.title("目标函数变化图", )
plt.show()
def example0():
N=1000
C=[[N/4,N/2,0,N/2],[N/2,N,0,N/2],[N/4,N/2,N/2,N],[N/2,N,N/2,N]]
data=[]
for i in range(4):
center_datanum=random.randint(20,50)
for j in range(center_datanum):
change=random.randint(20,100)
x=random.randint(C[i][0]+change,C[i][1]-change)
y=random.randint(C[i][2]+change,C[i][3]-change)
data.append([x,y])
data=np.mat(data)
a=FCM(data,4,20)
a.plot()
def example1():
x1 = np.zeros((10, 1))
x2 = np.zeros((10, 1))
for i in range(0, 10):
x1[i] = np.random.rand() * 5
x2[i] = np.random.rand() * 5 + 5
x = np.append(x1, x2, axis=0)
a = FCM(x, 2,20)
a.plot()
def example2():
x1 = np.zeros((10, 1))
y1 = np.zeros((10, 1))
x2 = np.zeros((10, 1))
y2 = np.zeros((10, 1))
x3 = np.zeros((10, 1))
y3 = np.zeros((10, 1))
for i in range(0, 10):
x1[i] = np.random.rand() * 5
y1[i] = np.random.rand() * 5
x2[i] = np.random.rand() * 5 + 5
y2[i] = np.random.rand() * 5 + 5
x3[i] = np.random.rand() * 0.5 + 1
y3[i] = np.random.rand() * 0.5 + 1
x = np.append(x1, x2, axis=0)
x = np.append(x, x3, axis=0)
y = np.append(y1, y2, axis=0)
y = np.append(y, y3, axis=0)
data = np.append(x, y, axis=1)
a = FCM(data, 3,20) # 将数据分为三类
a.plot() # 打印结果图
def example3():
x1 = np.zeros((10, 1))
y1 = np.zeros((10, 1))
z1= np.zeros((10, 1))
x2 = np.zeros((10, 1))
y2 = np.zeros((10, 1))
z2 = np.zeros((10, 1))
x3 = np.zeros((10, 1))
y3 = np.zeros((10, 1))
z3 = np.zeros((10, 1))
for i in range(0, 10):
x1[i] = np.random.rand() * 5
y1[i] = np.random.rand() * 5
z3[i] = np.random.rand() * 5
x2[i] = np.random.rand() * 5 + 5
y2[i] = np.random.rand() * 5 + 5
z2[i] = np.random.rand() * 5+5
x3[i] = np.random.rand() * 0.5 + 1
y3[i] = np.random.rand() * 0.5 + 1
z3[i] = np.random.rand() * 0.5 + 3
x = np.append(x1, x2, axis=0)
x = np.append(x, x3, axis=0)
y = np.append(y1, y2, axis=0)
y = np.append(y, y3, axis=0)
z = np.append(z1, z2, axis=0)
z = np.append(z, z3, axis=0)
data = np.append(x, y, axis=1)
print(data.shape)
data=np.append(data,z,axis=1)
a = FCM(data, 3,20) # 将数据分为三类
a.plot() # 打印结果图
if __name__ == '__main__':
example0()
#example1()
#example2()
#example3()
import matplotlib.pyplot as plt
import cv2
from FCMTEST import FCM
import numpy as np
def FCM_pic_cut0(img_path,gray=False,clustercenternum,iternum):
#def FCM_pic_cut0(img_path,gray=False,clustercenternum=5,iternum=10):
if gray:
img=cv2.imread(img_path,0) #灰度图
data=img.reshape(img.shape[0]*img.shape[1],1) #将图片拉成一列
else:
img=cv2.imread(img_path)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #转化为RGB,不然plt时图片会怪怪的
data=img.reshape(-1,3) # 将三维降成二维
print("开始聚类")
test=FCM(data,clustercenternum,iternum)
cluster=test.label # 聚类结果
center=test.Clast # 聚类中心
print("聚类完成,开始生成图片")
new_img=center[cluster] # 根据聚类结果和聚类中心构建新图像
new_img=np.reshape(new_img,img.shape) #矩阵转成原来图片的形状
new_img=new_img.astype('uint8') # 要变成图像得数据得转换成uint8
if gray:
plt.subplot(121), plt.imshow(img, cmap="gray"), plt.title("原图") # plt默认显示三通道,灰度图要加个cmap="gray",不然图片绿绿的。。
plt.subplot(122), plt.imshow(new_img, cmap="gray"), plt.title("FCM,%d个聚类中心"%clustercenternum)
else :
plt.subplot(121), plt.imshow(img), plt.title("原图")
plt.subplot(122), plt.imshow(new_img), plt.title("FCM,%d个聚类中心"%clustercenternum)
plt.show()
#plt.imsave("cutgray.jpg",new_img) # 保存图片
if __name__ == '__main__':
FCM_pic_cut0("地址",gray=False,clustercenternum=15)