Loading [MathJax]/jax/output/CommonHTML/jax.js
Back
Close

Basic Image Manipulation

[CG]Maxime
59.5K views
Previous: Colors

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:

Matrix convolution

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:

19[111111111]

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:

1256[1464141624164624362464162416414641]

As you can see, it's a weighted mean of the surrounding pixels that gives more weight to the pixel near the current pixel. This kind of filter is also called a low-pass filter.

Blur
from PIL import Image, ImageDraw
# Load image:
input_image = Image.open("input.png")
input_pixels = input_image.load()
# Box Blur kernel
box_kernel = [[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9]]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Sharpening

The details of an image can be emphasized by using a high-pass filter:

[00.500.530.500.50]

In this kernel, the pixel is boosted when the neighbor pixels are different.

Sharpening
from PIL import Image, ImageDraw
# Load image:
input_image = Image.open("input.png")
input_pixels = input_image.load()
# High-pass kernel
kernel = [[ 0 , -.5 , 0 ],
[-.5 , 3 , -.5 ],
[ 0 , -.5 , 0 ]]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This filter can also be improved by applying the transformation only when the pixel is dark enough.

Another approach, called unsharp mask, consist in substracting from the original image a mask created using a low-pass filter. Basically, sharpening is realized by removed the blurry part of the image: sharpened=original+(originalblurred)×amount.

Unsharp Mask
from PIL import Image, ImageDraw
# Load image:
input_image = Image.open("input.png")
input_pixels = input_image.load()
# Low-pass kernel
kernel = [[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9],
[1 / 9, 1 / 9, 1 / 9]]
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): Kx=[101202101] and Ky=[121000121].

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 magx and magy. The value of the current pixel is set at mag2x+mag2y.

Sobel operator
from PIL import Image, ImageDraw
from math import sqrt
# Load image:
input_image = Image.open("input.png")
input_pixels = input_image.load()
# 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)]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Create your playground on Tech.io
This playground was created on Tech.io, our hands-on, knowledge-sharing platform for developers.
Go to tech.io
codingame x discord
Join the CodinGame community on Discord to chat about puzzle contributions, challenges, streams, blog articles - all that good stuff!
JOIN US ON DISCORD
Online Participants