Colour depth

By Martin McBride, 2021-04-26
Tags: colour rgb
Categories: computer science colour


The human eye can see many different colours, but there are limits to our perception. When two colours are very similar, they appear to be identical - we can't see the difference, even if they are side by side. Here is an example:

This shows three pairs of overlapping orange squares.

The first pair (on the left) have colours rgb(95%, 40%, 15%) and rgb(91%, 44%, 11%). The red, green and blue values of the two squares differ by 4%. Although they are both similar shades of orange, you can probably see that they are different colours.

The second pair (in the middle) have colours rgb(95%, 40%, 15%) and rgb(93%, 42%, 13%). The colour values of the two squares differ by 2%. The two colours are very similar, but you might just be able to see that they aren't exactly the same.

The final pair (on the right) have colours that differ by just 1%. It is very difficult to see the difference between them.

We normally store RGB images using 1 byte (8 bits) per colour per pixel. A byte can store integer values 0 to 255, which is 256 distinct values. This means each colour channel can be represented with a precision of better than 0.5%. Since we can barely see any difference between two colours that differ by 1%, then this precision is perfectly adequate for most uses.

Colour depth

The total number of bits used to store an RGB colour is called the colour depth (or sometimes the bit depth).

In the case above, where red, green and blue are each stored in one byte, the colour occupies 24 bits (ie 3 bytes) so we refer to this as 24 bit colour.

If an image uses 24 bits to store each pixel, we refer to it as a 24 bit image.

Almost all RGB computer images are stored using 24 bits. It is a very convenient format because:

  • It stores just enough information to give a good quality image.
  • It is easy to access the pixel data because each byte stores exactly one colour component of one pixel.

Most other colour spaces also normally use one byte per component:

  • HSL and Luminance/chrominance schemes have 3 components, similar to RGB, so a colour occupies 3 bytes.
  • Greyscale images only have one component, so a colour can be stored as a single byte.
  • CMYK images only have 4 components, so a colour occupies 4 bytes.

Smaller colour depths

Not all images are 24 bit.

In the past, memory (particularly video memory) was very expensive. Various schemes were used to reduce the amount of memory required. It is worth being aware of these alternative colour depths, because some image formats still support them.

16 bit images encode all three colour components into 2 bytes. This allows 5 bits per colour, so instead of having 256 possible levels of red, green and blue, there are only 32 levels. This creates images that are ok for arcade games but not quite photographic quality. This leaves a spare bit. In some schemes, the green channel is allocated an extra bit, so it has 64 bits (the green channel is given the extra bit because the eye is more sensitive to shades of green). This only produces a marginal improvement.

8 bit images encode all 3 colour components into a single byte. This means that the entire image can only have 256 different colours. There are quite a few different schemes, but none of them work particularly well. 8 bit images are nowhere close to photographic quality.

16 bit and 8 bit images are also smaller than 24 bit images, which was useful in the past when disk space was also a lot more expensive, and networks were generally slower. However, modern image compression techniques can reduce the size of images quite dramatically, and ironically they often work better on 24 bit images. A JPEG compressed 24 bit image will often be smaller than the equivalent compressed 16 or 8 bit image.

These schemes are normally only used with RGB images. Sometimes similar schemes are used with greyscale images (for example, using 4 bits to represent a grey value). It is quite rare to see this used with other colour spaces such as CMYK or HSL, they are almost always stored using 8 bits per component.

1-bit images

1-bit images are an extreme example of a greyscale colour space. They only allow each pixel to be either black or white, so a pixel value can be stored in a single bit (that is, 8 pixels can be stored in 1 byte). These are sometimes used for images that contain only black text and black line drawings, so there are no grey values. For example, fax machines often used 1 bit data.

Larger colour depths

It is sometimes useful to store images with more than 24 bits. For example, if you plan to perform multiple operation on an images, such as filtering, colour manipulation and histogram corrections, it is often a good idea to store the intermediate results to a higher precision to avoid rounding errors between the stages.

RGB images can be stored as 10 bits per colour. This means that each pixel can fit into a 32 but word.

However, these days memory is very cheap so it is easier just to store 16 bits per colour, which makes it easier to process the data because each colour channel is stored in a separate 16 bit word.

See also

If you found this article useful, you might be interested in the book NumPy Recipes or other books by the same author.

Join the PythonInformer Newsletter

Sign up using this form to receive an email when new content is added:

Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest