计算机视觉入门到实战系列(十六)基于空间约束的k-means图像分割

基于空间约束的k-means图像分割

上节中我们实现了基于k-means的图像分割,这节我们实现基于空间约束的k-means图像分割。

代码实现

添加空间信息

这里我们在之前的基础上添加相应的坐标信息。部分函数已经在上一节实现了,这里不再重复赘述。这里解释下为什么要在之前的基础上添加相应的坐标信息。

如果只用RGB颜色特征,聚类结果可能:

  • 颜色相似但位置很远的像素归为一类
  • 导致分割结果不连续、碎片化

添加坐标信息的好处:

  1. 空间连续性:鼓励位置相近的像素聚类在一起
  2. 区域一致性:更容易形成连续的区域分割
  3. 控制分割粒度 :通过weight参数可以调整空间信息的重要性
    • weight=0:纯颜色聚类
    • weight越大:越重视空间位置,分割区域越紧凑
python 复制代码
image = imread('segmentation.jpeg')[:,:,:3]
# 将RGB值统一到0-255内
if np.max(image)>1:
    image = image / 255
    

sp = image.shape
# 增加xy坐标的信息
# 设定一个权重,对坐标信息加权
weight = 2
y = weight * np.array([[i for i in range(sp[1])] 
                       for j in range(sp[0])]) / sp[0] / sp[1]
x = weight * np.array([[j for i in range(sp[1])] 
                       for j in range(sp[0])])/ sp[0] / sp[1]
image = np.append(image, x.reshape(sp[0], sp[1], 1), axis=2)
image = np.append(image, y.reshape(sp[0], sp[1], 1), axis=2)

X = image.reshape(-1, image.shape[2])
segmented_imgs = []

# 将 K 分别设置为6、5、4、3、2
n_colors = (6, 5, 4, 3, 2)
for n_cluster in n_colors:
    kmeans = KMeans(n_clusters=n_cluster, random_state=42).fit(X)
    segmented_img = kmeans.cluster_centers_[kmeans.labels_]
    segmented_imgs.append(decode_segmap(
        kmeans.labels_.reshape(image.shape[0],
                               image.shape[1])).astype(np.uint8))

这段代码是在给图像像素添加空间位置信息,然后用于K-means聚类分割。让我详细解释每个部分的作用:

  1. 获取图像形状
python 复制代码
sp = image.shape  # 得到 (高度, 宽度, 通道数)
# 对于RGB图像通常是 (h, w, 3)
  1. 创建y坐标特征矩阵
python 复制代码
y = weight * np.array([[i for i in range(sp[1])] 
                       for j in range(sp[0])]) / sp[0] / sp[1]
  • 生成一个与图像同尺寸的矩阵,每个位置的值是该像素的列坐标(从0到宽度-1)
  • range(sp[1]) 创建列索引 0, 1, 2, ..., 宽度-1
  • 外层的 for j in range(sp[0]) 重复这个行,形成一个矩阵
  • / sp[0] / sp[1] 将坐标归一化到0,1范围(除以总像素数)
  • weight = 2 给坐标信息一个权重,控制它在聚类中的重要性

实际效果:创建一个矩阵,从左到右值从0线性增加到1

  1. 创建x坐标特征矩阵
python 复制代码
x = weight * np.array([[j for i in range(sp[1])] 
                       for j in range(sp[0])]) / sp[0] / sp[1]
  • 生成一个与图像同尺寸的矩阵,每个位置的值是该像素的行坐标(从0到高度-1)
  • 注意这里的循环变量交换了:j 在外层循环(行索引)

实际效果:创建一个矩阵,从上到下值从0线性增加到1

  1. 将坐标信息添加到图像特征中
python 复制代码
image = np.append(image, x.reshape(sp[0], sp[1], 1), axis=2)
image = np.append(image, y.reshape(sp[0], sp[1], 1), axis=2)
  • axis=2 表示在通道维度拼接
  • 原来图像是 (h, w, 3) - RGB三通道
  • 添加x坐标后变成 (h, w, 4)
  • 再添加y坐标后变成 (h, w, 5)
  1. 重塑为特征矩阵
python 复制代码
X = image.reshape(-1, image.shape[2])
  • 将 (h, w, 5) 重塑为 (h×w, 5) 的矩阵
  • 每一行代表一个像素的5维特征R, G, B, x坐标, y坐标

举例说明:

假设有一张图,左上角和右下角都有相似的红色:

  • 只用RGB:这两个红色区域会被分到同一类
  • 添加xy坐标:由于位置差异大,会被分到不同类,形成更合理的分割
循环嵌套
python 复制代码
y = weight * np.array([[i for i in range(sp[1])] 
                       for j in range(sp[0])]) / sp[0] / sp[1]

对于上面的循环嵌套,乍一看可能会很懵这里详细解释下。

  1. 首先理解sp[0]sp[1]
python 复制代码
sp = image.shape  # (高度, 宽度, 通道数)
sp[0] = 图像的高度 (行数)
sp[1] = 图像的宽度 (列数)
  1. 简化这个表达式
    原始的代码可以分解为两步:

第一步:创建y坐标矩阵

python 复制代码
# 创建一个列表推导式
matrix = []
for j in range(sp[0]):  # 遍历所有行
    row = []
    for i in range(sp[1]):  # 遍历所有列
        row.append(i)  # 当前列的位置
    matrix.append(row)

# 等价于
y_matrix = np.array([[i for i in range(sp[1])] for j in range(sp[0])])

举个例子:

如果图像尺寸是 3×4(高3像素,宽4像素):

python 复制代码
# range(sp[1]) = range(4) = [0, 1, 2, 3]
# 这个值在每一行都重复

y_matrix = [
    [0, 1, 2, 3],  # 第一行
    [0, 1, 2, 3],  # 第二行  
    [0, 1, 2, 3]   # 第三行
]

关键点 :这个矩阵的列值从左到右递增 ,但是每一行的列值都相同

  1. 然后是归一化和加权
python 复制代码
y = weight * y_matrix / sp[0] / sp[1]

实际上是:

python 复制代码
y = weight * y_matrix / (sp[0] * sp[1])

继续上面的例子:

python 复制代码
weight = 2
sp[0] = 3, sp[1] = 4
除数 = 3 × 4 = 12

原始值:[0, 1, 2, 3]
归一化后:[0/12, 1/12, 2/12, 3/12] = [0, 0.0833, 0.1667, 0.25]
加权后:×2 = [0, 0.1667, 0.3333, 0.5]

最终y矩阵:
[
    [0, 0.1667, 0.3333, 0.5],
    [0, 0.1667, 0.3333, 0.5],
    [0, 0.1667, 0.3333, 0.5]
]

展示结果

python 复制代码
# 展示结果
plt.figure(figsize=(12,8))
plt.subplot(231)
plt.imshow(image[:,:,:3])
plt.title('Original image')
plt.axis('off')

for idx,n_clusters in enumerate(n_colors):
    plt.subplot(232+idx)
    plt.imshow(segmented_imgs[idx])
    plt.title('{} center'.format(n_clusters))
    plt.axis('off')

输出

相关推荐
沪漂阿龙5 分钟前
create_agent:LangChain 新版 Agent 的核心入口
人工智能·架构·langchain
茉莉玫瑰花茶7 分钟前
综合案例 - AI 智能租房助手 [ 5 ]
服务器·数据库·人工智能·python·ai
文艺倾年13 分钟前
【强化学习】强化学习基本概念,20W字总结(一)
人工智能·python·语言模型·自然语言处理·面试·职场和发展·大模型
FserSuN15 分钟前
压缩在智能中的作用
人工智能
产业家15 分钟前
AI长跑,来到了腾讯的主场
大数据·人工智能
MartinYeung520 分钟前
[论文学习]大型语言模型中个人可识别资讯(PII)的机器遗忘技术:UnlearnPII 基准与 PERMU_tok 方法的深度分析
人工智能·学习·语言模型
孟郎郎20 分钟前
2026 年 15 款 AI 视频生成工具推荐
人工智能·ai·工具·ai视频
器灵科技20 分钟前
AI视频工具实测:Seedance/可灵/HappyHorse谁最能打?
java·运维·数据库·人工智能·github
腾飞开源24 分钟前
05_Dify接入Ollama本地大模型
人工智能·项目实战·dify·ai智能体·ollama·企业级应用·接入模型
HavenlonLabs28 分钟前
重塑链上未来的隐形基石:长期主义下的生态演进
大数据·人工智能·安全·区块链