Title: Apply a shifting transformation to images in Python
The following examples show how you can use NumPy to apply transformations to images.
Both of those examples converted pixel locations into polar coordinates, transformed the pixel positions, and then transformed back to Cartesian coordinates.
This example performs its transformation in Cartesian coordinates. It shifts an image with a sinusoidal pattern vertically and horizontally. The Scale widgets let you determine the periods and magnitudes of the patterns. Here are three examples.
| Shift X | Shift Y | Shift X and Y |
![[An image warped by a shifting in the X direction]](image_shifter1.png) |
![[An image warped by a shifting in the Y direction]](image_shifter2.png) |
![[An image warped by a shifting in the X and Y directions]](image_shifter3.png) |
Waving Images
The following apply_shifter function shifts an image's pixels vertically, horizontally, or both. It's a bit simpler than the code used in the previous example, though it's still confusing enough. The key pieces are highlighted in blue.
def apply_shifter(image, x_period, x_scale, y_period, y_scale, ):
'''Shift pixels by x_scale * sin(x/(2*x_period)) and similarly for y.'''
# Convert the image to a NumPy array.
image_array = np.array(image)
# Create a grid of target pixel coordinates (y, x).
hgt, wid, channels = image_array.shape
y_indices, x_indices = np.indices((hgt, wid))
# Define X and Y offsets.
x_offsets = x_scale * np.sin(y_indices * (2 * math.pi) / y_period)
y_offsets = y_scale * np.sin(x_indices * (2 * math.pi) / x_period)
# Add the X and Y offsets.
x_shifted = x_indices + x_offsets
y_shifted = y_indices + y_offsets
# Reconstruct the image channels using interpolation.
output_array = np.zeros_like(image_array)
for c in range(channels):
output_array[:, :, c] = map_coordinates(
image_array[:, :, c],
[y_shifted, x_shifted],
order=3, # Cubic spline interpolation for high quality
mode='constant', # Fill black colors outside bounds
cval=0,
)
# Convert the result to a PIL image.
return Image.fromarray(output_array)
This code converts the image's pixels into a NumPy array and gets the array's shape as before. It then multiplies the X scale by the np.sin function to get the pixels' shifts in the X direction. Notice that the X shift depends on the Y parameters. As Y changes, a pixel's X coordinate is shifted. Also notice how the code multiples each pixel's index in the np.sin function by (2 * math.pi) / y_period so the sine function repeats every y_period pixels.
The function performs similar steps to shift the pixels' Y coordinates.
After it calculates the X and Y shifts, the code adds them to the pixels' X and Y coordinates and then uses them to rebuild the image as in the previous examples.
The rest of the program is similar to the one in the previous examples.
Conclusion
The main difference between this example and the previous ones is that this one doesn't use polar coordinates.
Download the example to experiment with it and to see additional details. You may find it easier to experiment with the grid pattern than with a picture, at least until you get the hang of it.
|