使用PCA对彩色图片降维

PCA对图片降维

  • 1.原图片
  • 2.PCA降维思路
  • 3.代码
  • 4.k=5效果图
  • 5.结论

1.原图片

使用PCA对彩色图片降维_第1张图片

2.PCA降维思路

    1、小灰灰图片(407,367)
    2、求图片407行每行的均值mean,再将407行每行元素各自减去对应行的均值mean,即去中心化。得矩阵X(407,367)
    3、为求特征,需要矩阵X为方阵,故方阵C=X^T * X。的矩阵C(367,367)
    4、求C的特征值(367,1)和特征向量(367,367)
    5、取前k个最大特征值对应的特征向量。得k个特征向量Vec,也就是k个基(367,k)
    6、将去中心化了的原图片矩阵X在这k个基中投影,在基中降维为k的新矩阵D=X * Vec。得D(407,k)
      [注]因为Vec矩阵(367,k)中k的不同取值,会导致原图丢失信息,故恢复后的图片与原图片不同
           另外,当k=367时,将不会丢失信息,k值越少,丢失信息越多,因为降维只取了k个最主要的成分
    7、将降维后的矩阵恢复为图片:X'=D * Vec^T。得X'(407,367)
      [注]因此降维后图片与原图尺寸相同

3.代码

from PIL import Image

import numpy as np
import os

"""
    参数说明:
        file_path:该路径存放原图片和产生的灰度图片
        work_path:该路径存放pca处理后的图片,图片编号代表此图片使用了多少特征数
        img_path:用于判断,不必理会
"""
file_path = './img/'
work_path = './pcaImg/'
img_path = file_path + '1.jpg'

#用于创建文件夹,不必理会
if not os.path.exists(file_path):
    os.mkdir(file_path)
if not os.path.exists(img_path):
    print('请在img文件夹中添加一张照片并将其命名为1.jpg')
    exit()
if not os.path.exists(work_path):
    os.mkdir(work_path)

"""
    函数功能:将原图片变为灰度图片
    参数说明:
        path:原图片路径
    输出说明:
        data:灰度图片像素数组
"""
def loadImage(path):
    # 打开图片
    img = Image.open(path)
    # 将图像转换成灰度图
    img = img.convert("L")
    # 图像对象,可变为数组
    data = img.getdata()
    # size中1为长,0为宽
    # 为了避免溢出,这里对数据进行一个缩放,缩小100倍
    data = np.array(data).reshape(img.size[1], img.size[0])/100
    # 查看原图的话,需要还原数据
    new_im = Image.fromarray(data*100)
    # 将图片保存在路径中
    # 一定要写convert()不然会一直报错cannot write mode F as JPEG或者keyerror
    new_im.convert('RGB').save(file_path+'gImg.jpg', format='jpeg')
    # 展示灰度图片
    # new_im.show()
    return data

"""
    函数功能:使用pca对灰度图片进行降维处理
    参数说明:
        data:灰度图路径
        k:主成分个数
    输出说明:
        pass
"""
def pca(data, k):
    # 求图片每一行的均值
    mean = np.array([np.mean(data[:, index]) for index in range(data.shape[1])])
    # 去中心化
    normal_data = data - mean
    # 得到协方差矩阵:1/n*(X * X^T),这里不除以n也不影响
    matrix = np.dot(np.transpose(normal_data), normal_data)
    # 此函数可用来计算特征值及对应的特征向量
    # eig_val存储特征值,eig_vec存储对应的特征向量
    eig_val, eig_vec = np.linalg.eig(matrix)
    # 对矩阵操作,按从小到大的顺序对应获得此数的次序(从0开始)
    # 比如说有矩阵[2,1,3,1]
    # 那么将按数组的顺序[1,123]输出对应的下标
    # 即[2130]
    eig_index = np.argsort(eig_val)
    # 取下标的倒数k位,也就是取前k个大特征值的下标
    eig_vec_index = eig_index[:-(k+1):-1]
    # 取前k个大特征值的特征向量
    feature = eig_vec[:, eig_vec_index]
    # 将特征值与对应特征向量矩阵乘得到最后的pca降维图
    new_data = np.dot(normal_data, feature)
    # 将降维后的数据映射回原空间
    rec_data = np.dot(new_data, np.transpose(feature)) + mean
    # 压缩后的数据也需要乘100还原成RGB值的范围
    newImage = Image.fromarray(np.uint8(rec_data*100))
    # 将处理好的降维图片存入文件夹
    newImage.convert('RGB').save(work_path + 'k=' + str(k) + '.jpg')
    # newImage.show()

if __name__ == '__main__':
    data = loadImage(img_path)

    for i in range(1, data.shape[1]+1):
        pca(data, i)
        print('正在处理第', str(i) + '/' + str(data.shape[1]), '张图片')

    print('处理完成,请查看pcaImg文件夹')

4.k=5效果图

使用PCA对彩色图片降维_第2张图片

5.结论

该程序可以处理任何图片,请随意使用。如果有问题请留言。

你可能感兴趣的:(pca降维)