为啥我执行 PCA 后图像文件的大小会增加?

Posted

技术标签:

【中文标题】为啥我执行 PCA 后图像文件的大小会增加?【英文标题】:Why does the size of the image file increase after I performed PCA?为什么我执行 PCA 后图像文件的大小会增加? 【发布时间】:2021-12-08 13:10:25 【问题描述】:

我正在为美国的鹿种创建一个图像分类模型,我目前正在对这些图像执行 PCA,以减少它们的内存大小并减少模型的运行时间。

我知道主成分分析应该在不放弃太多方差的情况下减少数据集的维度。因此,当我注意到通过我的Deer_PCA 函数运行的所有新 PCA 压缩图像都比原始图像大时,我有点困惑。原始图像为 128 KB,新的压缩图像在 n_components = 150 运行后为 293 KB。有谁知道为什么会这样?

这是我在函数中运行的图片,在运行代码之前将图片放在一个空文件夹中:

这是通过Deer_PCA 函数运行后的新压缩图像:

这是我的代码:

#import some packages

import cv2
import os,sys
from PIL import Image
import pandas as pd

from scipy.stats import stats
from sklearn.decomposition import PCA

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

#Let's write a function to perform PCA on all the images in the folder and output it to a new folder

#inpath = folder containing the image - string value 
#outpath = which folder do I want the new compressed image saved to. - string value
#n_comp = number of components - int value

        
def Deer_PCA(inpath, outpath,n_comp):
    for image_path in os.listdir(inpath):

        # create the full input path and read the file
        input_path = os.path.join(inpath, image_path)
        print(input_path)
        
        w_deer = cv2.cvtColor(cv2.imread(input_path), cv2.COLOR_BGR2RGB)

        #split image
        blue_2,green_2,red_2 = cv2.split(w_deer)

        #scale channels
        w_blue = blue_2/255
        w_green = green_2/255
        w_red = red_2/255

        #PCA on each channel
        pca_b2 = PCA(n_components=n_comp)
        pca_b2.fit(w_blue)            
        trans_pca_b2 = pca_b2.transform(w_blue)

        pca_g2 = PCA(n_components=n_comp)
        pca_g2.fit(w_green)
        trans_pca_g2 = pca_g2.transform(w_green)

        pca_r2 = PCA(n_components=n_comp)
        pca_r2.fit(w_red)
        trans_pca_r2 = pca_r2.transform(w_red)

        #merge channels after PCA
        b_arr2 = pca_b2.inverse_transform(trans_pca_b2)
        g_arr2 = pca_g2.inverse_transform(trans_pca_g2)
        r_arr2 = pca_r2.inverse_transform(trans_pca_r2)

        img_reduced2 = (cv2.merge((b_arr2, g_arr2, r_arr2)))
        
        print("Merge Successful")

        # create the full output path
        fullpath = os.path.join(outpath, 'PCA_'+image_path)
        cv2.imwrite(fullpath, img_reduced2*255)
        
        print("Successfully saved\n")
        
#Check the image sizes 

original_image_path = '/Users/matthew_macwan/Downloads/CIS/I_Class_Deer/mule_deer_doe/mule deer doe_1.jpeg'

PCA_compressed_image_path = '/Users/matthew_macwan/Downloads/CIS/I_Class_Deer/mule_deer_doe/PCA_mule deer doe_1.jpeg'

print('Original Image:',sys.getsizeof(original_image_path))

print('PCA Image:',sys.getsizeof(PCA_compressed_image_path))

【问题讨论】:

您处理了一张我们看不到的图像并获得了另一张我们也看不到的图像,您想知道为什么一张更大?来吧——如果你想让人们帮助你,让他们轻松一点。谢谢。 我很抱歉。我不是一个真正使用 *** 的人。无论我使用什么图像,PCA 压缩后的图像总是比原始图像大。所以我认为问题出在代码上,并且认为信息就足够了。我会上传图片。 我不确定您将 PCA 单独应用于每个通道并在之后重新组合的方法是否合法。通常,您会使用 PCA 来降低维度,例如您可能有一个 225 通道的高光谱图像,并希望将其减少到只有 3 个通道,其中包含大部分方差以进行可视化。您似乎将通道分开处理并保留它们,这似乎不太可能减少任何东西。我很可能是错的,并且可能还有其他一些我不知道的 PCA 用途。也许 Fred @fmw42 会发表评论? 【参考方案1】:

这里有一些误解。当你像这样对单个图像进行 PCA 时,它会将每一列(或每一行,不确切知道)作为一个观察值。然后它将图像减少到 150 行(或列),确实减少了数据量,并且可能还减少了这些数据中包含的信息量。

然后你从 PCA 重建原始图像,得到一个与原始图像大小相同的数组,并将其保存为 JPEG。您没有更少的数据点要存储。图像总体上可能包含较少的信息,但减少信息的方式与JPEG减少信息的方式不同,因此JPEG算法不太可能受益,不太可能以更少的字节保存这些数据。

您的输出 JPEG 明显大于输入可能是由于 PCA 更改实际上使 JPEG 算法变得更加困难,或者是 JPEG 算法的质量设置(或两者的组合)。降低 JPEG 压缩的质量设置是使 JPEG 文件更小的最佳方法。

如果要使用 PCA 压缩图像文件,则必须保存 PCA 基向量和投影到这些向量中的图像。我怀疑这是压缩图像的有效方法。

压缩图像的一种完全不同的方法是获取大量图像集合,通过将所有样本值放在一行中,将每个图像组成一个向量,然后将 PCA 应用于集合。 PCA 基向量形成一个“字典”,现在每个图像都由这些基向量的线性组合表示,这意味着您只需要存储权重,每个基向量一个值。再说一次,不能保证这是有效的,我这样说是为了说明 PCA 是如何工作的。您能做的最好的事情就是坚持使用众所周知且经过测试的图像压缩方法,例如 JPEG 和 JPEG2000。


当我到达那个点时减少他们的内存大小并减少模型的运行时间。

请注意,文件大小与模型必须完成的工作量无关。当您将图像从文件读入内存时,您会获得一定数量的像素。模型必须处理所有这些像素。在这一点上,数据在磁盘上占用多少空间是无关紧要的。如果你想让模型更快,减少图像中的像素数,你可以通过二次采样来做到这一点。但请确保您仍然可以识别模型在重新采样后需要识别的任何内容。如果删除太多像素,您将无法区分鹿和老鼠!

【讨论】:

所以如果我理解正确的话,我在这里使用的 PCA 函数不会减少 JPEG 图像大小,也不会减少图像中的像素数(这不会减少模型的运行时间)。 另外,我将研究对这些鹿图像进行二次采样。谢谢。

以上是关于为啥我执行 PCA 后图像文件的大小会增加?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Imagemagick 或 GraphicsMagick 在调整为较小尺寸时会增加我的 PNG 图像的 MB 大小?

磁盘上的图像文件大小(KB)随着Java中动态图像大小的调整(减小大小)而增加

为啥程序读取图像文件后分辨率会变小?

为啥切换轮播后背景图像的大小会发生变化?

为啥 Qt 中图像的大小会增加?

为啥当我滚动浏览 UITableView 时图像会不断调整大小?