Basic Image Manipulation

[CG]Maxime
26.7K views

Crop

Let's start with a very simple operation: cropping. Cropping is the action to cut a part of the image to reframe it.

In order to crop an image, we need to copy in a new image the pixels we want to keep. Let origin be the coordinate of upper-left corner and end the coordinate of the bottom-right corner. The pixel at coordinate (x, y) in the new image is equal to the pixel located at coordinate (x + origin.x, y + origin.y) in the old image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image, ImageDraw
input_image = Image.open("input.png")
# Cropped area
origin = (130, 150)
end = (400, 320)
# Create output image
output_image = Image.new("RGB", (end[0] - origin[0], end[1] - origin[1]))
draw = ImageDraw.Draw(output_image)
# Copy pixels
for x in range(output_image.width):
for y in range(output_image.height):
xp, yp = x + origin[0], y + origin[1]
draw.point((x, y), input_pixels[xp, yp])
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Scale

Scaling is used to change the size of the image. It can be a scale down or up. There are several methods available to interpolate the pixels. We will use the simplest possible algorithm: Nearest Neighbor. Feel free to implement other algorithms such as the Bilinear algorithm, Box sampling, Fourier transform...

To compute the rescaled image, we need the ratio for both horizontal and vertical axes: x_ratio = old_img.x / new_img.x and y_ratio = old_img.y / new_img.y. The pixel at coordinate (x, y) in the new image is equal to the pixel that is located at coordinate (floor(x * x_ratio), floor(y * y_ratio)).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from PIL import Image, ImageDraw
from math import floor
input_image = Image.open("input.png")
new_size = (300, 300)
# Create output image
output_image = Image.new("RGB", new_size)
draw = ImageDraw.Draw(output_image)
x_scale = input_image.width / output_image.width
y_scale = input_image.height / output_image.height
# Copy pixels
for x in range(output_image.width):
for y in range(output_image.height):
xp, yp = floor(x * x_scale), floor(y * y_scale)
draw.point((x, y), input_pixels[xp, yp])
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Flip

A flip (mirror effect) is done by reversing the pixels horizontally or vertically. For instance, for an horizontal flip, the pixel situated at coordinate (x, y) will be situated at coordinate (width - x - 1, y) in the new image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from PIL import Image, ImageDraw
input_image = Image.open("input.png")
# Create output image
output_image = Image.new("RGB", input_image.size)
draw = ImageDraw.Draw(output_image)
# Copy pixels
for x in range(output_image.width):
for y in range(output_image.height):
xp = input_image.width - x - 1
draw.point((x, y), input_pixels[xp, y])
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Rotate

The algorithm used for a rotation is similar to a flip: to compute the new image, we iterate over all the pixels and print the corresponding pixel from the source image.

The point situated at the coordinates (x, y) in the new image is equal to the point (xp, yp) in the input image:

xp = x * cos(angle) - y * sin(angle)
yp = x * sin(angle) + y * cos(angle)


If (xp, yp) is out of the input image, it is ignored (black pixel).

This can be used to do a rotation, however, the center of the rotation will be at coordinate (0, 0). In order to change the coordinates of the center of the rotation, we need to shift the coordinates before the rotation and after the rotation:

xp = (x - center_x) * cos(angle) - (y - center_y) * sin(angle) + center_x
yp = (x - center_x) * sin(angle) + (y - center_y) * cos(angle) + center_y

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from PIL import Image, ImageDraw
from math import sin, cos, pi
input_image = Image.open("input.png")
# Create output image
output_image = Image.new("RGB", input_image.size)
draw = ImageDraw.Draw(output_image)
angle = pi / 3 # angle in radian
center_x = input_image.width / 2
center_y = input_image.height / 2
# Copy pixels
for x in range(input_image.width):
for y in range(input_image.height):
# Compute coordinate in input image
xp = int((x - center_x) * cos(angle) - (y - center_y) * sin(angle) + center_x)
yp = int((x - center_x) * sin(angle) + (y - center_y) * cos(angle) + center_y)
if 0 <= xp < input_image.width and 0 <= yp < input_image.height:
draw.point((x, y), input_pixels[xp, yp])
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Open Source Your Knowledge: become a Contributor and help others learn.