You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用scipy.cluster.hierarchy的linkage函数实现图像颜色聚类分割

嘿,我懂你想只靠颜色相似度做图像分割的需求,用层次聚类的思路完全靠谱!我来帮你把这个方案补全,顺便提些实用的细节,让代码能跑起来还能优化效果~

基于颜色的层次聚类图像分割实现

先给你补全并优化代码,再一步步拆解关键要点:

1. 完整可运行代码

假设你的img是已经加载好的(256,256,3) numpy数组,这里会处理像素值归一化、聚类执行和结果可视化:

import numpy as np
from scipy.cluster.hierarchy import linkage, fcluster
import matplotlib.pyplot as plt

# 处理像素值:把0-255的uint8转成0-1的float(避免数值范围干扰聚类)
img_normalized = img.astype(np.float32) / 255.0

# 将图像展平为[N, 3]的像素矩阵,N=256*256=65536
ppp = img_normalized.reshape(-1, 3)

# 执行层次聚类的linkage步骤——选ward方法最优,它会最小化类内方差,特别适合颜色聚类
# 注意:直接对65536个点聚类会很慢,后面会给优化方案
Z = linkage(ppp, method='ward', metric='euclidean')

# 指定聚类数量,比如分成5个颜色类
num_clusters = 5
labels = fcluster(Z, num_clusters, criterion='maxclust')

# 把聚类标签转回图像形状,得到分割结果
segmented_img = labels.reshape(img.shape[0], img.shape[1])

# 对比可视化原图和分割图
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.imshow(img)
plt.title('Original Image')
plt.axis('off')

plt.subplot(122)
plt.imshow(segmented_img, cmap='viridis')
plt.title(f'Segmented Image ({num_clusters} color groups)')
plt.axis('off')
plt.show()

2. 关键优化与细节说明

  • 性能救星:采样聚类
    直接对65536个像素做层次聚类(时间复杂度O(n²))会非常慢,你可以先随机采样部分像素聚类,再用KNN给剩余像素贴标签,速度提升几十倍,效果几乎没差:

    # 随机采样1000个像素做聚类
    sample_indices = np.random.choice(ppp.shape[0], size=1000, replace=False)
    sample_points = ppp[sample_indices]
    Z_sample = linkage(sample_points, method='ward', metric='euclidean')
    sample_labels = fcluster(Z_sample, num_clusters, criterion='maxclust')
    
    # 用KNN给所有像素分配标签
    from sklearn.neighbors import KNeighborsClassifier
    knn = KNeighborsClassifier(n_neighbors=5)
    knn.fit(sample_points, sample_labels)
    labels = knn.predict(ppp)
    
  • 聚类数量怎么选?
    不想手动指定num_clusters的话,可以画树状图找聚类分界点——看树状图里距离突然跳变的“断层”,就是合适的聚类数量:

    plt.figure(figsize=(15,5))
    dendrogram(Z_sample)
    plt.title('Dendrogram of Color Clusters')
    plt.xlabel('Sample Pixels')
    plt.ylabel('Euclidean Distance')
    plt.show()
    
  • 更贴合人眼的颜色聚类
    RGB空间的欧氏距离和人眼感知的颜色相似度不完全匹配,你可以把图像转成Lab颜色空间再聚类,结果会更符合视觉直觉:

    from skimage.color import rgb2lab
    img_lab = rgb2lab(img_normalized)
    ppp_lab = img_lab.reshape(-1, 3)
    # 后续聚类步骤用ppp_lab代替ppp即可
    

3. 必踩坑提醒

  • 一定要把uint8类型的0-255像素值转成0-1的float,不然大数值的RGB分量会主导聚类结果,完全打乱颜色相似性的判断。

内容的提问来源于stack exchange,提问作者Utpal Datta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:26:26