一、理論深度提升:補充算法細節與數學基礎
1.?K-Means 算法核心公式(增強專業性)
在 “原理步驟” 中加入數學表達式,說明聚類目標:
K-Means 的目標是最小化簇內平方和(Within-Cluster Sum of Squares, WCSS):J=∑i=1K?∑x∈Ci??∥x?μi?∥2
其中,Ci??是第?i?個簇,μi??是簇中心。算法通過迭代更新簇中心?μi??和分配樣本到最近中心,逐步優化?J。
2.?顏色空間選擇(擴展知識邊界)
新增小節說明 RGB 顏色空間的局限性,推薦更適合聚類的顏色空間(如 Lab):
- RGB:各通道高度相關,歐氏距離不能準確反映視覺差異。
- Lab:基于人眼感知,通道獨立,聚類效果更符合視覺預期(可補充代碼示例,需安裝
colorama
庫)。
?
二、K-Means 顏色聚類(K-Means Color Clustering)
1.概念與作用
K-Means 顏色聚類是借助?K-Means 聚類算法?對圖像(或顏色集合)中的顏色進行分組,目的是提取出最具代表性的若干種顏色(聚類中心),實現顏色簡化或風格化。比如:
1)簡化圖像色彩:把照片的上百種顏色壓縮為 5 - 10 種主色,生成類似插畫、低多邊形藝術的效果。
2)色彩分析:快速找出圖像里占比高的顏色,用于設計配色參考、圖像分類(如區分風景照的 “暖色調”“冷色調” )。
2.原理步驟
1)數據準備:把圖像的每個像素(RGB 形式,如?(r, g, b)?)視為高維空間(3 維,對應 RGB 通道)中的點。
2)聚類分組:用 K-Means 算法將這些點聚成?K?類(K?是你設定的聚類數,比如 5 類就提取 5 種主色 )。算法隨機選?K?個初始中心,不斷迭代調整,讓同類點盡可能靠近自己的中心,不同類中心盡可能遠離。
3)顏色替換:用每個聚類的中心顏色,替換該類所有像素的顏色。最終圖像就只剩?K?種主色,實現色彩簡化。
代碼:(使用的時候記得修改圖片路徑)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from matplotlib.image import imreaddef set_chinese_font():"""設置 Matplotlib 支持中文顯示的字體"""import matplotlib.font_manager as fmchinese_fonts = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Microsoft YaHei"]available_fonts = [f.name for f in fm.fontManager.ttflist]for font in chinese_fonts:if font in available_fonts:plt.rcParams["font.family"] = fontprint(f"已設置中文字體: {font}")return Trueprint("警告: 未找到可用的中文字體,圖表中的中文可能顯示為方塊")return False# 設置中文字體
set_chinese_font()
image_path = r"D:\keshihua\biancheng\PythonProject1\haimianbaobao.jpg"
try:image = imread(image_path)if image.shape[-1] == 4:image = image[..., :3]print(f"圖像加載成功,尺寸: {image.shape}")
except FileNotFoundError:print("錯誤:圖片路徑不存在,請檢查路徑!")exit(1)
except Exception as e:print(f"加載圖片失敗: {e}")exit(1)n_clusters = 5
pixels = image.reshape(-1, 3) kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init='auto')
kmeans.fit(pixels)if image.dtype == np.uint8:main_colors = kmeans.cluster_centers_.astype(np.uint8)
else:main_colors = kmeans.cluster_centers_
main_colors = main_colors.reshape(-1, 3)plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.title("原始圖像")
plt.axis('off')plt.subplot(1, 2, 2)
color_width = 1 / n_clusters
for i in range(n_clusters):plt.fill_between(x=[i * color_width, (i + 1) * color_width],y1=0, y2=1,color=main_colors[i] / 255.0 if image.dtype == np.uint8 else main_colors[i],edgecolor='white')
plt.axis('off')
plt.title(f"提取的 {n_clusters} 種主色")plt.tight_layout()
plt.show()print("提取的主色 (RGB 數值):")
for i, color in enumerate(main_colors):if image.dtype == np.uint8:print(f"主色 {i+1}: {color}")else:print(f"主色 {i+1}: {color.round(3)}")
運行結果:
三、漸變色(Gradient Color)
1.概念與作用
漸變色是指?兩種或多種顏色之間平滑過渡的色彩效果?,能營造柔和、連貫的視覺感受。結合 K-Means 顏色聚類,常用來:
1)可視化聚類結果:用聚類得到的主色,生成從一種主色平滑過渡到另一種主色的色帶,直觀展示 “提取了哪些主色” 。
2)設計配色方案:基于圖像主色,快速生成協調的漸變色,用于 UI 設計、海報背景等。
2.實現方式:
1)提取主色:先用 K-Means 聚類得到?K?個主色(聚類中心)。
2)創建漸變映射:用?LinearSegmentedColormap(Matplotlib 工具),把主色按順序排列,讓顏色在色帶中平滑過渡。
3)生成漸變圖像:用創建好的顏色映射,生成從左到右(或其他方向)的漸變色帶。
代碼:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from matplotlib.image import imread
from matplotlib.colors import LinearSegmentedColormap# 設置中文字體
def set_chinese_font():import matplotlib.font_manager as fmchinese_fonts = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Microsoft YaHei"]available_fonts = [f.name for f in fm.fontManager.ttflist]for font in chinese_fonts:if font in available_fonts:plt.rcParams["font.family"] = fontprint(f"已設置中文字體: {font}")return Trueprint("警告: 未找到可用的中文字體,圖表中的中文可能顯示為方塊")return Falseset_chinese_font()image_path = r"D:\keshihua\biancheng\PythonProject1\haimianbaobao.jpg"
try:image = imread(image_path)if image.shape[-1] == 4:image = image[..., :3]print(f"圖像加載成功,尺寸: {image.shape}")
except Exception as e:print(f"加載圖片失敗: {e}")exit(1)n_clusters = 5 # 可調整聚類數量
pixels = image.reshape(-1, 3)kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init='auto')
kmeans.fit(pixels)if image.dtype == np.uint8:main_colors = kmeans.cluster_centers_.astype(np.uint8)
else:main_colors = kmeans.cluster_centers_
main_colors = main_colors.reshape(-1, 3)# 歸一化顏色到 [0,1] 范圍
main_colors_normalized = main_colors / 255.0 if image.dtype == np.uint8 else main_colors# 創建漸變色映射(按聚類中心順序過渡)
cmap = LinearSegmentedColormap.from_list('custom_gradient', main_colors_normalized, N=200)# 生成水平漸變色條
gradient = np.linspace(0, 1, 500).reshape(1, -1) # 500 個漸變點
gradient_image = cmap(gradient)[0, :, :3] # 提取 RGB 值plt.figure(figsize=(14, 8))# 子圖 1:原始圖像
plt.subplot(2, 2, 1)
plt.imshow(image)
plt.title("原始圖像")
plt.axis('off')# 子圖 2:主色提取(色塊形式)
plt.subplot(2, 2, 2)
color_width = 1 / n_clusters
for i in range(n_clusters):plt.fill_between(x=[i * color_width, (i + 1) * color_width],y1=0, y2=1,color=main_colors_normalized[i],edgecolor='white',linewidth=1)# 添加顏色標簽plt.text((i * color_width + (i + 1) * color_width) / 2,0.5,f"#{i+1}",ha='center',va='center',color='white' if np.mean(main_colors_normalized[i]) < 0.5 else 'black',fontweight='bold')
plt.axis('off')
plt.title(f"提取的 {n_clusters} 種主色")# 子圖 3:漸變色條(水平)
plt.subplot(2, 1, 2)
plt.imshow(gradient_image.reshape(1, -1, 3), aspect='auto')
plt.title("主色之間的平緩過渡")
plt.axis('off')# 添加主色標記點(修復顏色格式問題)
for i in range(n_clusters):pos = i / (n_clusters - 1) if n_clusters > 1 else 0.5 # 計算位置plt.plot([pos * 499], [0], 'wo', markersize=8, markeredgecolor='black') # 白色圓點# 修復:使用 tuple 格式傳遞顏色,而不是字符串plt.plot([pos * 499], [0], 'o', color=tuple(main_colors_normalized[i]), markersize=5)plt.tight_layout()
plt.show()print("提取的主色 (RGB 數值):")
for i, color in enumerate(main_colors):rgb_str = f"RGB({color[0]:3d}, {color[1]:3d}, {color[2]:3d})"hex_str = '#{:02x}{:02x}{:02x}'.format(*color) if image.dtype == np.uint8 else ''print(f"主色 #{i+1}: {rgb_str} {hex_str if hex_str else ''}")
原圖:
四、常見問題與優化策略(提升實用性)
1.?如何選擇最優 K 值?
新增小節介紹肘部法則(Elbow Method),通過 WCSS 曲線確定最佳聚類數:
?
# 計算不同K值的WCSS
wcss = []
for k in range(2, 10):kmeans = KMeans(k, random_state=42).fit(pixels)wcss.append(kmeans.inertia_)# 繪制肘部曲線
plt.plot(range(2, 10), wcss, 'bo-')
plt.xlabel("聚類數 K")
plt.ylabel("WCSS")
plt.title("肘部法則確定最優K值")
2.?聚類結果不穩定怎么辦?
建議:
- 增加
n_init
參數(如n_init=10
),重復初始化多次取最優。 - 使用層次聚類(Hierarchical Clustering)作為預聚類,提供更穩定的初始中心。
?
3.?對比其他顏色聚類算法
新增表格對比 K-Means 與其他算法的優缺點:
?