I was looking for a pure-Python (no external library) rescaling code for something I’m working on. I realized the options are limited, even with Numpy. Most of the solutions recommend using OpenCV or SciPy. I ended up putting together this solution which meets my needs (arbitrary size + smooth rescale).

Original reply: https://stackoverflow.com/a/69157357/2000521

Code:

**import **math

**import **numpy

**def **resize_linear(image_matrix, new_height:int, new_width:int):

*"""Perform a pure-numpy linear-resampled resize of an image."""*

* *output_image = numpy.zeros((new_height, new_width), dtype=image_matrix.dtype)

original_height, original_width = image_matrix.shape

inv_scale_factor_y = original_height/new_height

inv_scale_factor_x = original_width/new_width

*# This is an ugly serial operation.*

* ***for **new_y **in **range(new_height):

**for **new_x **in **range(new_width):

*# If you had a color image, you could repeat this with all channels here.*

* # Find sub-pixels data:*

* *old_x = new_x * inv_scale_factor_x

old_y = new_y * inv_scale_factor_y

x_fraction = old_x - math.floor(old_x)

y_fraction = old_y - math.floor(old_y)

*# Sample four neighboring pixels:*

* *left_upper = image_matrix[math.floor(old_y), math.floor(old_x)]

right_upper = image_matrix[math.floor(old_y), min(image_matrix.shape[1] - 1, math.ceil(old_x))]

left_lower = image_matrix[min(image_matrix.shape[0] - 1, math.ceil(old_y)), math.floor(old_x)]

right_lower = image_matrix[min(image_matrix.shape[0] - 1, math.ceil(old_y)), min(image_matrix.shape[1] - 1, math.ceil(old_x))]

*# Interpolate horizontally:*

* *blend_top = (right_upper * x_fraction) + (left_upper * (1.0 - x_fraction))

blend_bottom = (right_lower * x_fraction) + (left_lower * (1.0 - x_fraction))

*# Interpolate vertically:*

* *final_blend = (blend_top * y_fraction) + (blend_bottom * (1.0 - y_fraction))

output_image[new_y, new_x] = final_blend

**return **output_image