• kmeans实现图像像素分类


    代码

    1. import tkinter as tk
    2. from tkinter import filedialog
    3. from PIL import Image, ImageTk
    4. import numpy as np
    5. import random
    6. import math
    7. class Cluster(object):
    8. def __init__(self):
    9. # pixels是像素的意思,这里定义一个像素组用来存放像素的值
    10. self.pixels = []
    11. # 创建一个中心点
    12. self.centroid = None
    13. def addPoint(self, pixels):
    14. # 将像素值存放到这个空的pixels数组当中
    15. self.pixels.append(pixels)
    16. def setNewCentroid(self):
    17. # 这里通道R在像素点中进行轮寻R就会得到一个数组,里面是所有像素点R通道的像素值
    18. R = [colour[0] for colour in self.pixels]
    19. G = [colour[1] for colour in self.pixels]
    20. B = [colour[2] for colour in self.pixels]
    21. # 求R,G,B所有像素点的平均值
    22. R = sum(R) / len(R)
    23. R= round(R)
    24. G = sum(G) / len(G)
    25. G = round(G)
    26. B = sum(B) / len(B)
    27. B = round(B)
    28. self.centroid = (R,G,B)
    29. return self.centroid
    30. class Kmeans(object):
    31. # 初始化k个簇,最大迭代次数,阈值用来判断中心点与上一代中心点的误差,小于就结束,图片大小
    32. def __init__(self, k=10, max_iteration=10, min_distance=5.0, size=200):
    33. self.k = k
    34. self.max_iterations = max_iteration
    35. self.min_distance = min_distance
    36. self.size = (size, size)
    37. def run(self, image):
    38. self.image = image
    39. #将图像缩放到指定大小self.size
    40. self.image.thumbnail(self.size)
    41. # 将image转化为数组
    42. self.p = np.array(image)
    43. # 打印出来的是每个像素的数值[113, 110, 75]这是一个像素点RGB值
    44. self.pixels = np.array(image.getdata(), dtype=np.uint8)
    45. # return self.pixels,self.p
    46. # 创建了一个长度为 self.k 的列表,其中每个元素都被初始化为 None。这里,self.k 是一个类的属性,代表了你想要创建的簇(clusters)的数量。
    47. self.clusters = [None for i in range(self.k)]
    48. self.oldClusters = None
    49. # self.pixels 数组中随机选择 self.k 个像素点,并将这些像素点的值存储到 randomPixels 列表中
    50. randomPixels = random.sample(list(self.pixels), self.k)
    51. # 这里循环每个簇
    52. for idx in range(self.k):
    53. self.clusters[idx] = Cluster()
    54. self.clusters[idx].centroid = randomPixels[idx]
    55. iterations = 0
    56. while self.shouldExit(iterations) is False:
    57. self.oldClusters = [cluster.centroid for cluster in self.clusters]
    58. for pixel in self.pixels:
    59. self.assignClusters(pixel)
    60. for cluster in self.clusters:
    61. cluster.setNewCentroid()
    62. iterations += 1
    63. return [cluster.centroid for cluster in self.clusters]
    64. #分配簇,将像素分配到簇
    65. def assignClusters(self, pixel):
    66. # 可能是用来比较的shortest = float('Inf')这是设定距离为无穷大
    67. shortest = float('Inf')
    68. for cluster in self.clusters:
    69. distance = self.calcDistance(cluster.centroid, pixel)
    70. if distance < shortest:
    71. shortest = distance
    72. nearest = cluster
    73. nearest.addPoint(pixel)
    74. # 计算像素到中心点的欧式距离
    75. def calcDistance(self, a, b):
    76. # 计算欧氏距离
    77. result = math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2)
    78. # result = np.sqrt(sum((a-b) ** 2))
    79. return result
    80. # 迭代结束
    81. def shouldExit(self, iterations):
    82. if self.oldClusters is None:
    83. return False
    84. for idx in range(self.k):
    85. dist = self.calcDistance(
    86. np.array(self.clusters[idx].centroid),
    87. np.array(self.oldClusters[idx])
    88. )
    89. if dist
    90. return True
    91. if iterations <= self.max_iterations:
    92. return False
    93. return True
    94. # 显示原图像
    95. def showImage(self):
    96. self.image.show()
    97. # 显示每个200*200的图像,颜色是每个聚类中心像素
    98. def showCentroidColours(self):
    99. # 创建cluster * 200大小的图像
    100. total_width = len(self.clusters) * 200
    101. # 整体高度是200
    102. total_height = 200
    103. big_image = Image.new("RGB", (total_width, total_height), "white")
    104. # 计算每个小图片在大图上的位置
    105. x_offset = 0
    106. y_offset = 0
    107. for cluster in self.clusters:
    108. image = Image.new("RGB", (200, 200), cluster.centroid)
    109. # 将小图片粘贴到大图上
    110. big_image.paste(image, (x_offset, y_offset))
    111. # 更新 x 偏移量以准备下一个图片的位置
    112. x_offset += 200
    113. # new_width = 1000
    114. # new_height = 400
    115. # new_image = Image.new('RGB', (new_width, new_height), 'white')
    116. #
    117. # big_image = np.array(big_image)
    118. # image = np.concatenate((self.p, big_image), axis=0)
    119. # image = np.vstack((image, big_image))
    120. # big_image.show()
    121. big_image = big_image.resize((500, 30))
    122. return big_image
    123. # y_offset = 0
    124. # for img in zip([image, big_image]):
    125. # new_image.paste(img, (0, y_offset))
    126. # y_offset = y_offset + 1
    127. # new_image.show()
    128. # new_image.show()
    129. # 颜色图像显示
    130. def showClustering(self):
    131. # 创建一个与localPixels相同长度的
    132. localPixels =[None] * len(self.image.getdata())
    133. for idx, pixel in enumerate(self.image.getdata()):
    134. shortest = float('Inf')
    135. for cluster in self.clusters:
    136. distance =self.calcDistance(cluster.centroid, pixel)
    137. if distance < shortest:
    138. shortest = distance
    139. nearest = cluster
    140. localPixels[idx] = nearest.centroid
    141. w,h = self.image.size
    142. # 将localPixel转换为一个大小为(h, w, 3)的图像
    143. localPixels = np.asarray(localPixels)\
    144. .astype('uint8')\
    145. .reshape((h, w, 3))
    146. # 颜色图像显示
    147. colourMap = Image.fromarray(localPixels)
    148. colourMap = colourMap.resize((200, 200))
    149. return colourMap
    150. # colourMap.show()
    151. # 初始化Tkinter窗口
    152. root = tk.Tk()
    153. root.title("图片处理GUI")
    154. # 全局变量用于存储图片和图片数据
    155. image_path = None
    156. image_data = None
    157. def open_image():
    158. global image_path, image_data, image
    159. # 打开文件对话框,选择图片文件
    160. file_path = filedialog.askopenfilename(title="选择图片", filetypes=[("图像文件", "*.png;*.jpg;*.jpeg;*.bmp;*.gif")])
    161. if file_path:
    162. # 使用PIL打开图片
    163. image = Image.open(file_path)
    164. # 转换为Tkinter可以显示的格式
    165. image = image.resize((200, 200))
    166. tk_image = ImageTk.PhotoImage(image)
    167. # 展示图片
    168. label_image.config(image=tk_image)
    169. label_image.config(padx=10, pady=5)
    170. label_image.image = tk_image
    171. # 存储图片路径和图片数据(转换为numpy数组)
    172. image_path = file_path
    173. image_data = np.array(image)
    174. def apply_kmeans():
    175. global image_data, image_path
    176. if image_data is not None:
    177. # 将图片数据重塑为二维数组,每行是一个像素,每列是RGB值
    178. image = Image.open(image_path)
    179. image = image.resize((200, 200))
    180. # 初始化自定义的Kmeans类并运行算法
    181. k = Kmeans()
    182. # k.showImage()
    183. k.run(image)
    184. segmented_image_pil = k.showCentroidColours()
    185. # 展示处理后的图片
    186. segmented_tk_image = ImageTk.PhotoImage(segmented_image_pil)
    187. label_segmented.config(image=segmented_tk_image)
    188. label_segmented.image = segmented_tk_image
    189. else:
    190. print("请先打开一张图片!")
    191. # 创建按钮来打开图片
    192. def apply_kmeans1():
    193. global image_data, image_path
    194. if image_data is not None:
    195. # 将图片数据重塑为二维数组,每行是一个像素,每列是RGB值
    196. image = Image.open(image_path)
    197. image = image.resize((200, 200))
    198. # 初始化自定义的Kmeans类并运行算法
    199. k = Kmeans()
    200. # k.showImage()
    201. k.run(image)
    202. segmented_image_pil = k.showClustering()
    203. # 展示处理后的图片
    204. segmented_tk_image = ImageTk.PhotoImage(segmented_image_pil)
    205. label_segmented1.config(image=segmented_tk_image)
    206. label_segmented1.image = segmented_tk_image
    207. else:
    208. print("请先打开一张图片!")
    209. # 创建按钮来打开图片
    210. button_open = tk.Button(root, text="打开图片", command=open_image)
    211. # 使用 grid 布局,并指定在第0行第0列
    212. button_open.grid(row=0, column=0, sticky="ew")
    213. # 创建标签来展示原始图片
    214. label_image = tk.Label(root)
    215. # sticky="news" 表示填充所有方向
    216. label_image.grid(row=1, column=0, sticky="news")
    217. # 创建按钮来应用K-means算法
    218. button_kmeans = tk.Button(root, text="应用K-means", command=apply_kmeans)
    219. button_kmeans.grid(row=0, column=1, sticky="ew")
    220. # 创建标签来展示K-means处理后的图片
    221. label_segmented = tk.Label(root)
    222. label_segmented.grid(row=1, column=1, sticky="news")
    223. button_kmeans1 = tk.Button(root, text="返回图像", command=apply_kmeans1)
    224. button_kmeans1.grid(row=0, column=2, sticky="ew")
    225. label_segmented1 = tk.Label(root)
    226. label_segmented1.grid(row=1, column=2, sticky="news")
    227. # 运行Tkinter事件循环
    228. root.columnconfigure(0, weight=1)
    229. root.columnconfigure(1, weight=1)
    230. root.columnconfigure(2, weight=1)
    231. root.mainloop()

  • 相关阅读:
    [附源码]SSM计算机毕业设计中小企业人事管理系统JAVA
    JdbcTemplate
    排序1:直接插入排序
    开发一款流行的国内App可能用到的SDK功能分析
    gnss rtcm rtklib Ntrip...
    【Kafka系列】(二)Kafka的基本使用
    基于Python的性能优化
    ECharts综合案例一:近七天跑步数据
    孩子到底是食物过敏?还是食物不耐受?
    【Java SE】“方法”论 — 《方法的概念及使用》
  • 原文地址:https://blog.csdn.net/weixin_48433993/article/details/138161574