Lesson 3 of 5Exploring computer science
Exploring computer science · Lesson 3 · 40 minutes
Pictures are made of pixels
What you'll learn
- Store a picture as a list of rows with brightness values
- Understand how colours are made from red, green and blue
- Program your own image filters
A picture is a table of numbers
If you zoom right into a photo, you see little squares: pixels. Every pixel has exactly one colour. For the computer, a picture is therefore just a big table of numbers.
The simplest kind is a greyscale picture: every pixel is a number from 0 (black) to 255 (white) – exactly one byte. In Python that’s a list of rows. We show it with the game module:
from codelix import game
picture = [
[255, 255, 200, 200, 200, 200, 255, 255],
[255, 200, 200, 200, 200, 200, 200, 255],
[200, 200, 0, 200, 200, 0, 200, 200],
[200, 200, 200, 200, 200, 200, 200, 200],
[200, 60, 200, 200, 200, 200, 60, 200],
[200, 200, 60, 60, 60, 60, 200, 200],
[255, 200, 200, 200, 200, 200, 200, 255],
[255, 255, 200, 200, 200, 200, 255, 255],
]
def show(picture, x0=0, size=20):
for y, row in enumerate(picture):
for x, grey in enumerate(row):
game.rect(x0 + x * size, y * size, size, size, f"rgb({grey},{grey},{grey})")
game.window(160, 160)
show(picture)
print("Width:", len(picture[0]), "Height:", len(picture))picture[2][2] is the pixel in row 2, column 2 – the left eye. Change a number and see what happens.
Colours from three numbers
A colour picture stores three numbers for every pixel: how much red, green and blue it contains, each from 0 to 255. The screen mixes all other colours from these three:
from codelix import game
colours = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255), (255, 255, 255)]
game.window(360, 120)
for number, (r, g, b) in enumerate(colours):
game.rect(number * 60, 0, 60, 60, f"rgb({r},{g},{b})")
grey = round(0.299 * r + 0.587 * g + 0.114 * b)
game.rect(number * 60, 60, 60, 60, f"rgb({grey},{grey},{grey})")
print((r, g, b), "→ grey value", grey)At the bottom you see the same colours in greyscale. Green looks much brighter than blue – that’s how your eye sees it too. That’s why green counts most in the formula.
A filter changes every pixel
An image filter goes through all pixels and calculates a new value for each one. This filter makes the picture brighter. With min(255, …) every value stays in the allowed range:
from codelix import game
picture = [
[0, 40, 80, 120],
[40, 80, 120, 160],
[80, 120, 160, 200],
[120, 160, 200, 240],
]
def brighter(picture, plus):
new = []
for row in picture:
new.append([min(255, value + plus) for value in row])
return new
def show(picture, x0=0, size=30):
for y, row in enumerate(picture):
for x, grey in enumerate(row):
game.rect(x0 + x * size, y * size, size, size, f"rgb({grey},{grey},{grey})")
game.window(260, 120)
show(picture)
show(brighter(picture, 80), 140)On the left the original, on the right the brighter picture. That’s exactly how filters in photo apps work – just with millions of pixels instead of 16.
Keep building: When your task works: try your filters on the smiley. Or program a mirror filter (reverse every row with
row[::-1]) or a blur that replaces every pixel with the average of its neighbours.
Your task
Your turn
Write two image filters for greyscale pictures (lists of rows with values from 0 to 255). invert(picture) makes a negative: every value v becomes 255 - v. black_white(picture, limit) turns every value from limit upwards into 255 (white) and all smaller ones into 0 (black). Both return a new picture and leave the old one unchanged.
picture = [
[0, 60, 120, 180],
[60, 120, 180, 240],
]
def invert(picture):
new = []
return new
def black_white(picture, limit):
new = []
return new
print(invert(picture))
print(black_white(picture, 128))- Something to think about
A new list for every row: [255 - value
forvalue in row] – and append it to new. - Which command helps?
255
ifvalue>=limitelse0Don't write
picture[y][x]=…, build new lists row by row instead. - Gap code – fill in the ___
picture = [ [0, 60, 120, 180], [60, 120, 180, 240], ] def invert(picture): new = [] for row in ___: new.append(___) return new def black_white(picture, limit): new = [] for row in ___: new.append(___) return new print(invert(picture)) print(black_white(picture, 128))
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
picture = [
[0, 60, 120, 180],
[60, 120, 180, 240],
]
def invert(picture):
new = []
for row in picture:
new.append([255 - value for value in row])
return new
def black_white(picture, limit):
new = []
for row in picture:
new.append([255 if value >= limit else 0 for value in row])
return new
print(invert(picture))
print(black_white(picture, 128))