K均值算法及利用其图片压缩

算法实现

一、K均值算法
K均值算法是典型的原型聚类算法,此类算法假设聚类结构能够通过一组原型刻画。通常情况下,算法先对原型进行初始化,然后对原型进行迭代更新求解。
K均值算法主要过程概括为:
1>初始化均值向量{ μ 1 , μ 2 , . . , μ k μ_1,μ_2,..,μ_k μ1,μ2,..,μk}, k k k值由用户给出,为聚类簇数。
2>对样本进行归类:对给定数据集 X X X中每个样本 x x x利用距离度量 d = ∣ ∣ x − μ ∣ ∣ 2 d=||x-μ||_2 d=xμ2计算每个样本到均值向量的距离,把样本 x x x归为其距离最近的均值向量所对应的簇。比如:对第 i i i个样本 x i x_i xi计算其到每个均值向量 μ 1 , μ 2 , . . . , μ k μ_1,μ_2,...,μ_k μ1,μ2,...μk的距离,如果他到第 j j j C j C_j Cj,就把 x i x_i xi划分到 C j C_j Cj中。
3>更新均值向量:现在我们每个均值向量 μ j μ_j μj对应的簇 C j C_j Cj下都有我们第二步通过归类所得到的样本。我们对每个簇下的样本进行求平均得到: μ j ′ = 1 ∣ C j ∣ ∑ x ∈ C i x μ_j^{'}=\frac{1}{|C_j|}\sum_{x∈C_i}x μj=Cj1xCix。这样我们就可以得到把 μ j ′ μ_j^{'} μj当做新的均值向量 μ j μ_j μj
4>跳至第二步,进行迭代,直至满足迭代终止条件为止。一般迭代终止条件为第二步中所有样本的类所属簇不在改变,或者由用户设定迭代次数。

二、K均值算法的实现
首先,根据我们上面的算法可以知道主要是对样本进行归类、更新均值向量,这样我们就需要编写两个函数。然后还需要将以上两个函数合并,给出迭代终止条件。
1、导入需要使用的模块

import numpy as np
from scipy.io import loadmat
import pandas as pd
import matplotlib.pyplot as plt

2、初始化均值向量
这里我们还需要编写一个能够初始化均值向量的函数。聚类的最终结果一定程度上取决于我们初始均值向量的选取,我们这里采用随机方法,产生初始均值向量。

def initial_centriod(X,k):
    m,d = X.shape
    initial_centriod=np.zeros((k,d))
    index=np.random.randint(0,m,k)
    for i in range(k):
        initial_centriod[i,:]=X[index[i],:]
    return initial_centriod

代码第三行创建一个 k ∗ d k*d kd零矩阵用于存放均值向量,其中 k k k是我们设定的聚类簇数, d d d为样本的维度或者说是我们研究的特征空间的维度,矩阵每一行就是用来存放初始均值向量,因为我们要产生 k k k个均值向量,所以矩阵为k行。
第四行我们产生一个大小为 k k k,范围为 1 — m 1—m 1m的数组, m m m为样本的大小。最后对零向量每一行进行遍历,使其每一行为 m m m个样本中随机产生的一个。例如,我们把 k k k设置为3,一共有20个样本,那么index就有可能是数组 [ 1 , 3 , 4 ] [1,3,4] [1,3,4],到底下对零矩阵每一行进行遍历时,初始均值向量的第一行就会是第1个样本,第二行为第3个样本,第三行为第4个样本。也就是说我们把第1,3,4个样本作为初始均值向量。

3、对每个样本进行归类

def find_closest_centriod(X,centriod):
    m=X.shape[0]
    k = centriod.shape[0]
    index_centriod=np.zeros(m)
    for i in range(m):
        minidist = 1000000000000
        for j in range(k):
             dist = (centriod[j]-X[i]).T @ (centriod[j]-X[i])
             if dist < minidist:
                minidist = dist
                index_centriod[i]=j
    return index_centriod

这里代码第4行的index_centriod它的维度为训练集大小 m m m,用来存放着 m m m个样本的所属簇的编号。然后我们队每一个样本进行遍历,在对每一个均值向量进行遍历,找出每一个样本最近的均值向量,第8行即是在计算当前遍历样本与当前遍历均值向量的距离平方大小。找出 x i x_i xi的最近均值向量 μ j μ_j μj后,即把index_centriod的第i个位置设置为均值向量 μ j μ_j μj对应的簇的编号j。

4、计算每个簇下样本的平均值,得到新的均值向量

def compute_centroid(X,index,k):
    m,d = X.shape
    centriod_mat = np.zeros((k,d))
    for j in range(k):
        l=[]
        for i in range(m):
            if index[i]==j:
                l.append(X[i])
        centriod_mat[j,:]=(sum(l))/len(l)
    return centriod_mat

这里我们遍历每个簇,对于每个簇创建一个列表,用于每个簇对应的样本,遍历每个上面分类得到的关于每个样本所属类别的数组,如果数组第 i i i个位置对应的数为第 j j j个簇对应的编号,那么就相当于我们的第i个样本 x i x_i xi属于第 j j j簇,就将其存放在列表中,最后对 j j j簇对应的列表中的所有样本求平均,即为新的均值向量 μ j μ_j μj,将其存放在已经创建的矩阵的第 j j j行,这个矩阵的第 i i i行存放着第 i i i簇的均值向量。

5、将两个函数整合在一起,即主函数

def run_k_means(X,centriod,max_iter):
    old_centriod=centriod
    for i in range(max_iter):
        old_index=find_closest_centriod(X,old_centriod)
        k = old_centriod.shape[0]
        new_centriod=compute_centroid(X,old_index,k)
        new_index=find_closest_centriod(X,new_centriod)
        if list(new_index)==list(old_index):
            break
        else:
            old_centriod=new_centriod
    return new_index,new_centriod

参数centriod为初始均值向量,max_iter为用户设置的迭代最大次数。如果我们发现迭代前后两次对样本分类结果一样,就立即停止迭代,否则执行到最大迭代次数max_iter

对数据进行聚类

一、处理数据并查看

先查看数据的维度:

data = loadmat('F:\\MachineLearning\data\ex7data2.mat')
X=data['X']
print(X.shape)

得到

(300,2)

即数据为二维,可以对其进行可视化:

#查看数据分布
data2 = pd.DataFrame(X,columns=['x1','x2'])
fig1,ax1=plt.subplots(figsize=(9,6))
ax1.scatter(data2['x1'],data2['x2'],s=20,color='blue')
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()

得到数据分布图:
在这里插入图片描述
很明显,我们可以把数据分为三类。

二、对数据进行聚类

1、首先,我们产生初始均值向量,用上面的initial_centriod函数:

centriod = initial_centriod(X,3)

2、接着,运行主函数进行聚类,并处理数据:

index,centriod=run_k_means(X,centriod,10)
data2['index']=index
data_index1=data2[data2['index']==0]
data_index2=data2[data2['index']==1]
data_index3=data2[data2['index']==2]

,这里我们设置最大迭代次数为10,然后得到了聚类原型,也就是最后一次迭代的均值向量centriod,以及每个样本聚类的结果index。然后我们给数据添加一列,即为index,给出每个样本对应的聚类编号。然后分别把属于簇1、2、3的样本分别存放data_index1data_index2data_index3
3、查看聚类结果

fig2,ax2 = plt.subplots(figsize=(9,6))
ax2.scatter(data_index1['x1'],data_index1['x2'],s=20,color='blue',label='cluster1')
ax2.scatter(data_index2['x1'],data_index2['x2'],s=20,color='red',label='cluster2')
ax2.scatter(data_index3['x1'],data_index3['x2'],s=20,color='green',label='cluster3')
plt.legend()
plt.show()

这里我们将簇1用蓝色表示,簇2用红色表示,簇3用绿色表示:
在这里插入图片描述
发现聚类结果良好。
当然也会发现例如一下这样的情况:
在这里插入图片描述
这样的聚类结果显然是不能令人满意的,这主要是因为我们的初始均值向量的选择会影响聚类结果,然而我们的均值向量是随机产生的,会有一定可能性(可能性较小)选择了“不好”的初始均值向量。如果遇到这种情况我们可以多次运行程序,当然也可以根据数据分布自行选择。

利用聚类算法进行图像压缩

一、查看原图,并产看数据
首先,查看我们需要处理的原图:

from IPython.display import Image,display
display(Image(filename='F:/MachineLearning/data/bird_small.png'))

得到原图:
在这里插入图片描述
接着,处理数据:
先查看数据维度

image_data=loadmat('F:/MachineLearning/data/bird_small.mat')
A=image_data['A']
print(A.shape)
(128, 128, 3)

即数据为三维数组。前两个维度即128和128表示我们的平面图由128128个像素点,第三个维度3表示我们每个像素点的红、蓝、绿的强度。所以我们有128128个样本,样本的维度为3。而我们利用聚类算法进行压缩的原理主要是将我们128*128个样本处理成k个簇,再把每个样本代表的簇的原型代替原先样本,利用这些点组成新的图。

二、利用聚类算法进行压缩图片

A=A/255
X=np.reshape(A,(A.shape[0]*A.shape[1],A.shape[2]))
initial_image_centriod=initial_centriod(X,16)
index,centriod=run_k_means(X,initial_image_centriod,10)
X_recovered = centriod[index.astype(int),:]
X_recovered=np.reshape(X_recovered,(A.shape[0],A.shape[1],A.shape[2]))
plt.imshow(X_recovered)
plt.show()

第一行:归一化数据,让imshow函数可以处理。第二行:我们把样本展开,形成128*128行,3列的样本矩阵,可以让程序处理。第三行:初始化聚类均值向量,这里我们聚类簇数设置为16,簇数决定了压缩图片的还原原图的质量,一般这个值设置的越大,质量越好,同时图片内存也越大。第四行:运行程序。第五行:将原始数据点用聚类原型代替。第六行:再次改变维度使变为图片维度。第七行:形成压缩图片。最后,显示图片。得到图:
在这里插入图片描述
这是我们聚类簇数为16的图。如果我们将第三行聚类簇数设置为32、8和4,会看到如下三图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
会发现参数为32好于参数16,参数为16明显好于参数为8,参数为8明显好于参数为4。这不难理解,聚类簇数相当压缩图片所使用的色彩数,色彩越少,图片质量肯定越差。

三、用sklearn中K-Means库处理此问题

from skimage import io
pic=io.imread('F:/MachineLearning/data/bird_small.png')
pic=pic/255
print(pic.shape)
io.imshow(pic)
plt.show

这里我们直接从原图得到数据,第一行:导入需要的模块。第二行:io.imread将我们的原图处理为数组形式。第三行:归一化。第四行:查看数据维度,为(128, 128, 3)。第五、六行再利用得到数据重构原图。我们会得到:
在这里插入图片描述
这实际上就是原图。

from sklearn.cluster import KMeans
#系数解释:n_cluster:聚类数。n_init:使用初始点次数。n_jobs:是否使用多线程,-1使用。
Cluster = KMeans(n_clusters=4,n_init=100,n_jobs=-1)
Cluster.fit(X)
centriod_pic=Cluster.cluster_centers_
print(centriod_pic)
C=Cluster.predict(data_pic)
pic_recovered=centriod_pic[C].reshape((128,128,3))

上面是调用K-Means库的情况。第一行:导入模块。第三行:设置参数。第四行:拟合数据。第五行:读取聚类原型矩阵。第七行:读取聚类结果C,即每个样本属于簇组成的数组。第八行:再把数据处理成可以图片数组。
这里我们可以得到centriod_pic,聚类原型矩阵:

[[0.48994379 0.40168338 0.32354671]
 [0.1287319  0.13038871 0.12085462]
 [0.91127734 0.8588342  0.74082312]
 [0.79460449 0.63997646 0.41903748]]

最后查看原图和压缩图片的差别:
在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、软件破解之前,先运行下载文件中的magicexif_setup_0813.exe安装软件 2、鼠标双击下载下来的安装程序。如果系统提示“无法验证发布者,您确定要运行此软件吗”请点“运行”按钮。 3、双击安装文件,进入安装程序欢迎页面,点击"next“开始安装,然后根据安装向导完成安装即可; 4、注意,软件安装完成之后,不要启动软件,因为这个破解方法不能在软件运行的情况下进行。将下载文件夹中的MagicEXIF.exe复制到软件的安装目录中替换同名文件 5、然后打开软件,可以看到,注册按钮是会社的,而且显示授权给旗舰版用户,无到期时间说明软件成功注册 软件特点: 1、强大的解码能力,看穿照片背后的一起隐藏信息 MagicEXIF 直接支持 EXIF2.3 和 TIFF6 标准,可从 JPEG/EXIF/TIFF/RAW 等多种文件格式中读取并编辑超过 1500 项 EXIF、GPS 数据,当中包括佳能、尼康、索尼、富士等内的16个常见的设备生产商的厂商注释项目。诸如快门次数、镜头参数、光圈档位,甚至是相机温度、转存次数等都能轻松查看和编辑 2、GPS数据可视化,照片地理信息一览无余 MagicEXIF 不仅可以读取和修改照片中的 GPS 地理数据,更能够通过内置的地图组件将 GPS 数据直接呈现在地图上。MagicEXIF 拥有强大的地图偏移修正功能,能够准确解密并修正 BD-09、GCJ-02 坐标系的偏移,真正实现精确定位。无论是探索自己或他人的旅行足迹,还是往照片中添加地理数据来归档照片、记录旅途,相信您总能找到属于自己的乐趣。对于航拍爱好者,您还可以使用 GPS 批量导入导出工具一次性把 GPS 数据导入到照片中或从照片中导出 3、一键清楚图像编辑历史,网络分享无忧,无惧隐私泄露 许多诸如 Adobe Photoshop 等图像编辑软件在转存图像后会自动插入大量其私有的元数据以方便图像编辑历史的管理,但事实上用户往往并不需要、也察觉不到这些信息。MagicEXIF 可以智能识别出这些私有数据以及其他被修改的项目,并将其彻底清除,从而保护图像的原始性和用户隐私 4、高真度原厂编码引擎,从此不怕原始数据丢失或损坏 MagicEXIF 不仅可以重编码图像的EXIF数据,更能够使用一系列原创的JPEG编码器对图像进行转码操作,从而生成带有原始EXIF数据的JPEG图像。经过 MagicEXIF 重构的图像与原厂数码相机出片并无明显差异,由此用户可以恢复由于压缩或编辑而丢失的图像数据,从此再也不怕原始数据意外丢失或损坏。 5、全面中文和Unicode支持,记录图像的点点滴滴 MagicEXIF 直接支持中文GBK编码,甚至允许用户使用日文JIS编码和Unicode字符插入自定义用户注释,可插入的文字长度超过50kb,能够满足新闻工作者、专业摄影师等以及普通用户对于图像记录和图像归档的需求。 6、批量处理,修改图像属性就是这么轻松 MagicEXIF 允许用户对多个图像文件进行批量操作,可操作的范围涵盖所有标准甚至非标准EXIF、GPS以及其他项目。MagicEXIF 还允许用户使用动态时间,每完成处理一张图的拍摄时间后系统会为这个时间自动加上一个指定范围的值作为下一张图的拍摄时间,整个过程用户无需介入,省时省力 常见问题: 1、运行 MagicEXIF 元数据编辑器有什么要求? MagicEXIF 元数据编辑器运行所需的系统要求很低,在 Windows XP(或 Windows NT 5.1)以上系统上即可顺利安装与运行,并且同时支持 32 位和 64 位的操作系统。但是在 Windows XP 下,因受到系统应用程序接口限制,与 UTC 时间计算有关的功能将无法使用,因此我们推荐使用 Windows 7 以上的操作系统。 2、软件可用编辑 RAW 文件吗? 目前 MagicEXIF 元数据编辑器可以直接打开 RAW 文件并读取当中的 EXIF、XMP 等元数据。但是为了保证 RAW 文件在编辑后的可读性,软件目前并不直接支持 RAW 格式的保存。对于 RAW 文件中的元数据,我们推荐先转存为 EXIF 格式的模板文件,然后再导入到转码后的 TIFF 或 JPEG 图像格式中。 3、照片编辑后会改变底层的数据编码方式或丢失原始信息吗? 传统的图片处理软件(包括 Adobe Photoshop、ACDSee 等在内)或其他 EXIF 编辑器在编辑图像后只能够保证 EXIF 部分数据的可读性,因此使用这些软件编辑图像后往往会令厂商注释、XMP、MPF、压缩特征等非标准 EXIF 部分的数据损坏甚至完全丢失。而 MagicEXIF 元数据编辑器拥有自主研发的强大的编码器,在不改变照片原本编码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值