matlab对图像进行均值滤波_用K均值进行图像分割

个人学习笔记:采用聚类方法对图像进行分割,以下内容纯粹个人理解,如有错误请帮我指出!多谢!

图像分割就是把图像按照某些条件分成不同的区域,并提取出感兴趣的区域。传统的分割方法包括基于阈值的分割、基于区域的分割、基于边缘的分割等。当然,本次笔记写的是采用K均值聚类实现图像分割。(代码在文章结尾)

一、理论分析

K均值是一种比较常用的聚类算法,由于并不是本次笔记的重点,因此只进行算法的流程简单记录如下:

1、选取K个样本作为聚类中心

2、计算各个样本到聚类中心的距离

3、更新均值向量,重复以上步骤

分割算法核心:对图像的像素进行聚类,相似RGB值的像素被聚到一起,就形成了K个区域!

问题的核心在于如何使用K均值对图像的像素进行聚类,自己整理了以下的几个问题:

1、 K均值使用什么做样本?

K均值聚类就是把图像的像素点按照“值的接近程度”进行聚类,那么就会给每个像素点打标签(把每个位置R、G、B值看作是一个样本,R、G、B就是三个特征),有多少像素值(R、G、B算一个像素值)就有多少个样本。

2、 K均值得到的标签含义是什么?

K均值得到的结果标签就是width*height个0,1,2这种值,因为图像提供的样本数就是width*height个,也就是对每个位置的像素点打标签。含义就是亮度接近的像素标签值相同。

3、K均值聚类以后如何得到新的聚类图像

像素点的标签值表示它属于哪个类,后续使用标签值作为亮度值。如果是聚类结果为3, 那么标签值就有0,1,2三个,标签的shape是width*height,那么就是用0,1,2填充一张np.zeros(width, height)图像,就得到了最后的聚类结果。

标签值相同的位置因此也就亮度相同,得到的聚类图像仅仅包含k个亮度种类,比如K=3,那么聚类图像就只有三种亮度值

实现代码里面未解决的Bug:因为标签值0,1,2代表的仅仅是三个不同区域,但是没办反设定哪个区域是2(最亮的区域),也就是最后合成的图像哪个区域亮没办反控制(比如人脸区域应该更亮),只能多运行几次程序。

二:代码实现

算法流程分为以下四步:

1、读取图片

2、将图片像素转为样本形式

3、对样本进行聚类

4、创建空白图像

5、使用聚类结果对空白图像进行填充

6、保存聚类得到的标签图

步骤1和2:

# 1:read image
    

上述代码块的#1负责读取图片,#2负责把(w,h,3)的图像转为(w*h,3)的数据,每行就是一个样本,每个样本包含R、G、B三个特征值。

步骤3:

    # 3: cluster, I thought: give every pixel (that in orignal image)
    #    a label , so the label have same shape as image(gray)
    cls = KMeans(n_clusters=k_cluster).fit_predict(data)
    cls = cls.reshape(image.shape[0], image.shape[1])

聚类就是对上述的像素值进行聚类

步骤4:

    # 4: create a image container
    container = np.zeros(shape=(image.shape[0], image.shape[1]))

创建的像素值全为0的空白图像,用于存储聚类标签。

步骤5:

    # 5: use cluster labels as "gray value" 
    #    and  fill it into aimage container
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            # cls[i, j]*30 ,because label value is 0, 1, 2
            # the bright difference betwwen labels is to small
            container[i, j] = cls[i, j]*60

将聚类标签值cls[i, j]乘以60作为亮度值(乘以70或者任何值都行,只要保证K*任何值不超过255)

步骤6:

    # 6: saver the cluster image
    container = container.astype(np.uint8) 
    imageio.imsave(save_name, container)

保存的时候一定要转换为uint8编码

完整的代码如下:

import numpy as np
import imageio
from sklearn.cluster import KMeans

def image_cluster(image_name, save_name, k_cluster=3):
    """
    cluster by KMeans for RGB image
    """
    
    # 1:read image
    image = imageio.imread(image_name)

    # 2: convert (w, h, 3) into (w*h, 3)
    # R,G and B combine as 3 features 
    # data will be a 2D matrix, each row have 3 values(R/G/B),
    # and each column has width*height values
    # this operation convert 3D to 2D, like reshape 
    image2matrix = []
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            r_v, g_v, b_v = image[i, j]
            image2matrix.append([r_v/255.0, g_v/255.0, b_v/255.0])
    data = np.mat(image2matrix)

    # 3: cluster, I thought: give every pixel (that in orignal image)
    #    a label , so the label have same shape as image(gray)
    cls = KMeans(n_clusters=k_cluster).fit_predict(data)
    cls = cls.reshape(image.shape[0], image.shape[1])
    
    # 4: create a image container
    container = np.zeros(shape=(image.shape[0], image.shape[1]))

    # 5: use cluster labels as "gray value" 
    #    and  fill it into aimage container
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            # cls[i, j]*30 ,because label value is 0, 1, 2
            # the bright difference betwwen labels is to small
            container[i, j] = cls[i, j]*60

    # 6: saver the cluster image
    container = container.astype(np.uint8) 
    imageio.imsave(save_name, container)
    
    return True

image_cluster("data/vivian.jpg", "results/cluster.jpg")

对标题上费雯丽的照片进行聚类结果如下:

f0687b148bb2169d6278460c4fdf72be.png

个人认为:K如果选择为2,那么图片视觉上看就应该包含“2种”明显不同的区域;K如果选择为3,那么图片中就应该包含3种明显不同的区域。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值