Image compression for colored images (RGB format)

animal2.jpg image_name.jpg

Note: You can download this .ipynb or .py file by Clicking here.

Importing the libraries

In [1]:
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import svd
from PIL import Image
In [2]:
# To show matplotlib graph inside the jupyte notebook
%matplotlib inline
In [3]:
# replace images with the image you want to compress
images = {
    "Beautiful Nature": np.asarray(Image.open('nature1.jpg')), # getting array of image from image object which will be 3D array
    "Lion": np.asarray(Image.open('animal2.jpg')),
    "Flower (coloured)": np.asarray(Image.open('flower2.jpeg'))
}

Show images without compression

In [4]:
def show_images(img_name):
    'It will show image in widgets'
    print("Loading...")
    plt.title("Image Name: "+img_name+"\n")
    plt.imshow(images[img_name]) # Show image in matplotlib graph
    plt.axis('off') # Do not show axis
    plt.show() # plot the graph
In [5]:
for image in images.keys():
    show_images(image)
Loading...
Loading...
Loading...

Image Compression (RGB)

RGB always stored in 3-D array like (100,50, 3) where 100 is number of rows, 50 is number of columns and 3 shows the values for R, G & B respectively.

Now, we have to split it into three 2D arrays for R, G & B and then apply the SVD on each of three and again merge all to get final compress 3D array of image

In [6]:
def compress_image(img_name, k):
    print("processing...")
    img = images[img_name] # getting image from
    
    # splitting the array into three 2D array (svd only apply on 2D array)
    r = img[:,:,0]  # array for R
    g = img[:,:,1]  # array for G
    b = img[:,:,2] # array for B
    
    print("compressing...")
    
    # Calculating the svd components for all three arrays
    ur,sr,vr = svd(r, full_matrices=False)
    ug,sg,vg = svd(g, full_matrices=False)
    ub,sb,vb = svd(b, full_matrices=False)
    
    # Forming the compress image with reduced information
    # We are selecting only k singular values for each array to make image which will exclude some information from the 
    # image while image will be of same dimension
    
    # ur (mxk), diag(sr) (kxk) and vr (kxn) if image is off (mxn)
    # so let suppose we only selecting the k1 singular value from diag(sr) to form image
    
    rr = np.dot(ur[:,:k],np.dot(np.diag(sr[:k]), vr[:k,:]))
    rg = np.dot(ug[:,:k],np.dot(np.diag(sg[:k]), vg[:k,:]))
    rb = np.dot(ub[:,:k],np.dot(np.diag(sb[:k]), vb[:k,:]))
    
    print("arranging...")
    
    # Creating a array of zeroes; shape will be same as of image matrix
    rimg = np.zeros(img.shape)
    
    # Adding matrix for R, G & B in created array
    rimg[:,:,0] = rr
    rimg[:,:,1] = rg
    rimg[:,:,2] = rb
    
    # It will check if any value will be less than 0 will be converted to its absolute
    # and, if any value is greater than 255 than it will be converted to 255
    # because in image array of unit8 can only have value between 0 & 255
    for ind1, row in enumerate(rimg):
        for ind2, col in enumerate(row):
            for ind3, value in enumerate(col):
                if value < 0:
                    rimg[ind1,ind2,ind3] = abs(value)
                if value > 255:
                    rimg[ind1,ind2,ind3] = 255

    # converting the compress image array to uint8 type for further conversion into image object
    compressed_image = rimg.astype(np.uint8)
    
    # Showing the compressed image in graph
    plt.title("Image Name: "+img_name+"\n")
    plt.imshow(compressed_image)
    plt.axis('off')
    plt.show()
    
    # Uncomment below code if you want to save your compressed image to the file
    #compressed_image = Image.fromarray(compressed_image)
    #compressed_image.save("image_name.jpg")
    
In [7]:
for image in images.keys():
    compress_image(image, 10) # Compressing images only having 10 singular values
processing...
compressing...
arranging...
processing...
compressing...
arranging...
processing...
compressing...
arranging...

You can varify the image compression by checking the difference between size of real image and compressed image (remove last two lines of compress_image function to save images)