-
-
Save dglaude/2d21262b1c776e7279f39258876d32d6 to your computer and use it in GitHub Desktop.
import time | |
import board | |
import busio | |
import adafruit_mlx90640 | |
import displayio | |
number_of_colors = 13 | |
palette = displayio.Palette(number_of_colors) # Palette with all our colors | |
palette[0] = 0x000000 # Black | |
palette[1] = 0x8e00fe | |
palette[2] = 0x6000fc | |
palette[3] = 0x2d51fd | |
palette[4] = 0x3dc4fa | |
palette[5] = 0x40c82d | |
palette[6] = 0xc5ff33 | |
palette[7] = 0xfcff1d | |
palette[8] = 0xf6ba1c | |
palette[9] = 0xf69035 | |
palette[10] = 0xf45b1b | |
palette[11] = 0xf3001b | |
palette[12] = 0xbe008e | |
bitmap = displayio.Bitmap( | |
board.DISPLAY.width, | |
board.DISPLAY.height, | |
number_of_colors, | |
) | |
print(board.DISPLAY.width) | |
print(board.DISPLAY.height) | |
# Now that we have a palette and a bitmap ready, we can create and use | |
# a TileGrid just like the previous example. | |
# The entire bitmap will be filled with palette[0] color on initialization | |
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) | |
group = displayio.Group() | |
group.append(tile_grid) | |
board.DISPLAY.show(group) | |
PRINT_TEMPERATURES = False | |
PRINT_ASCIIART = False | |
PRINT_PIXEL = True | |
ascii32_string=" .\'^\",:;!>~+?]})|\\txcXUCOqk*#&%@" | |
classical_dark_to_white_70="$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`\'. " | |
classical_white_to_dark_10=" .:-=+*#%@" | |
def map32(s): | |
a1=20 | |
a2=37 | |
if s<a1: | |
i=0 | |
elif s>a2: | |
i=31 | |
else: | |
i=int(round( ( (s-a1)*31 / (a2-a1)) )) | |
return i | |
def temp2index(s): | |
a1=20 | |
a2=37 | |
b1=0 | |
b2=12 | |
if s<a1: | |
i=b1 | |
elif s>a2: | |
i=b2 | |
else: | |
i=int(round( b1 + ((s - a1) * (b2 - b1) / (a2 - a1)) )) | |
return i | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
print([hex(i) for i in mlx.serial_number]) | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
frame = [0] * 768 | |
while True: | |
stamp = time.monotonic() | |
try: | |
mlx.getFrame(frame) | |
except ValueError: | |
# these happen, no biggie - retry | |
continue | |
print("Read 2 frames in %0.2f s" % (time.monotonic()-stamp)) | |
for h in range(24): # range(24) from 0 to 23 // range(23, -1, -1) from 23 to 0 | |
for w in range(32): | |
t = frame[h*32 + w] | |
if PRINT_TEMPERATURES: | |
print("%0.1f, " % t, end="") | |
if PRINT_ASCIIART: | |
c = ascii32_string[map32(t)] | |
print(c, end="") | |
if PRINT_PIXEL: | |
bitmap[5*w, 5*(24-h)] = temp2index(t) # Convert temperature to palette index | |
if PRINT_TEMPERATURES or PRINT_ASCIIART: | |
print() | |
if PRINT_TEMPERATURES or PRINT_ASCIIART: | |
print() | |
import time | |
import board | |
import busio | |
import adafruit_mlx90640 | |
import displayio | |
number_of_colors = 13 | |
palette = displayio.Palette(number_of_colors) # Palette with all our colors | |
palette[0] = 0x000000 # Black | |
palette[1] = 0x8e00fe | |
palette[2] = 0x6000fc | |
palette[3] = 0x2d51fd | |
palette[4] = 0x3dc4fa | |
palette[5] = 0x40c82d | |
palette[6] = 0xc5ff33 | |
palette[7] = 0xfcff1d | |
palette[8] = 0xf6ba1c | |
palette[9] = 0xf69035 | |
palette[10] = 0xf45b1b | |
palette[11] = 0xf3001b | |
palette[12] = 0xbe008e | |
bitmap = displayio.Bitmap( | |
board.DISPLAY.width, | |
board.DISPLAY.height, | |
number_of_colors, | |
) | |
print(board.DISPLAY.width) | |
print(board.DISPLAY.height) | |
# Now that we have a palette and a bitmap ready, we can create and use | |
# a TileGrid just like the previous example. | |
# The entire bitmap will be filled with palette[0] color on initialization | |
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette) | |
group = displayio.Group(scale=5) | |
group.append(tile_grid) | |
board.DISPLAY.show(group) | |
PRINT_TEMPERATURES = False | |
PRINT_ASCIIART = False | |
PRINT_PIXEL = True | |
ascii32_string=" .\'^\",:;!>~+?]})|\\txcXUCOqk*#&%@" | |
classical_dark_to_white_70="$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`\'. " | |
classical_white_to_dark_10=" .:-=+*#%@" | |
def map32(s): | |
a1=20 | |
a2=37 | |
if s<a1: | |
i=0 | |
elif s>a2: | |
i=31 | |
else: | |
i=int(round( ( (s-a1)*31 / (a2-a1)) )) | |
return i | |
def temp2index(s): | |
a1=20 | |
a2=37 | |
b1=0 | |
b2=12 | |
if s<a1: | |
i=b1 | |
elif s>a2: | |
i=b2 | |
else: | |
i=int(round( b1 + ((s - a1) * (b2 - b1) / (a2 - a1)) )) | |
return i | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
print([hex(i) for i in mlx.serial_number]) | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
frame = [0] * 768 | |
while True: | |
stamp = time.monotonic() | |
try: | |
mlx.getFrame(frame) | |
except ValueError: | |
# these happen, no biggie - retry | |
continue | |
print("Read 2 frames in %0.2f s" % (time.monotonic()-stamp)) | |
for h in range(24): # range(24) from 0 to 23 // range(23, -1, -1) from 23 to 0 | |
for w in range(32): | |
t = frame[h*32 + w] | |
if PRINT_TEMPERATURES: | |
print("%0.1f, " % t, end="") | |
if PRINT_ASCIIART: | |
c = ascii32_string[map32(t)] | |
print(c, end="") | |
if PRINT_PIXEL: | |
bitmap[w, (24-h)] = temp2index(t) # Convert temperature to palette index | |
if PRINT_TEMPERATURES or PRINT_ASCIIART: | |
print() | |
if PRINT_TEMPERATURES or PRINT_ASCIIART: | |
print() | |
import time | |
import board | |
import busio | |
import adafruit_mlx90640 | |
import displayio | |
import terminalio | |
from adafruit_display_text.label import Label | |
number_of_colors = 64 | |
palette = displayio.Palette(number_of_colors) # Palette with all our colors | |
## Heatmap code inspired from: http://www.andrewnoske.com/wiki/Code_-_heatmaps_and_color_gradients | |
color_A = [ [0, 0, 0] , [0, 0, 255] ,[0, 255, 255] , [0, 255, 0] ,[255, 255, 0] , [255, 0, 0] , [255, 255, 255] ] | |
color_B = [ [0, 0, 255] ,[0, 255, 255] , [0, 255, 0] ,[255, 255, 0] , [255, 0, 0] ] | |
color_C = [ [0, 0, 0] , [255, 255, 255] ] | |
color_D = [ [0, 0, 255] , [255, 0, 0] ] | |
color = color_B | |
NUM_COLORS = len (color) | |
def MakeHeatMapColor(): | |
for i in range(number_of_colors): | |
value = i * (NUM_COLORS-1) / (number_of_colors - 1); | |
idx1 = int(value); # Our desired color will be after this index. | |
if idx1 == value : # This is the corner case | |
red = color[idx1][0] | |
green = color[idx1][1] | |
blue = color[idx1][2] | |
else: | |
idx2 = idx1+1; # ... and before this index (inclusive). | |
fractBetween = value - idx1; # Distance between the two indexes (0-1). | |
red = int( round( (color[idx2][0] - color[idx1][0]) * fractBetween + color[idx1][0] ) ) | |
green = int( round( (color[idx2][1] - color[idx1][1]) * fractBetween + color[idx1][1] ) ) | |
blue = int( round( (color[idx2][2] - color[idx1][2]) * fractBetween + color[idx1][2] ) ) | |
palette[i]= ( 0x010000 * red ) + ( 0x000100 * green ) + ( 0x000001 * blue ) | |
MakeHeatMapColor() | |
image_bitmap = displayio.Bitmap( 32, 24, number_of_colors ) # Bitmap for colour coded thermal value | |
image_tile= displayio.TileGrid(image_bitmap, pixel_shader=palette) # Create a TileGrid using the Bitmap and Palette | |
image_group = displayio.Group(scale=4) # Create a Group that scale 32*24 to 128*96 | |
image_group.append(image_tile) | |
scale_bitmap = displayio.Bitmap( number_of_colors, 1, number_of_colors ) # | |
scale_group = displayio.Group(scale=2) # Create a Group Scale must be 128 divided by number_of_colors | |
scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = 60) | |
scale_group.append(scale_tile) | |
for i in range(number_of_colors): | |
scale_bitmap[i, 0] = i # Fill the scale with the palette gradian | |
# Create the super Group | |
group = displayio.Group() | |
min_label = Label(terminalio.FONT, max_glyphs=10, color=palette[0], x = 0, y = 110) | |
max_label = Label(terminalio.FONT, max_glyphs=10, color=palette[number_of_colors-1], x = 80, y = 110) | |
# Add all the sub-group to the SuperGroup | |
group.append(image_group) | |
group.append(scale_group) | |
group.append(min_label) | |
group.append(max_label) | |
# Add the SuperGroup to the Display | |
board.DISPLAY.show(group) | |
mini = 0 | |
maxi = 0 | |
a1 = 20 | |
a2 = 37 | |
def temp2index(s): | |
global mini, maxi | |
global a1, a2 | |
b1 = 1 | |
b2 = number_of_colors - 1 | |
if s > maxi: | |
maxi = s | |
if s < mini: | |
mini = s | |
if s < a1: | |
i = b1 | |
elif s > a2: | |
i = b2 | |
else: | |
i = int( round( b1 + ( (s - a1) * (b2 - b1) / (a2 - a1) ) ) ) | |
return i | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
print([hex(i) for i in mlx.serial_number]) | |
#mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ | |
frame = [0] * 768 | |
while True: | |
stamp = time.monotonic() | |
try: | |
mlx.getFrame(frame) | |
except ValueError: | |
# these happen, no biggie - retry | |
continue | |
print("Read 2 frames in %0.2f s" % (time.monotonic()-stamp)) | |
mini = frame[0] # Define a default min and max value | |
maxi = frame[0] # Will be updated by temp2index function | |
for h in range(24): # range(24) from 0 to 23 // range(23, -1, -1) from 23 to 0 | |
for w in range(32): | |
t = frame[h*32 + w] | |
image_bitmap[w, (23-h)] = temp2index(t) # Convert temperature to palette index | |
min_label.text="%0.2f" % (mini) | |
max_string="%0.2f" % (maxi) | |
max_label.x=120-(5*len(max_string)) # Tricky calculation to left align | |
max_label.text=max_string | |
a1 = mini # Automatically change the color scale | |
a2 = maxi |
import time | |
import board | |
import busio | |
import adafruit_mlx90640 | |
import displayio | |
import terminalio | |
from adafruit_display_text.label import Label | |
number_of_colors = 64 | |
palette_grey = displayio.Palette(number_of_colors) # Palette with all our colors | |
for i in range(number_of_colors): | |
palette_grey[i]= ( 0x030303 * i ) | |
palette_red = displayio.Palette(number_of_colors) # Another Palette with all our colors | |
for i in range(number_of_colors): | |
palette_red[i]= ( ( 0x000300 * ( number_of_colors - i ) ) + 0xff0000 ) | |
palette=palette_red | |
image_bitmap = displayio.Bitmap( 32, 24, number_of_colors ) | |
# Create a TileGrid using the Bitmap and Palette | |
image_tile= displayio.TileGrid(image_bitmap, pixel_shader=palette) | |
# Create a Group | |
image_group = displayio.Group(scale=4) # Scale 32*24 to 128*96 | |
scale_bitmap = displayio.Bitmap( | |
number_of_colors, # This is the number of pixels | |
1, | |
number_of_colors, # This is the number of colors | |
) | |
# Create a Group | |
scale_group = displayio.Group(scale=2) # scale=2 for number_of_colors=64 | |
scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = 60) | |
for i in range(number_of_colors): | |
scale_bitmap[i, 0] = i | |
# Add the TileGrid to the Group | |
image_group.append(image_tile) | |
scale_group.append(scale_tile) | |
# Create the super Group | |
group = displayio.Group() | |
# Add the sub-group to the super group | |
group.append(image_group) | |
group.append(scale_group) | |
min_label = Label(terminalio.FONT, max_glyphs=32, color=palette[0], x = 0, y = 110) | |
group.append(min_label) | |
max_label = Label(terminalio.FONT, max_glyphs=32, color=palette[number_of_colors-1], x = 80, y = 110) | |
group.append(max_label) | |
# Add the Group to the Display | |
board.DISPLAY.show(group) | |
mini = 0 | |
maxi = 0 | |
a1 = 20 | |
a2 = 37 | |
def temp2index(s): | |
global mini, maxi | |
global a1, a2 | |
b1 = 1 | |
b2 = number_of_colors - 1 | |
if s > maxi: | |
maxi = s | |
if s < mini: | |
mini = s | |
if s < a1: | |
i = b1 | |
elif s > a2: | |
i = b2 | |
else: | |
i = int( round( b1 + ( (s - a1) * (b2 - b1) / (a2 - a1) ) ) ) | |
return i | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
print([hex(i) for i in mlx.serial_number]) | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
frame = [0] * 768 | |
while True: | |
stamp = time.monotonic() | |
try: | |
mlx.getFrame(frame) | |
except ValueError: | |
# these happen, no biggie - retry | |
continue | |
print("Read 2 frames in %0.2f s" % (time.monotonic()-stamp)) | |
mini = frame[0] # Define a default min and max value | |
maxi = frame[0] # Will be updated by temp2index function | |
for h in range(24): # range(24) from 0 to 23 // range(23, -1, -1) from 23 to 0 | |
for w in range(32): | |
t = frame[h*32 + w] | |
image_bitmap[w, (23-h)] = temp2index(t) # Convert temperature to palette index | |
min_label.text="%0.2f" % (mini) | |
max_string="%0.2f" % (maxi) | |
max_label.x=120-(5*len(max_string)) # Tricky calculation to left align | |
max_label.text=max_string | |
a1 = mini # Automatically change the color scale | |
a2 = maxi |
min_max.py version display the color scale and the minimum and maximum temperature from the image.
Colour scale goes from Yellow to Red.
heatmap_generated.py is the last version and has been proposed as an example for Adafruit: adafruit/Adafruit_CircuitPython_MLX90640#5
Some video and image available here: https://twitter.com/DavidGlaude/status/1210705136882003968?s=20
I am trying this with an external 320 x 240 dpi TFT display on the PyBadge.
You might be interested into this: https://gist.github.com/dglaude/cdd4ede9e43fe620637a2199e05ba8cb
Or some other of my gist at that time.
It is using ulab to do linear interpolation and invent pixel not present on the sensor, or "enhance" the image.
Not sure what a PyBadge with a 320x240 external TFT display could look like, but the code I linked has various scaling factor depending on board capabilities (memory and processing power).
The first version is with a single pixel per sensor capture.
With displayio you can define a scaling factor for a group, so writing in a 32x24 bitmap, and scaling by 5 make a 160x120 area.