Raspberry Pi Thermal Camera

The Raspberry Pi also has an i2c interface, and even better has processing capability to interpolate and filter the sensor output. By adding processing power, you can 'turn' the 8x8 output into what appears to be a higher-resolution display.

We're using a PiTFT 2.8" and a Pi Cobbler but the code can be adapted to output to the HDMI display - we're using pygame to draw to the framebuffer.

You can use any Raspberry Pi computer, from Pi A+ to Pi 3 or even a Pi Zero, but we happen to have a Pi 3 on our desk set up already so we're using that.

Raspberry Pi 3 - Model B - ARMv8 with 1G RAM

PRODUCT ID: 3055
Did you really think the Raspberry Pi would stop getting better? At this point, we sound like a broken record, extolling on the new Pi’s myriad improvements like we’re...
$35.00
IN STOCK

PiTFT Plus Assembled 320x240 2.8" TFT + Resistive Touchscreen

PRODUCT ID: 2298
Is this not the cutest little display for the Raspberry Pi? It features a 2.8" display with 320x240 16-bit color pixels and a resistive touch overlay. The plate uses the high...
$34.95
IN STOCK

Assembled Pi T-Cobbler Plus - GPIO Breakout

PRODUCT ID: 2028
This is the assembled version of the Pi T-Cobbler Plus.  It only works with the Raspberry Pi Model Zero, A+, B+, Pi 2,Pi 3! (Any Pi with 2x20 connector)
$7.95
IN STOCK

Setup PiTFT

If you have not done so already, the first thing you will need to do is setup your PiTFT. Instructions on how to do so can be found in this guide.

Install Python Software

Once your PiTFT is all set up, and you have Internet access set up go back to this page and install the Python software for the AMG8833 so you can read data from the sensor.

Finally, install both pygame and scipy. Pygame lets us draw easily to a screen using python, we'll use that to make the display work. Scipy is a powerful scientific/data processing library that we can use to magically turn the 8x8 = 64 pixel array into something that looks more like a 32x32 = 1024 pixel array. Wow, isn't digital signal processing cool?

Download: file
sudo apt-get install -y python-scipy python-pygame
sudo pip3 install colour

Wiring Up Sensor

With the Pi powered off, we can wire up the sensor to the Pi Cobbler like this:

  • Connect Vin to the 3V or 5V power supply (either is fine)
  • Connect GND to the ground pin on the Cobbler
  • Connect SDA  to SDA on the Cobbler
  • Connect SCL to SCL on the Cobbler

You can also use direct wires, we happen to have a Cobbler ready. remember you can plug the cobbler into the bottom of the PiTFT to get access to all the pins!

Now you should be able to verify that the sensor is wired up correctly by asking the Pi to detect what addresses it can see on the I2C bus:

Download: file
sudo i2cdetect -y 1

It should show up under it's default address (0x69). If you don't see 0x69, check your wiring, did you install I2C support, etc?

Run example code

At long last, we are finally ready to run our example code

"""This example is for Raspberry Pi (Linux) only!
   It will not work on microcontrollers running CircuitPython!"""

import os
import math
import time

import busio
import board

import numpy as np
import pygame
from scipy.interpolate import griddata

from colour import Color

import adafruit_amg88xx

i2c_bus = busio.I2C(board.SCL, board.SDA)

#low range of the sensor (this will be blue on the screen)
MINTEMP = 26.

#high range of the sensor (this will be red on the screen)
MAXTEMP = 32.

#how many color values we can have
COLORDEPTH = 1024

os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()

#initialize the sensor
sensor = adafruit_amg88xx.AMG88XX(i2c_bus)

# pylint: disable=invalid-slice-index
points = [(math.floor(ix / 8), (ix % 8)) for ix in range(0, 64)]
grid_x, grid_y = np.mgrid[0:7:32j, 0:7:32j]
# pylint: enable=invalid-slice-index

#sensor is an 8x8 grid so lets do a square
height = 240
width = 240

#the list of colors we can choose from
blue = Color("indigo")
colors = list(blue.range_to(Color("red"), COLORDEPTH))

#create the array of colors
colors = [(int(c.red * 255), int(c.green * 255), int(c.blue * 255)) for c in colors]

displayPixelWidth = width / 30
displayPixelHeight = height / 30

lcd = pygame.display.set_mode((width, height))

lcd.fill((255, 0, 0))

pygame.display.update()
pygame.mouse.set_visible(False)

lcd.fill((0, 0, 0))
pygame.display.update()

#some utility functions
def constrain(val, min_val, max_val):
    return min(max_val, max(min_val, val))

def map_value(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

#let the sensor initialize
time.sleep(.1)

while True:

    #read the pixels
    pixels = []
    for row in sensor.pixels:
        pixels = pixels + row
    pixels = [map_value(p, MINTEMP, MAXTEMP, 0, COLORDEPTH - 1) for p in pixels]

    #perform interpolation
    bicubic = griddata(points, pixels, (grid_x, grid_y), method='cubic')

    #draw everything
    for ix, row in enumerate(bicubic):
        for jx, pixel in enumerate(row):
            pygame.draw.rect(lcd, colors[constrain(int(pixel), 0, COLORDEPTH- 1)],
                             (displayPixelHeight * ix, displayPixelWidth * jx,
                              displayPixelHeight, displayPixelWidth))

    pygame.display.update()

If you have everything installed and wired up correctly, you should see a nice thermal camera image. Cool tones (blue and purple) are cooler temperatures, and warmer tones (yellow, red) are warmer temperatures.

If your image seems to be flipped on the screen, try changing the orientation of the AMG8833 breakout on the breadboard.

If you're interested int he details, and want to know more about how we made 64 pixels look like many more, it's called bicubic interpolation (hat tip to OSHpark for the idea!)

This guide was first published on Jun 28, 2017. It was last updated on Jun 28, 2017. This page (Raspberry Pi Thermal Camera) was last updated on Aug 24, 2019.