How to do it...

Let's see how to compress an image using vector quantization:

  1. The full code for this recipe is given in the vector_quantization.py file that has already been provided to you. Let's take a look at how it's built. We'll start by importing the required packages. Create a new Python file, and add the following lines:
import argparse 
 
import numpy as np 
from scipy import misc  
from sklearn import cluster 
import matplotlib.pyplot as plt
  1. Let's create a function to parse the input arguments. We will be able to pass the image and the number of bits per pixel as input arguments:
def build_arg_parser(): 
    parser = argparse.ArgumentParser(description='Compress the input image \ 
            using clustering') 
    parser.add_argument("--input-file", dest="input_file", required=True, 
            help="Input image") 
    parser.add_argument("--num-bits", dest="num_bits", required=False, 
            type=int, help="Number of bits used to represent each pixel") 
    return parser 
  1. Let's create a function to compress the input image:
def compress_image(img, num_clusters): 
    # Convert input image into (num_samples, num_features)  
    # array to run kmeans clustering algorithm  
   X = img.reshape((-1, 1))   
 
    # Run kmeans on input data 
    kmeans = cluster.KMeans(n_clusters=num_clusters, n_init=4, random_state=5) 
    kmeans.fit(X) 
    centroids = kmeans.cluster_centers_.squeeze() 
    labels = kmeans.labels_ 
 
    # Assign each value to the nearest centroid and  
    # reshape it to the original image shape 
    input_image_compressed = np.choose(labels, centroids).reshape(img.shape) 
 
    return input_image_compressed 
  1. Once we compress the image, we need to see how it affects the quality. Let's define a function to plot the output image:
def plot_image(img, title): 
    vmin = img.min() 
    vmax = img.max() 
    plt.figure() 
    plt.title(title) 
    plt.imshow(img, cmap=plt.cm.gray, vmin=vmin, vmax=vmax)
  1. We are now ready to use all these functions. Let's define the main function that takes the input arguments, processes them, and extracts the output image:
if __name__=='__main__': 
    args = build_arg_parser().parse_args() 
    input_file = args.input_file 
    num_bits = args.num_bits 
 
    if not 1 <= num_bits <= 8: 
        raise TypeError('Number of bits should be between 1 and 8') 
 
    num_clusters = np.power(2, num_bits) 
 
    # Print compression rate 
    compression_rate = round(100 * (8.0 - args.num_bits) / 8.0, 2) 
    print("The size of the image will be reduced by a factor of", 8.0/args.num_bits) 
    print("Compression rate = " + str(compression_rate) + "%") 
  1. Let's load the input image:
    # Load input image 
    input_image = misc.imread(input_file, True).astype(np.uint8) 
 
    # original image  
    plot_image(input_image, 'Original image') 
  1. Now, let's compress this image using the input argument:
    # compressed image  
    input_image_compressed = compress_image(input_image, num_clusters) 
    plot_image(input_image_compressed, 'Compressed image; compression rate = '  
            + str(compression_rate) + '%') 
 
    plt.show() 
  1. We are now ready to run the code; run the following command on your Terminal:
    $ python vector_quantization.py --input-file flower_image.jpg --num-bits 4

The following results are returned:

The size of the image will be reduced by a factor of 2.0
Compression rate = 50.0%

The input image looks like the following:

You should get a compressed image as the output:

  1. Let's compress the image further by reducing the number of bits to 2. Run the following command on your Terminal:
    $ python vector_quantization.py --input-file flower_image.jpg --num-bits 2  

The following results are returned:

The size of the image will be reduced by a factor of 4.0
Compression rate = 75.0%

You should get the following compressed image as the output:

  1. If you reduce the number of bits to 1, you can see that it will become a binary image with black and white as the only two colors. Run the following command:
    $ python vector_quantization.py --input-file flower_image.jpg --num-bits 1  

The following results are returned:

The size of the image will be reduced by a factor of 8.0
Compression rate = 87.5%

You will get the following output:

We have seen how, by compressing the image further, the quality of the image has undergone considerable downsizing.