Home > Back-end >  Why does the size of the image file increase after I performed PCA?
Why does the size of the image file increase after I performed PCA?

Time:10-24

I'm creating an image classification model on species of deer in the USA and I'm currently performing PCA on these images to reduce their memory size and reduce the run time of the model when I get to that point.

I know that Principal Component Analysis is supposed to reduce the dimensions of a dataset without giving up too much variance. So I'm a bit confused when I noticed that all the new PCA compressed images that ran through my Deer_PCA function are larger than the original image. The original image was 128 KB and the new compressed image is 293 KB after running it at n_components = 150. Does anyone have any idea why this is occurring?

Here's the picture I ran in the function, put the image in an empty folder before running the code: input pic

Here's the new compressed image after running it through the Deer_PCA function: output pic

Here is my code:

#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))

CodePudding user response:

There is some misunderstanding here. When you do PCA on a single image like this, it takes each column (or row, don’t know exactly) as an observation. It then reduces the image to 150 rows (or columns), indeed reducing the amount of data, and likely also reducing the amount of information contained in those data.

But then you reconstruct the original image from the PCA, getting an array of the same size as the original, and save that as JPEG. You don’t have fewer data points to store. The image may contain less information overall, but the way that the information is reduced is not the same way that JPEG reduces information, and so the JPEG algorithm is unlikely to benefit, it is unlikely to be able to save those data with fewer bytes.

That your output JPEG is significantly larger than the input could be caused by the PCA alterations actually making things harder on the JPEG algorithm, or by the quality setting of the JPEG algorithm (or a combination of both). Reducing the quality setting of the JPEG compression is the best way to make JPEG files smaller.

If you want to use PCA to compress image files, you must save the PCA basis vectors and the image projected into those vectors. I doubt that this is an effective way to compress images.

A wholly different way to compress images is to take a large collection of them, making each one into a vector by putting all its sample values in a row, then applying PCA to the collection. The PCA basis vectors form a “dictionary”, and each image is now represented by a linear combination of these basis vectors, meaning you only need to store the weights, one value per basis vector. It again, there is no guarantee that this is effective, I’m stating this to illustrate how PCA works. The best thing you can do is stick to well known and tested methods of image compression such as JPEG and JPEG2000.


to reduce their memory size and reduce the run time of the model when I get to that point.

Note that the file size does not relate to the amount of work the model has to do. When you read the image from the file into memory, you get a certain number of pixels. The model has to process all these pixels. How much space the data take up on disk is irrelevant at this point. If you want to make the model faster, reduce the number of pixels in the image, which you can do by subsampling. But be sure you can still recognize whatever the model needs to recognize after resampling. If you remove too many pixels, you won’t be able to tell a deer from a mouse!

  • Related