Images

Pixels, resolution, colour depth, metadata and file size, from the robot's camera.

F8.7Data representationGCSE15 min

Covers OCR J277 1.2.4 Data storage · AQA 8525 3.3.6 Representing images · Edexcel 1CP2 2.2.2 Bitmap images

Do this lesson in the simulator

A digital image is a grid of dots called pixels, and each pixel's colour is stored as a binary number. BugBot's camera works exactly like this, and camera_image() gives you its picture as a grid of numbers you can read, change and measure. This lesson looks at the robot's view pixel by pixel.

A picture is a grid of numbers

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

img = camera_image(16, 12)
print(len(img), "rows of", len(img[0]), "pixels")
print("top-left pixel:", img[0][0])
print("middle pixel:", img[6][8])
print("bottom-left pixel:", img[11][0])

Run this in the simulator

camera_image(width, height) returns a list of rows, and each row is a list of pixels. Each pixel is a tuple of three numbers, red, green and blue, from 0 to 255: one byte each. img[6][8] is row 6, column 8, the 2D arrays of lesson F3.5.

The 16 by 12 image as a grid: rows counted from 0 at the top, columns from 0 at the left, and img[6][8] is row 6, column 8, a pixel of three bytes0481215column0611rowimg[0][0] is the top-left pixel, img[11][0] the bottom-leftimg[6][8]red8 bits, 0 to 255green8 bits, 0 to 255blue8 bits, 0 to 255one pixel: a tuple of3 bytes = 24 bits
The first number picks the row and the second the column, both counted from 0, so img[6][8] is in the seventh row down, the ninth pixel along. Every square in the grid holds three numbers like it.

Seeing it in the console

Printing a character for each pixel draws the picture. Dark pixels as #, light as .:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

img = camera_image(32, 24)
for row in img:
    line = ""
    for r, g, b in row:
        brightness = (r + g + b) / 3
        line = line + ("#" if brightness < 128 else ".")
    print(line)

Run this in the simulator

The top of the picture is the light room behind the mat, the dark shape across the middle is the wall, and the red and blue balls in front of it are dark too, because red and blue pixels have a low average brightness. With only 32 by 24 pixels, small things become just a few dots. Turn the robot with turn_right(30, angle=30) before camera_image to look somewhere else.

Resolution and colour depth

Two things decide how good an image looks, and how much space it takes:

  • Resolution: the number of pixels, width × height. More pixels, more detail.
  • Colour depth: the number of bits for each pixel. With n bits a pixel can be one of 2 to the power n colours.
Colour depth Colours per pixel Example
1 bit 2 black and white, like the # and . picture
8 bits 256 a greyscale photo
24 bits 16,777,216 full colour, like the camera: 8 bits each for red, green and blue
The same 8 by 6 picture stored with 1 bit a pixel, two shades, and with 2 bits a pixel, four shades1 bit a pixel: 2 shades000000000000000000000000111111111111111100110000018 × 6 × 1 = 48 bits2 bits a pixel: 4 shades000000000000000000000000000000000101010101010101111110101111111111101010101111110101101001010101000110118 × 6 × 2 = 96 bits
With 1 bit a pixel is one of two shades, so the ball disappears into the wall. With 2 bits it can be one of four and the ball shows, but every pixel now needs twice the bits.

File size

The size of an image in bits is:

width × height × colour depth

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

def image_bits(width, height, depth):
    return width * height * depth

for w, h, depth in [(32, 24, 1), (32, 24, 24), (320, 240, 24), (1920, 1080, 24)]:
    bits = image_bits(w, h, depth)
    print(f"{w} x {h} at {depth}-bit: {bits} bits = {bits / 8 / 1000:.1f} kB")

Run this in the simulator

Double the width and the height, and the file is four times as big. A full HD photo is over 6 MB before compression.

A 320 by 240 image and a 640 by 480 one, which holds four copies of it: 230.4 kB against 921.6 kB at 24 bits320 × 240the camera76,800 pixels230.4 kB320 × 240320 × 240320 × 240320 × 240double the width and the height640 × 480: 307,200 pixels921.6 kB, 4 times as big
Doubling both sides fits four of the old picture inside the new one, so there are four times the pixels to store. Both sizes here are at 24 bits a pixel.

Metadata

An image file also stores metadata: data about the image. Without its width and height, a list of pixel values could not be turned back into a picture, because the computer would not know where each row ends. Metadata often includes the colour depth, the date, the camera, and sometimes the location where a photo was taken, which is worth knowing before sharing one.

Task: camera pixels

Capture camera_image(32, 24). Print it as 24 lines of 32 characters, # for a pixel whose average of red, green and blue is below 128, . otherwise. Then print 1-bit size: <bits> and 24-bit size: <bits> for a 32 × 24 image, worked out with a calculation.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

img = camera_image(32, 24)

Challenges

  1. Count how many pixels in the picture are mostly red, meaning red is more than green and blue added together.
  2. Print a greyscale picture using the characters .:-=+*#%@ from light to dark.
  3. How many bytes would 10 seconds of camera frames at 320 × 240, 24-bit and 30 frames a second take?