Crop the Image Intuitively — NumPy

Crop the Image Intuitively — NumPy

Introduction

In this blog article, we will learn how to crop an image in Python using NumPy as an ideal library. When we talk about images, they are just matrices in 2D space. And of course, it depends on the image, if it is an RGB image then the size of the image would be (width, height, 3) otherwise — grayscale would just be (width, height). But ultimately, images are just large matrices where each value is a pixel positioned row-wise and column-wise accordingly.

Credits of Cover Image - Photo by Ulrike Langner on Unsplash

Cropping the image is just obtaining the sub-matrix of the image matrix. The size of the sub-matrix (cropped image) can be of our choice and mainly it is the height and width. There needs to be one important thing for the image to be cropped, i.e., starting position. The starting position is helpful for obtaining the sub-matrix from that position and depending upon height and width we can easily crop cut the image.

The three important things are:

  • starting_position
  • length (height)
  • width

Based on these three things, we can construct our cropping function completely ready.

Time to Code

The packages that we mainly use are:

  • NumPy
  • Matplotlib
  • OpenCV → It is only used for reading the image.

python_packages.png

Import the Packages

import numpy as np
import cv2
import json
from matplotlib import pyplot as plt

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.

Cropping the Image

We need to pass the above mentioned 3 things as arguments in our function. But before doing let’s try to crop (slice) the matrix with NumPy.

>>> import numpy as np
>>> m = np.array([
...     [1, 2, 3, 4, 5, 6, 7],
...     [5, 3, 4, 2, 1, 7, 6],
...     [6, 4, 3, 5, 1, 2, 7],
...     [5, 6, 3, 1, 4, 2, 7],
...     [1, 2, 3, 4, 5, 6, 7]
... ])
>>>
>>> print(m)
[[1 2 3 4 5 6 7]
 [5 3 4 2 1 7 6]
 [6 4 3 5 1 2 7]
 [5 6 3 1 4 2 7]
 [1 2 3 4 5 6 7]]
>>>
>>> crop_m = m[1:4, 2:7]
>>> print(crop_m)
[[4 2 1 7 6]
 [3 5 1 2 7]
 [3 1 4 2 7]]
>>>

The above code is an example of how we can crop an image matrix. Notice crop_m is the cropped matrix (sub-matrix) that is sliced from the original matrix m. The sub-matrix crop_m is taking values from [1:4, 2:7], i.e., values from 1st row till 4th row and from 2nd column till 7th column. We should something similar for the image to obtain the cropped image. Let’s write the cropping image function.

def crop_this(image_file, start_pos, length, width, with_plot=False, gray_scale=False):
    image_src = read_this(image_file=image_file, gray_scale=gray_scale)
    image_shape = image_src.shape

    length = abs(length)
    width = abs(width)

    start_row = start_pos if start_pos >= 0 else 0
    start_column = start_row

    end_row = length + start_row
    end_row = end_row if end_row <= image_shape[0] else image_shape[0]

    end_column = width + start_column
    end_column = end_column if end_column <= image_shape[1] else image_shape[1]

    print("start row \t- ", start_row)
    print("end row \t- ", end_row)
    print("start column \t- ", start_column)
    print("end column \t- ", end_column)

    image_cropped = image_src[start_row:end_row, start_column:end_column]
    cmap_val = None if not gray_scale else 'gray'

    if with_plot:
        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("Cropped")

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

Let’s understand what this function will actually result in.

  1. At the first step, we read the image either in grayscale or RGB and obtain the image matrix.
  2. We obtain the height and width of the image which is further used in the validation of the code.
  3. We make sure that the length and width are positive integers. Hence absolute values are considered.
  4. We calculate the four important values which are useful for slicing the matrix start_row, end_row, start_column, end_column. We obtain that using the three arguments that are passed — start_pos, length, width.
  5. We obtain the cropped image by slicing the matrix.
  6. We plot both the original and cropped images for the visualization.

Let’s test the above function —

For RGB Image

crop_this(
    image_file='lena_original.png',
    start_pos=199,
    length=100,
    width=200,
    with_plot=True
)
start row -  199
end row -  299
start column -  199
end column -  399

cropc_lena.png

For Grayscale Image

crop_this(
    image_file='lena_original.png',
    start_pos=199,
    length=100,
    width=200,
    with_plot=True,
    gray_scale=True
)
start row -  199
end row -  299
start column -  199
end column -  399

cropg_lena.png


This is it!!! We finally are able to crop the image by just knowing the starting position and length & width of the cropped image. Isn’t it great? We can also add a lot of customization options like adding a border around the image and other things. To know how to add a border to the image, you can refer to my article.

Other similar articles can be found in my profile. Have a great time reading and implementing the same.

If you liked it, you can buy coffee for me from here.

bmc-button.png