Advertisement

基于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
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/mRLo1VX8lOACtdxIzin9P4TQSjuB.png)

结果

改进

多查阅资料会发现,简单利用一些函数,会让代码变得非常简洁,但实现起来的趣味性少了一些。

复制代码
 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
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/PiENKm3g8jDF67z9aI5JAcwBorTY.png)

结果如下

全部评论 (0)

还没有任何评论哟~