【OpenCv】图像分割——聚类算法

本文深入解析了KMeans聚类算法的工作原理及OpenCV中的API使用方法,并通过一个具体的图像分割案例展示了如何利用KMeans算法进行颜色聚类,以实现图像的基本分割。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 原理

KMeans算法概述

  • KMeans算法的作者是MacQueen, KMeans的算法是对数据进行分类的算法,采用的硬分类方式,是属于非监督学习的算法;
  • 对于给定的样本集,按照样本之间的距离大小,将样本划分为K个簇,让簇内的点尽量紧密的连接在一起,而让簇间的距离尽量的大。

KMeans算法流程

  • 1:选择K个点作为初始质心。
  • 2:Repeat
  • 3: 计算邻近度,将每个点指派到最近的质心,形成K个簇;
  • 4: 重新计算每个簇的质心;
  • 5: Until 质心不发生变化或者新的中心和之前的中心之间的距离小于某阈值,或迭代次数超过某阈值,认为聚类已经收敛,终止。

2 API

函数原型:

compactness, labels, (centers) = kmeans(data, K, bestLabels, criteria, attempts, flags, centers=None)

参数:

  • data:输入的样本数据,必须是按行组织样本,每一行为一个样本数据,列表示样本的维度。
  • K:最终的簇的数目。
  • bestLabels:预设的分类标签或者None。
  • criteria:迭代停止的模式选择,这是一个含有三个元素的元组型数。格式为(type, max_iter, epsilon) 其中,type有如下模式:
    • cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon,则停止。
    • cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter,则停止。
    • cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER:两者结合,满足任意一个结束。
  • attempts:重复试验kmeans算法次数,将会返回最好的一次结果。
  • flags:初始中心选择,可选以下三种:
    • cv2.KMEANS_PP_CENTERS:使用kmeans++算法的中心初始化算法,即初始中心的选择使眼色相差最大。
    • cv2.KMEANS_RANDOM_CENTERS:每次随机选择初始中心

返回值:

  • compactness:密度,返回每个点到相应重心的距离的平方和。
  • labels:结果标记,每个成员被标记为分组的序号,如 0,1,2,3,4…等。
  • centers:由聚类的中心的描述信息(可能是坐标,也可能是色彩值)组成的数组。

3 图像分割

  • 在一张图片中,每一个像素点对应位置坐标和色彩坐标,用k-means算法对图像聚类不是聚类位置信息,而是对其色彩进行聚类。
  • kmeans能够实现简单的分割,当然效果不是非常好,需要经过一些后处理调整,才能得到高精度的分割图。

本次的案例是分割下面图片的各个区域。即分割出天空、楼房、草坪、湖面。

在这里插入图片描述

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

def test_KMeans(image_path) :
    image = cv.imread(image_path, cv.IMREAD_COLOR)
    image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
    pixel_value = np.float32(image.reshape((-1, 3)))

    #终止条件
    criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 200, 0.1)

    #起始的中心选择
    flags = cv.KMEANS_RANDOM_CENTERS

    #定义簇的数量
    K = 3

    _, labels, center = cv.kmeans(pixel_value, K, None, criteria, 10, flags)
    center = np.uint8(center)

    #将所有像素转换为质心的颜色
    segmented_image = center[labels.flatten()]
    
    #重塑回原始图像尺寸
    segmented_image = segmented_image.reshape((image.shape))

    plt.figure(figsize = (8, 4))
    plt.subplot(121)
    plt.imshow(image)
    plt.axis('off')
    plt.title(f'$input\_image$')
    plt.subplot(122)
    plt.imshow(segmented_image)
    plt.axis('off')
    plt.title(f'$segmented\_image$')
    plt.tight_layout()
    plt.savefig('segmented_result.png')
    plt.show()

if __name__ == '__main__':
    test_KMeans('images/shenzhen.png')

效果:
在这里插入图片描述

整体效果还是不错的,但是一些细节的地方处理的不好,比如说湖面有部分被分为了天空,改进策略有有规则地初始化质心等。

4 代码解释

大家有疑惑的地方就是segmented_image = center[labels.flatten()]是怎么将所有像素转换为质心的颜色的。我们前面说过,返回值center是色彩的描述信息,当图片为三通道时,center的维度就是(K,Channels),K是簇的个数,Channels是图片的通道数,如当center返回值是[[ 33 71 57], [193 202 214],[ 65 134 173]]时,[ 33 71 57]分别表示第一个簇心的R、G、B通道的像素值。其次labels返回每个成员被标记为分组的序号,如 0,1,2,3,4…等,在过程中是将R、G、B通道的像素信息整合到一起来标记,所以labels的维度只相当于某一通道展平,如图片本来是[2,4,3],那labels是[8,1]。因此labels中每个标记对应center中的每个簇的下标,如0对应center下标为0的簇心信息。则segmented_image = center[labels.flatten()]也是将一个通道"拓展"成三通道的过程。也等效于于下面的代码:

 labels = labels.flatten()
    segmented_image = np.zeros((len(labels), 3), dtype = np.uint8)
    for i in range(len(labels)) :
        segmented_image[i] = center[labels[i]]
### 图像分割中的MeanShift算法 #### MeanShift算法概述 MeanShift是一种基于密度估计的聚类算法,通过不断移动数据点至局部数据密度最高的位置来完成聚类操作。此特性使得MeanShift非常适合用于图像处理领域内的对象跟踪和图像分割任务[^2]。 #### OpenCV实现MeanShift算法进行图像分割 为了利用MeanShift算法来进行图像分割,可以借助于OpenCV库提供的`pyrMeanShiftFiltering()`函数。该函数接受两个主要参数——空间窗口大小(spatial window size)和颜色窗口大小(color window size),这两个参数决定了算法如何识别相似的颜色区域并将其聚合在一起形成不同的片段[^3]。 下面是一个Python代码示例展示如何使用OpenCV执行MeanShift过滤: ```python import cv2 import numpy as np # 加载图片 image = cv2.imread('input.jpg') # 应用均值漂移滤波器 shifted = cv2.pyrMeanShiftFiltering(image, sp=10, sr=30) # 显示原始图与处理后的对比 cv2.imshow("Input", image) cv2.imshow("Output", shifted) cv2.waitKey(0) ``` 这段代码读取了一张名为`input.jpg`的图片,并调用了`pyrMeanShiftFiltering()`方法对其进行处理,最后显示原图及其经过MeanShift处理的结果。这里设置的空间窗口大小为10,色彩窗口大小为30,可以根据实际需求调整这些数值以获得更好的分割效果。 #### 改进版MeanShift算法的特点 相比于标准的OpenCV库函数,改进版本采用了更为精确的方法寻找模态点(即密度最大处)。具体来说,不是采用随机方式而是遍历所有像素点来找寻最合适的模式点,尽管这种方法增加了计算成本。另外,在核密度估算方面引入了高斯核代替原来的均匀核,从而提高了模型对于真实世界情况下的适应能力。此外,还优化了平滑和平铺策略,减少了不必要的重复扫描次数,进一步提升了性能表现[^4]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八岁爱玩耍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值