# Basic Image Manipulation

[CG]Maxime
37.6K views

## Filtering

A lot of image processing algorithms rely on the convolution between a kernel (typicaly a 3x3 or 5x5 matrix) and an image. This may sound scary to some of you but that's not as difficult as it sounds:

Let's take a 3x3 matrix as our kernel. For each pixel, the filter multiplies the current pixel value and the other 8 surrounding pixels by the kernel corresponding value. Then it adds the result to get the value of the current pixel. Let's see an example:

In this example, the value of each pixel is equal to the double of the pixel that was located above it (e.g. 92 = 46 x 2).

## Blur

A simple blur can be done using this kernel:

$\frac{1}{9}\left[\begin{array}{ccc}1& 1& 1\\ 1& 1& 1\\ 1& 1& 1\end{array}\right]$

This is called the Box Blur. Each pixel is computed as the average of the surrounding pixels.

And here is the kernel for the Gaussian Blur:

$\frac{1}{256}\left[\begin{array}{ccccc}1& 4& 6& 4& 1\\ 4& 16& 24& 16& 4\\ 6& 24& 36& 24& 6\\ 4& 16& 24& 16& 4\\ 1& 4& 6& 4& 1\end{array}\right]$

As you can see, it's a weighted mean of the surrounding pixels that gives more weight to the pixel near the current pixel.

Blur
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from PIL import Image, ImageDraw
input_image = Image.open("input.png")
# Box Blur kernel
box_kernel = [[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9]]
# Gaussian kernel
gaussian_kernel = [[1 / 256, 4 / 256, 6 / 256, 4 / 256, 1 / 256],
[4 / 256, 16 / 256, 24 / 256, 16 / 256, 4 / 256],
[6 / 256, 24 / 256, 36 / 256, 24 / 256, 6 / 256],
[4 / 256, 16 / 256, 24 / 256, 16 / 256, 4 / 256],
[1 / 256, 4 / 256, 6 / 256, 4 / 256, 1 / 256]]
# Select kernel here:
kernel = box_kernel
# Middle of the kernel
offset = len(kernel) // 2
# Create output image
output_image = Image.new("RGB", input_image.size)
draw = ImageDraw.Draw(output_image)
# Compute convolution between intensity and kernels
for x in range(offset, input_image.width - offset):
for y in range(offset, input_image.height - offset):
acc = [0, 0, 0]
for a in range(len(kernel)):
for b in range(len(kernel)):
xn = x + a - offset
yn = y + b - offset
pixel = input_pixels[xn, yn]
acc[0] += pixel[0] * kernel[a][b]
acc[1] += pixel[1] * kernel[a][b]
acc[2] += pixel[2] * kernel[a][b]
draw.point((x, y), (int(acc[0]), int(acc[1]), int(acc[2])))
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

## Edge detection

There are multiple ways to do edge detection. We will present the Sobel Operator here.

The Sobel Operator uses two kernels (one for each direction): ${K}_{x}=\left[\begin{array}{ccc}-1& 0& 1\\ -2& 0& 2\\ -1& 0& 1\end{array}\right]$ and ${K}_{y}=\left[\begin{array}{ccc}-1& -2& -1\\ 0& 0& 0\\ 1& 2& 1\end{array}\right]$.

We compute the convolution between the image (converted in black and white) and the two kernels separately. That gives us, for each pixel, the values $ma{g}_{x}$ and $ma{g}_{y}$. The value of the current pixel is set at $\sqrt{ma{g}_{x}^{2}+ma{g}_{y}^{2}}$.

Sobel operator
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
27
28
29
30
31
32
33
34
35
36
37
38
from PIL import Image, ImageDraw
from math import sqrt
input_image = Image.open("input.png")
# Calculate pixel intensity as the average of red, green and blue colors.
intensity = [[sum(input_pixels[x, y]) / 3 for y in range(input_image.height)] for x in range(input_image.width)]
# Sobel kernels
kernelx = [[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]]
kernely = [[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]]
# Create output image
output_image = Image.new("RGB", input_image.size)
draw = ImageDraw.Draw(output_image)
# Compute convolution between intensity and kernels
for x in range(1, input_image.width - 1):
for y in range(1, input_image.height - 1):
magx, magy = 0, 0
for a in range(3):
for b in range(3):
xn = x + a - 1
yn = y + b - 1
magx += intensity[xn][yn] * kernelx[a][b]
magy += intensity[xn][yn] * kernely[a][b]
# Draw in black and white the magnitude
color = int(sqrt(magx**2 + magy**2))
draw.point((x, y), (color, color, color))
output_image.save("output.png")
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Open Source Your Knowledge: become a Contributor and help others learn.