Solarizing the Image with NumPy

Solarizing the Image with NumPy

Introduction

Solarization is a process used in Photography to describe the effect of tone reversal observed in cases of extreme overexposure of the photographic film in the camera. It is a darkroom technique to convert any photograph to look graphic or surrealistic. It often occurs when a very intense light source appears in the picture and is grossly overexposed. It is a technique where the image is partially or completely reversed (inverted) by an extreme overexposure. Original Source - here. With this blog, let's understand the same in a more Pythonic way.

Credits of Cover Image - Photo by engin akyurt on Unsplash

When we are solarizing an image, we mainly consider a threshold pixel value in order to reverse (invert) the image partially or completely. To know more about inverting an image, you can refer to my article here.

We will rely on the PIL library to solarize the image. We will also code the same without using the PIL module and by just using NumPy for the matrix operations.

Time to Code

The packages that we mainly use are:

  • NumPy
  • Matplotlib
  • OpenCV
  • PIL

python_packages.png

import the Packages

import numpy as np
import cv2
import json

from PIL import Image
from PIL import ImageOps as ipo

from matplotlib import pyplot as plt

Code Implementation with Library

We use the method solarize() available in the module ImageOps - part of the main module PIL. The method takes the following arguments -

  • image → image file that needs to solarized.
  • threshold → threshold value to either partially or completely reverse (invert) the image.

Now that we have all the requirements, let's write the function that solarizes the image.

def solarize_lib(image_file, thresh_val, gray_scale=False):
    image_src = Image.open(image_file)
    image_src = image_src.convert('L') if gray_scale else image_src

    image_sol = ipo.solarize(image_src, threshold=thresh_val)

    cmap_val = None if not gray_scale else 'gray'
    fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 20))

    ax1.axis("off")
    ax1.title.set_text('Original')

    ax2.axis("off")
    ax2.title.set_text("Solarized")

    ax1.imshow(image_src, cmap=cmap_val)
    ax2.imshow(image_sol, cmap=cmap_val)
    return True

The above function solarizes the images that are read both in colored mode or grayscale mode. Let's test the same.

solarize_lib(image_file='scenary.jpg', thresh_val=130)

For RGB image

solarize_libc.png

For grayscale image

solarize_libg.png

Above are the results of the images that are solarized.

Code Implementation from Scratch

For coding from scratch, we are relying on the NumPy module since matrix operations can be achieved with so much ease. We will need to validate for both colored images as well as grayscale images.

Read the Image

def read_this(image_file, gray_scale=False):
    image_src = cv2.imread(image_file)
    if gray_scale:
        image_src = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
    else:
        image_src = cv2.cvtColor(image_src, cv2.COLOR_BGR2RGB)
    return image_src

The above function reads the image either in grayscale or RGB and returns the image matrix.

As above we will have a thresh_val argument based on which the partial or complete reversing (inverting) be done.

def solarize_this(image_file, thresh_val, with_plot=False, gray_scale=False):
    image_src = read_this(image_file=image_file, gray_scale=gray_scale)

    if not gray_scale:
        r_image, g_image, b_image = image_src[:, :, 0], image_src[:, :, 1], image_src[:, :, 2]
        ## inverting the colored image (partially)
        r_sol = np.where((r_image < thresh_val), r_image, ~r_image)
        g_sol = np.where((g_image < thresh_val), g_image, ~g_image)
        b_sol = np.where((b_image < thresh_val), b_image, ~b_image)
        image_sol = np.dstack(tup=(r_sol, g_sol, b_sol))
    else:
        ## inverting the grayscale image (partially)
        image_sol = np.where((image_src < thresh_val), image_src, ~image_src)

    if with_plot:
        cmap_val = None if not gray_scale else 'gray'
        fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 20))

        ax1.axis("off")
        ax1.title.set_text('Original')

        ax2.axis("off")
        ax2.title.set_text("Solarized")

        ax1.imshow(image_src, cmap=cmap_val)
        ax2.imshow(image_sol, cmap=cmap_val)
        return True
    return image_sol

We are using the where() method of NumPy to find out those pixels which are less than thresh_val and inverting the same which are greater. Let's test the function.

For RGB image

solarize_this(
    image_file='scenary.jpg', 
    thresh_val=130, 
    with_plot=True
)

solarize_libc.png

For grayscale image

solarize_this(
    image_file='lena_original.png', 
    thresh_val=120, 
    with_plot=True, 
    gray_scale=True
)

solarize_libg.png

PIL is a great library and so is NumPy. PIL is easy to use and the results can be obtained with less code. It is great for researchers and beginners. Implementing the same from scratch is what I have gained.


Here I take leave. If you have liked it consider visiting this page to read more on Image Processing. And make sure to buy coffee for me from here.