基于K-means的图像分割(三类)(Python不调包实现)
发布时间
阅读量:
阅读量
本文是课程《智能图像分析》课程的一次编程作业,基于K-means的原理,从零开始尝试编程,用了七个小时,由于没有Python基础,基本是上一步一步往下走,因此代码存在冗长和不足,望读者进行甄别和改进。
作业内容

关于K-means聚类原理不再赘述,代码实现如下。
代码实现
import cv2
import numpy as np
img = cv2.imread('图像位置')#读图
#显示图像
#cv2.imshow("Image", img)
#cv2.waitKey (0)
########## Begin ##########
import random #用于随机生成初始聚类中心
#计算两个像素点之间的欧氏距离
def distance(x,y):
dist=np.linalg.norm(x-y)
return dist
#将图像矩阵变换为样本数量*特征数量的形式
X=img.reshape(-1,3)
#建立像素标签矩阵及存储三个聚类中心的矩阵
total=img.shape[0]*img.shape[1]
label=np.zeros((total,1))
#选取初始聚类中心(通过随机选择样本位置且保证不重复)
center1 = random.randint(0,total)
while True:
center2 = random.randint(0,total)
if center2!=center1:
break
while True:
center3=random.randint(0,total)
if center3!=center1 and center3!=center2:
break
C=[[X[center1]],[X[center2]],[X[center3]]]
#k均值循环
label = np.array(label)#这是debug过程发现的,需要转换格式才能进行运算
label=label.T#同样,为了方便表示,把它变成行矩阵
sum=0
k=3
label=label.flatten()
while sum<10:
#遍历所有的样本
sum=sum+1
for i in range(total):
#初始最小距离
min_dist = 100000
#对于每个点找到它当前最近的簇心
for j in range(0,k):
dist=distance(X[i],C[j])
if dist<min_dist:
min_dist=dist
label[i]=j+1
#分开各类并计数(后面输出图像会用)
index1 = np.where(label ==1)
len1=np.size(index1)
index2 = np.where(label ==2)
len2=np.size(index2)
index3 = np.where(label ==3)
len3=np.size(index3)
index1 = np.array(index1,dtype=int)
index1=index1.flatten()
index2 = np.array(index2,dtype=int)
index2=index2.flatten()
index3 = np.array(index3,dtype=int)
index3=index3.flatten()
ln = np.array([len1,len2,len3])
计算新的簇心位置
for u in range(k):
if u==0:
X1=np.zeros((len1,3))
index=index1
elif u==1:
X1=np.zeros((len2,3))
index=index2
else:
X1=np.zeros((len3,3))
index=index3
for v in range(0,ln[u]):
X1[v]=X[index[v]]
c=np.average(X1, axis=0)
C[u]=c
#输出图像(十分刻意。根据用例来输出颜色,白最多,然后红,绿色最少)
for i in range(total):
if label[i]==1:
g=ln[0]
if g==max(ln):
X[i]=[255,255,255]
elif g==min(ln):
X[i]=[0,255,0]
else:
X[i]=[255,0,0]
if label[i]==2:
g=ln[1]
if g==max(ln):
X[i]=[255,255,255]
elif g==min(ln):
X[i]=[0,255,0]
else:
X[i]=[255,0,0]
if label[i]==3:
g=ln[2]
if g==max(ln):
X[i]=[255,255,255]
elif g==min(ln):
X[i]=[0,255,0]
else:
X[i]=[255,0,0]
out=img.reshape(img.shape[0],img.shape[1],3)
cv2.imshow("out", out)
cv2.waitKey (0)
########## End ##########
#cv2.imwrite('K_means/result/out.png', out)
python

结果

改进
多查阅资料会发现,简单利用一些函数,会让代码变得非常简洁,但实现起来的趣味性少了一些。
import cv2
import numpy as np
img = cv2.imread('图像位置')#读图
########## Begin ##########
#计算图像长和宽
row = img.shape[0]
col = img.shape[1]
def knn(data, iter, k): #data表示图像源,iter表示迭代次数,k表示聚类中心个数
data = data.reshape(-1, 3)
data = np.column_stack((data, np.ones(row*col)))
#随机产生初始簇心
cluster_center = data[np.random.choice(row*col, k)]
#分类
distance = [[] for i in range(k)]
for i in range(iter):
#计算与中心距离
for j in range(k):
distance[j] = np.sqrt(np.sum((data - cluster_center[j])**2, axis=1))
#根据最近距离进行分类
data[:, 3] = np.argmin(distance, axis=0)
#根据种类求平均得新的聚类中心
for j in range(k):
cluster_center[j] = np.mean(data[data[:, 3] == j], axis=0)
return data[:, 3]
#对图像进行三个类别的聚类分割
if __name__ == "__main__":
out = knn(img, 100, 3)
#根据类别进行颜色分配
X=np.zeros((len(out),3))
from collections import Counter
c=Counter(out)
for i in range(len(out)):
if out[i]==c.most_common(3)[2][0]: #统计出现次数最少的标签值,将其赋为绿色
X[i]=[0,255,0]
elif out[i]==c.most_common(1)[0][0]: #统计出现次数最多的标签值,将其赋为白色
X[i]=[255,255,255]
else:
X[i]=[0,0,255]
#将一维向量变换为图像
X = X.reshape(row, col,3)
out=X
cv2.imshow("out", out)
cv2.waitKey (0)
########## End ##########
cv2.imwrite('K_means/result/out.png', out)
python

结果如下

全部评论 (0)
还没有任何评论哟~
