Last active
May 10, 2021 22:11
-
-
Save dglaude/f9241f8c83cb8fdc32dc5436a87062be to your computer and use it in GitHub Desktop.
MLX90640 + FeatherWing Keyboard bilinear upscalling and displayio pixel stretching with Feather RP2040 and Feather S2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### MLX90640 + FeatherWing Keyboard bilinear upscalling and displayio pixel stretching | |
### Feather RP2040: Reach 4x bilinear x2 pixel doubling | |
### Feather S2: Reach x5 bilinear x2 pixel doubling | |
### Detect what Feather is in use and adapt | |
# Input is 32x24 | |
# Make use of ulab for fast math operation on matrix | |
# Split ulab operations to minimise memory consumption by temporary variable | |
#from bbq10keyboard import BBQ10Keyboard, STATE_PRESS, STATE_RELEASE, STATE_LONG_PRESS | |
#from adafruit_stmpe610 import Adafruit_STMPE610_SPI | |
import adafruit_ili9341 | |
#import adafruit_sdcard | |
import digitalio | |
import displayio | |
#import neopixel | |
import storage | |
import board | |
import time | |
import os | |
import busio | |
import adafruit_mlx90640 | |
import terminalio | |
import bitmaptools | |
#from adafruit_display_text.label import Label | |
from simpleio import map_range | |
import adafruit_fancyled.adafruit_fancyled as fancy | |
import gc | |
import ulab | |
# Release any resources currently in use for the displays | |
displayio.release_displays() | |
spi = board.SPI() | |
import os | |
machine=os.uname().machine | |
if machine in ("Adafruit Feather RP2040 with rp2040"): | |
tft_cs = board.D9 | |
tft_dc = board.D10 | |
touch_cs = board.D6 | |
sd_cs = board.D5 | |
neopix_pin = board.D11 | |
# other_factor = 2; scale_factor = 5 | |
# other_factor = 3; scale_factor = 3 | |
other_factor = 4; scale_factor = 2 | |
elif machine in ('FeatherS2 with ESP32S2'): | |
tft_cs = board.D5 | |
tft_dc = board.D6 | |
touch_cs = board.D21 | |
sd_cs = board.D20 | |
neopix_pin = board.D9 | |
# other_factor = 3; scale_factor = 3 | |
other_factor = 5; scale_factor = 2 | |
else: | |
print("Unknown machine:", machine) | |
print(42/0) | |
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) | |
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240) | |
gc.collect() | |
start_mem = gc.mem_free() | |
start_time = time.monotonic_ns() | |
# On PyPortal, the scale factor works from 3 to 9 | |
# On Clue the biggest scale is 7 | |
total_factor = scale_factor * other_factor | |
#text_x = (32 * scale_factor) - 30 | |
#text_y = (24 * scale_factor) + 8 | |
#gradian_y = 24 + int (20 / total_factor) | |
#gradian_y = int( (text_y + 8) / 2 ) | |
number_of_colors = 128 # Number of color in the gradian | |
#number_of_colors = 64 # Number of color in the gradian | |
#number_of_colors = 32 # Number of color in the gradian | |
last_color = number_of_colors-1 # Last color in palette | |
palette = displayio.Palette(number_of_colors) # Palette with all our colors | |
# gradian for fancyled palette generation | |
grad = [(0.00, fancy.CRGB(0, 0, 255)), # Blue | |
(0.25, fancy.CRGB(0, 255, 255)), | |
(0.50, fancy.CRGB(0, 255, 0)), # Green | |
(0.75, fancy.CRGB(255, 255, 0)), | |
(1.00, fancy.CRGB(255, 0, 0))] # Red | |
# create our palette using fancyled expansion of our gradian | |
fancy_palette = fancy.expand_gradient(grad, number_of_colors) | |
for c in range(number_of_colors): | |
palette[c] = fancy_palette[c].pack() | |
### Only saving 192 but a test in the use of del() | |
gc.collect() | |
aaa_mem = gc.mem_free() | |
del(fancy) | |
del(grad) | |
gc.collect() | |
bbb_mem = gc.mem_free() | |
print("Saved mem:", bbb_mem-aaa_mem) | |
bitmap_x=other_factor*24+(1-other_factor) | |
bitmap_y=other_factor*32+(1-other_factor) | |
# Bitmap for colour coded thermal value (FIXME: Why x and y are inverted) | |
image_bitmap = displayio.Bitmap( bitmap_y, bitmap_x, number_of_colors ) | |
# Create a TileGrid using the Bitmap and Palette | |
image_tile= displayio.TileGrid(image_bitmap, pixel_shader=palette) | |
# Create a Group that scale with displayio scale | |
image_group = displayio.Group(scale=scale_factor) | |
image_group.append(image_tile) | |
#^# scale_bitmap = displayio.Bitmap( number_of_colors, 1, number_of_colors ) | |
# Create a Group Scale | |
#^# scale_group = displayio.Group(scale=total_factor) | |
#^# scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = gradian_y) | |
#^# 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=text_y) | |
#_# center_label = Label(terminalio.FONT, max_glyphs=10, color=palette[int(number_of_colors/2)], x=int (text_x/2), y=text_y) | |
#°# max_label = Label(terminalio.FONT, max_glyphs=10, color=palette[last_color], x=text_x, y=text_y) | |
# Indicator for the minimum and maximum location | |
#°# o_label = Label(terminalio.FONT, max_glyphs = 1, text = "o", color = 0xFFFFFF, x = 0, y = 0) | |
#°# x_label = Label(terminalio.FONT, max_glyphs = 1, text = "x", color = 0xFFFFFF, x = 0, y = 0) | |
# Add all the sub-group to the SuperGroup | |
group.append(image_group) | |
#^# group.append(scale_group) | |
#°# group.append(min_label) | |
#_# group.append(center_label) | |
#°# group.append(max_label) | |
#°# group.append(o_label) | |
#°# group.append(x_label) | |
# Add the SuperGroup to the Display | |
display.show(group) | |
min_t = 20 # Initial minimum temperature range, before auto scale | |
max_t = 37 # Initial maximum temperature range, before auto scale | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
#mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ | |
#mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_8_HZ | |
####frame = [0] * 768 | |
npframe = ulab.zeros(768) | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory before a:", mid_mem) | |
# Allocate once, not in the loop. | |
#a = ulab.zeros((other_factor*24+(1-other_factor), other_factor*32+(1-other_factor))) # the upscaled image | |
a = ulab.zeros((bitmap_x, bitmap_y)) # the upscaled image | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory after a:", mid_mem) | |
div_factor = 1 | |
while True: | |
gc.collect() | |
stamp = time.monotonic() | |
try: | |
# mlx.getFrame(frame) | |
mlx.getFrame(npframe) | |
except ValueError: # these happen, no biggie - retry | |
continue | |
print("Time for data aquisition: %0.2f s" % (time.monotonic()-stamp)) | |
stamp = time.monotonic() | |
# Convert in ulab.array, find the min and max and normalize to int from 0 to last_color. | |
# npframe=ulab.array(frame) | |
min_t=ulab.numerical.min(npframe) | |
# min_t=min(0,ulab.numerical.min(npframe)) | |
max_t=ulab.numerical.max(npframe) | |
factor=last_color/(max_t-min_t) | |
# Maybe this will lose a lot of precision as it goes in int16 | |
# But that save twice the memory of working with floating point | |
intb=ulab.array((npframe-min_t)*factor,dtype=ulab.int16) | |
b = intb.reshape((24,32)) | |
if other_factor == 1: | |
a = b | |
elif other_factor == 2: | |
print("x2 factor") | |
# Some old magic by @v923z | |
# a[::2,::2] = b | |
# a[1::2,::2] = 0.5 * (b[:-1,:] + b[1:, :]) | |
# a[::2,1::2] = 0.5 * (b[:,1:] + b[:,:-1]) | |
# a[1::2,1::2] = 0.25 * (b[:-1,1:] + b[1:,:-1] + b[1:,1:] + b[:-1,:-1]) | |
if False: # Readable arithmetic => more memory, max: n=65 | |
print("x2 factor readable") | |
a[::2,::2] = b | |
a[1::2,::2] = 0.5 * (b[:-1,:] + b[1:, :]) | |
a[::,1::2] = 0.5 * (a[::,:-1:2] + a[::,2::2]) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x2 factor memory") | |
a[::2,::2] = b | |
a[1::2,::2] = b[:-1,:] | |
a[1::2,::2] += b[1:, :] | |
a[1::2,::2] /= 2 | |
a[::,1::2] = a[::,:-1:2] | |
a[::,1::2] += a[::,2::2] | |
a[::,1::2] /= 2 | |
div_factor = 2 | |
elif other_factor == 3: | |
if True: # Readable arithmetic => more memory | |
print("x3 factor readable") | |
a[::3,::3] = b | |
a[1::3,::3] = b[:-1,:] * (2/3) + b[1:,:] * (1/3) | |
a[2::3,::3] = b[:-1,:] * (1/3) + b[1:,:] * (2/3) | |
a[::,1::3] = a[::,:-1:3] * (2/3) + a[::,3::3] * (1/3) | |
a[::,2::3] = a[::,:-1:3] * (1/3) + a[::,3::3] * (2/3) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x3 factor memory") | |
a[::3,::3] = b | |
a[1::3,::3] = b[:-1,:] | |
a[1::3,::3] *= 2 | |
a[1::3,::3] += b[1:,:] | |
a[1::3,::3] /= 3 | |
a[2::3,::3] = b[1:,:] | |
a[2::3,::3] *= 2 | |
a[2::3,::3] += b[:-1,:] | |
a[2::3,::3] /= 3 | |
a[::,1::3] = a[::,:-1:3] | |
a[::,1::3] *= 2 | |
a[::,1::3] += a[::,3::3] | |
a[::,1::3] /= 3 | |
a[::,2::3] = a[::,3::3] | |
a[::,2::3] *= 2 | |
a[::,2::3] += a[::,:-1:3] | |
a[::,2::3] /= 3 | |
elif other_factor == 4: | |
if False: # Readable arithmetic => more memory | |
print("x4 factor readable") | |
a[::4,::4] = b | |
a[1::4,::4] = b[:-1,:] * (3/4) + b[1:,:] * (1/4) | |
a[2::4,::4] = b[:-1,:] * (2/4) + b[1:,:] * (2/4) | |
a[3::4,::4] = b[:-1,:] * (1/4) + b[1:,:] * (3/4) | |
a[::,1::4] = a[::,:-1:4] * (3/4) + a[::,4::4] * (1/4) | |
a[::,2::4] = a[::,:-1:4] * (2/4) + a[::,4::4] * (2/4) | |
a[::,3::4] = a[::,:-1:4] * (1/4) + a[::,4::4] * (3/4) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x4 factor memory") | |
a[::4,::4] = b | |
# a[2::4,::4] = b[:-1,:] * (2/4) + b[1:,:] * (2/4) | |
a[2::4,::4] = b[:-1,:] | |
a[2::4,::4] += b[1:,:] | |
a[2::4,::4] /= 2 | |
# a[1::4,::4] = b[:-1,:] * (3/4) + b[1:,:] * (1/4) | |
a[1::4,::4] = b[:-1,:] | |
a[1::4,::4] *= 3 | |
a[1::4,::4] += b[1:,:] | |
a[1::4,::4] /= 4 | |
# a[3::4,::4] = b[:-1,:] * (1/4) + b[1:,:] * (3/4) | |
a[3::4,::4] = b[1:,:] | |
a[3::4,::4] *= 3 | |
a[3::4,::4] += b[:-1,:] | |
a[3::4,::4] /= 4 | |
# a[::,2::4] = a[::,:-1:4] * (2/4) + a[::,4::4] * (2/4) | |
a[::,2::4] = a[::,:-1:4] | |
a[::,2::4] += a[::,4::4] | |
a[::,2::4] /= 2 | |
# a[::,1::4] = a[::,:-1:4] * (3/4) + a[::,4::4] * (1/4) | |
a[::,1::4] = a[::,:-1:4] | |
a[::,1::4] *= 3 | |
a[::,1::4] += a[::,4::4] | |
a[::,1::4] /= 4 | |
# a[::,3::4] = a[::,:-1:4] * (1/4) + a[::,4::4] * (3/4) | |
a[::,3::4] = a[::,4::4] | |
a[::,3::4] *= 3 | |
a[::,3::4] += a[::,:-1:4] | |
a[::,3::4] /= 4 | |
elif other_factor == 5: | |
print("x5 factor") | |
a[::5,::5] = b | |
a[1::5,::5] = b[:-1,:] * (4/5) + b[1:,:] * (1/5) | |
a[2::5,::5] = b[:-1,:] * (3/5) + b[1:,:] * (2/5) | |
a[3::5,::5] = b[:-1,:] * (2/5) + b[1:,:] * (3/5) | |
a[4::5,::5] = b[:-1,:] * (1/5) + b[1:,:] * (4/5) | |
a[::,1::5] = a[::,:-1:5] * (4/5) + a[::,5::5] * (1/5) | |
a[::,2::5] = a[::,:-1:5] * (3/5) + a[::,5::5] * (2/5) | |
a[::,3::5] = a[::,:-1:5] * (2/5) + a[::,5::5] * (3/5) | |
a[::,4::5] = a[::,:-1:5] * (1/5) + a[::,5::5] * (4/5) | |
elif other_factor == 6: | |
print("x6 factor") # ulab processing: 0.42 s | |
a[::6,::6] = b | |
a[1::6,::6] = b[:-1,:] * (5/6) + b[1:,:] * (1/6) | |
a[2::6,::6] = b[:-1,:] * (4/6) + b[1:,:] * (2/6) | |
a[3::6,::6] = b[:-1,:] * (3/6) + b[1:,:] * (3/6) | |
a[4::6,::6] = b[:-1,:] * (2/6) + b[1:,:] * (4/6) | |
a[5::6,::6] = b[:-1,:] * (1/6) + b[1:,:] * (5/6) | |
a[::,1::6] = a[::,:-1:6] * (5/6) + a[::,6::6] * (1/6) | |
a[::,2::6] = a[::,:-1:6] * (4/6) + a[::,6::6] * (2/6) | |
a[::,3::6] = a[::,:-1:6] * (3/6) + a[::,6::6] * (3/6) | |
a[::,4::6] = a[::,:-1:6] * (2/6) + a[::,6::6] * (4/6) | |
a[::,5::6] = a[::,:-1:6] * (1/6) + a[::,6::6] * (5/6) | |
else: | |
print("Unknown other_factor: ", other_factor) | |
print(42/0) | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory now:", mid_mem) | |
# min_t_a=ulab.numerical.min(a) | |
# max_t_a=ulab.numerical.max(a) | |
# Going from int16 to int8 because that is what we need for bitmap conversion | |
inta=ulab.array((a),dtype=ulab.int8) | |
# min_t_inta=ulab.numerical.min(a) | |
# max_t_inta=ulab.numerical.max(a) | |
# print("Min: ", min_t, min_t_a, min_t_inta) | |
# print("Max: ", max_t, max_t_a, max_t_inta) | |
#°# minx = 0 | |
#°# miny = 0 | |
#°# maxx = 23 | |
#°# maxy = 31 | |
print("ulab processing: %0.2f s" % (time.monotonic()-stamp)) | |
print("Memory now:", gc.mem_free()) | |
stamp_copy = time.monotonic() | |
bitmaptools.arrayblit(image_bitmap, inta) | |
print("Copy from uLab to bitmap: %0.2f s" % (time.monotonic()-stamp_copy)) | |
# min and max temperature indicator | |
#°# min_label.text="%0.2f" % (min_t) | |
#°# max_label.text="%0.2f" % (max_t) | |
# Compute average_center temperature of the middle of sensor and convert to palette color | |
#_# center_average = (frame[11*32 + 15] + frame[12*32 + 15] + frame[11*32 + 16] + frame[12*32 + 16]) / 4 | |
#_# center_color = int(map_range(center_average, min_t, max_t, 0, last_color )) | |
#_# center_label.text = "%0.2f" % (center_average) | |
#_# center_label.color = palette[center_color] | |
# Set the location of X for lowest temperature | |
#°# x_label.x = maxx * total_factor | |
#°# x_label.y = (23-maxy) * total_factor | |
# Set the location of O for highest temperature | |
#°# o_label.x = minx * total_factor | |
#°# o_label.y = (23-miny) * total_factor | |
# print("Total time for aquisition and display %0.2f s" % (time.monotonic()-stamp)) | |
stop_time = time.monotonic_ns() | |
gc.collect() | |
stop_mem = gc.mem_free() | |
print(stop_time - start_time, stop_mem - start_mem) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### MLX90640 + MatrixPortal + Matrix 32x64 | |
### Add some gamma_adjust to the colour for LED display | |
### | |
### If a 64x64 matrix (or two time 32x64) then the following | |
### 32x24 (pixel doubling) => 64x48 | |
### 32x24 (upscale) => 63x47 | |
### | |
import time | |
import board | |
import displayio | |
#import adafruit_ili9341 | |
#from bbq10keyboard import BBQ10Keyboard, STATE_PRESS, STATE_RELEASE, STATE_LONG_PRESS | |
#from adafruit_stmpe610 import Adafruit_STMPE610_SPI | |
#import adafruit_sdcard | |
import digitalio | |
import displayio | |
#import neopixel | |
import storage | |
import board | |
import time | |
import os | |
import busio | |
import adafruit_mlx90640 | |
import terminalio | |
import bitmaptools | |
#from adafruit_display_text.label import Label | |
from simpleio import map_range | |
import adafruit_fancyled.adafruit_fancyled as fancy | |
import gc | |
import ulab | |
import os | |
machine=os.uname().machine | |
if machine in ("Adafruit Feather RP2040 with rp2040"): | |
tft_cs = board.D9 | |
tft_dc = board.D10 | |
touch_cs = board.D6 | |
sd_cs = board.D5 | |
neopix_pin = board.D11 | |
# other_factor = 2; scale_factor = 5 | |
# other_factor = 3; scale_factor = 3 | |
other_factor = 4; scale_factor = 2 | |
elif machine in ('FeatherS2 with ESP32S2'): | |
tft_cs = board.D5 | |
tft_dc = board.D6 | |
touch_cs = board.D21 | |
sd_cs = board.D20 | |
neopix_pin = board.D9 | |
# other_factor = 3; scale_factor = 3 | |
other_factor = 5; scale_factor = 2 | |
elif machine in ('Adafruit Matrix Portal M4 with samd51j19'): | |
other_factor = 1; scale_factor = 1 | |
else: | |
print("Unknown machine:", machine) | |
print(42/0) | |
# Release any resources currently in use for the displays | |
displayio.release_displays() | |
if machine in ('Adafruit Matrix Portal M4 with samd51j19'): | |
# the display | |
import adafruit_imageload | |
from adafruit_matrixportal.matrix import Matrix | |
matrix = Matrix(width=64, height=32, bit_depth=6) | |
display = matrix.display | |
display.rotation = 90 # matrixportal up | |
# display.rotation = 270 # matrixportal down | |
else: | |
spi = board.SPI() | |
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs) | |
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240) | |
gc.collect() | |
start_mem = gc.mem_free() | |
start_time = time.monotonic_ns() | |
# On PyPortal, the scale factor works from 3 to 9 | |
# On Clue the biggest scale is 7 | |
total_factor = scale_factor * other_factor | |
#text_x = (32 * scale_factor) - 30 | |
#text_y = (24 * scale_factor) + 8 | |
#gradian_y = 24 + int (20 / total_factor) | |
#gradian_y = int( (text_y + 8) / 2 ) | |
number_of_colors = 128 # Number of color in the gradian | |
#number_of_colors = 64 # Number of color in the gradian | |
#number_of_colors = 32 # Number of color in the gradian | |
last_color = number_of_colors-1 # Last color in palette | |
palette = displayio.Palette(number_of_colors) # Palette with all our colors | |
# gradian for fancyled palette generation | |
grad = [(0.00, fancy.CRGB(0, 0, 255)), # Blue | |
(0.25, fancy.CRGB(0, 255, 255)), | |
(0.50, fancy.CRGB(0, 255, 0)), # Green | |
(0.75, fancy.CRGB(255, 255, 0)), | |
(1.00, fancy.CRGB(255, 0, 0))] # Red | |
# create our palette using fancyled expansion of our gradian | |
fancy_palette = fancy.expand_gradient(grad, number_of_colors) | |
# print(fancy_palette) | |
for c in range(number_of_colors): | |
color = fancy_palette[c] | |
adjusted_color = fancy.gamma_adjust(color) | |
# print(color, adjusted_color) | |
palette[c] = adjusted_color.pack() | |
### Only saving 192 but a test in the use of del() | |
gc.collect() | |
aaa_mem = gc.mem_free() | |
del(fancy) | |
del(grad) | |
gc.collect() | |
bbb_mem = gc.mem_free() | |
print("Saved mem:", bbb_mem-aaa_mem) | |
bitmap_x=other_factor*24+(1-other_factor) | |
bitmap_y=other_factor*32+(1-other_factor) | |
# Bitmap for colour coded thermal value (FIXME: Why x and y are inverted) | |
image_bitmap = displayio.Bitmap( bitmap_y, bitmap_x, number_of_colors ) | |
# Create a TileGrid using the Bitmap and Palette | |
image_tile= displayio.TileGrid(image_bitmap, pixel_shader=palette) | |
# Create a Group that scale with displayio scale | |
image_group = displayio.Group(scale=scale_factor) | |
image_group.append(image_tile) | |
#^# scale_bitmap = displayio.Bitmap( number_of_colors, 1, number_of_colors ) | |
# Create a Group Scale | |
#^# scale_group = displayio.Group(scale=total_factor) | |
#^# scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = gradian_y) | |
#^# 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=text_y) | |
#_# center_label = Label(terminalio.FONT, max_glyphs=10, color=palette[int(number_of_colors/2)], x=int (text_x/2), y=text_y) | |
#°# max_label = Label(terminalio.FONT, max_glyphs=10, color=palette[last_color], x=text_x, y=text_y) | |
# Indicator for the minimum and maximum location | |
#°# o_label = Label(terminalio.FONT, max_glyphs = 1, text = "o", color = 0xFFFFFF, x = 0, y = 0) | |
#°# x_label = Label(terminalio.FONT, max_glyphs = 1, text = "x", color = 0xFFFFFF, x = 0, y = 0) | |
# Add all the sub-group to the SuperGroup | |
group.append(image_group) | |
#^# group.append(scale_group) | |
#°# group.append(min_label) | |
#_# group.append(center_label) | |
#°# group.append(max_label) | |
#°# group.append(o_label) | |
#°# group.append(x_label) | |
# Add the SuperGroup to the Display | |
display.show(group) | |
min_t = 20 # Initial minimum temperature range, before auto scale | |
max_t = 37 # Initial maximum temperature range, before auto scale | |
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) | |
mlx = adafruit_mlx90640.MLX90640(i2c) | |
print("MLX addr detected on I2C") | |
#mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ | |
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ | |
#mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_8_HZ | |
####frame = [0] * 768 | |
npframe = ulab.zeros(768) | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory before a:", mid_mem) | |
# Allocate once, not in the loop. | |
#a = ulab.zeros((other_factor*24+(1-other_factor), other_factor*32+(1-other_factor))) # the upscaled image | |
a = ulab.zeros((bitmap_x, bitmap_y)) # the upscaled image | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory after a:", mid_mem) | |
div_factor = 1 | |
while True: | |
gc.collect() | |
stamp = time.monotonic() | |
try: | |
# mlx.getFrame(frame) | |
mlx.getFrame(npframe) | |
except ValueError: # these happen, no biggie - retry | |
continue | |
print("Time for data aquisition: %0.2f s" % (time.monotonic()-stamp)) | |
stamp = time.monotonic() | |
# Convert in ulab.array, find the min and max and normalize to int from 0 to last_color. | |
# npframe=ulab.array(frame) | |
min_t=ulab.numerical.min(npframe) | |
# min_t=min(0,ulab.numerical.min(npframe)) | |
max_t=ulab.numerical.max(npframe) | |
factor=last_color/(max_t-min_t) | |
# Maybe this will lose a lot of precision as it goes in int16 | |
# But that save twice the memory of working with floating point | |
intb=ulab.array((npframe-min_t)*factor,dtype=ulab.int16) | |
b = intb.reshape((24,32)) | |
if other_factor == 1: | |
a = b | |
elif other_factor == 2: | |
print("x2 factor") | |
# Some old magic by @v923z | |
# a[::2,::2] = b | |
# a[1::2,::2] = 0.5 * (b[:-1,:] + b[1:, :]) | |
# a[::2,1::2] = 0.5 * (b[:,1:] + b[:,:-1]) | |
# a[1::2,1::2] = 0.25 * (b[:-1,1:] + b[1:,:-1] + b[1:,1:] + b[:-1,:-1]) | |
if False: # Readable arithmetic => more memory, max: n=65 | |
print("x2 factor readable") | |
a[::2,::2] = b | |
a[1::2,::2] = 0.5 * (b[:-1,:] + b[1:, :]) | |
a[::,1::2] = 0.5 * (a[::,:-1:2] + a[::,2::2]) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x2 factor memory") | |
a[::2,::2] = b | |
a[1::2,::2] = b[:-1,:] | |
a[1::2,::2] += b[1:, :] | |
a[1::2,::2] /= 2 | |
a[::,1::2] = a[::,:-1:2] | |
a[::,1::2] += a[::,2::2] | |
a[::,1::2] /= 2 | |
div_factor = 2 | |
elif other_factor == 3: | |
if True: # Readable arithmetic => more memory | |
print("x3 factor readable") | |
a[::3,::3] = b | |
a[1::3,::3] = b[:-1,:] * (2/3) + b[1:,:] * (1/3) | |
a[2::3,::3] = b[:-1,:] * (1/3) + b[1:,:] * (2/3) | |
a[::,1::3] = a[::,:-1:3] * (2/3) + a[::,3::3] * (1/3) | |
a[::,2::3] = a[::,:-1:3] * (1/3) + a[::,3::3] * (2/3) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x3 factor memory") | |
a[::3,::3] = b | |
a[1::3,::3] = b[:-1,:] | |
a[1::3,::3] *= 2 | |
a[1::3,::3] += b[1:,:] | |
a[1::3,::3] /= 3 | |
a[2::3,::3] = b[1:,:] | |
a[2::3,::3] *= 2 | |
a[2::3,::3] += b[:-1,:] | |
a[2::3,::3] /= 3 | |
a[::,1::3] = a[::,:-1:3] | |
a[::,1::3] *= 2 | |
a[::,1::3] += a[::,3::3] | |
a[::,1::3] /= 3 | |
a[::,2::3] = a[::,3::3] | |
a[::,2::3] *= 2 | |
a[::,2::3] += a[::,:-1:3] | |
a[::,2::3] /= 3 | |
elif other_factor == 4: | |
if False: # Readable arithmetic => more memory | |
print("x4 factor readable") | |
a[::4,::4] = b | |
a[1::4,::4] = b[:-1,:] * (3/4) + b[1:,:] * (1/4) | |
a[2::4,::4] = b[:-1,:] * (2/4) + b[1:,:] * (2/4) | |
a[3::4,::4] = b[:-1,:] * (1/4) + b[1:,:] * (3/4) | |
a[::,1::4] = a[::,:-1:4] * (3/4) + a[::,4::4] * (1/4) | |
a[::,2::4] = a[::,:-1:4] * (2/4) + a[::,4::4] * (2/4) | |
a[::,3::4] = a[::,:-1:4] * (1/4) + a[::,4::4] * (3/4) | |
else: # Splitting into simple operation => less memory max: n=87 | |
print("x4 factor memory") | |
a[::4,::4] = b | |
# a[2::4,::4] = b[:-1,:] * (2/4) + b[1:,:] * (2/4) | |
a[2::4,::4] = b[:-1,:] | |
a[2::4,::4] += b[1:,:] | |
a[2::4,::4] /= 2 | |
# a[1::4,::4] = b[:-1,:] * (3/4) + b[1:,:] * (1/4) | |
a[1::4,::4] = b[:-1,:] | |
a[1::4,::4] *= 3 | |
a[1::4,::4] += b[1:,:] | |
a[1::4,::4] /= 4 | |
# a[3::4,::4] = b[:-1,:] * (1/4) + b[1:,:] * (3/4) | |
a[3::4,::4] = b[1:,:] | |
a[3::4,::4] *= 3 | |
a[3::4,::4] += b[:-1,:] | |
a[3::4,::4] /= 4 | |
# a[::,2::4] = a[::,:-1:4] * (2/4) + a[::,4::4] * (2/4) | |
a[::,2::4] = a[::,:-1:4] | |
a[::,2::4] += a[::,4::4] | |
a[::,2::4] /= 2 | |
# a[::,1::4] = a[::,:-1:4] * (3/4) + a[::,4::4] * (1/4) | |
a[::,1::4] = a[::,:-1:4] | |
a[::,1::4] *= 3 | |
a[::,1::4] += a[::,4::4] | |
a[::,1::4] /= 4 | |
# a[::,3::4] = a[::,:-1:4] * (1/4) + a[::,4::4] * (3/4) | |
a[::,3::4] = a[::,4::4] | |
a[::,3::4] *= 3 | |
a[::,3::4] += a[::,:-1:4] | |
a[::,3::4] /= 4 | |
elif other_factor == 5: | |
print("x5 factor") | |
a[::5,::5] = b | |
a[1::5,::5] = b[:-1,:] * (4/5) + b[1:,:] * (1/5) | |
a[2::5,::5] = b[:-1,:] * (3/5) + b[1:,:] * (2/5) | |
a[3::5,::5] = b[:-1,:] * (2/5) + b[1:,:] * (3/5) | |
a[4::5,::5] = b[:-1,:] * (1/5) + b[1:,:] * (4/5) | |
a[::,1::5] = a[::,:-1:5] * (4/5) + a[::,5::5] * (1/5) | |
a[::,2::5] = a[::,:-1:5] * (3/5) + a[::,5::5] * (2/5) | |
a[::,3::5] = a[::,:-1:5] * (2/5) + a[::,5::5] * (3/5) | |
a[::,4::5] = a[::,:-1:5] * (1/5) + a[::,5::5] * (4/5) | |
elif other_factor == 6: | |
print("x6 factor") # ulab processing: 0.42 s | |
a[::6,::6] = b | |
a[1::6,::6] = b[:-1,:] * (5/6) + b[1:,:] * (1/6) | |
a[2::6,::6] = b[:-1,:] * (4/6) + b[1:,:] * (2/6) | |
a[3::6,::6] = b[:-1,:] * (3/6) + b[1:,:] * (3/6) | |
a[4::6,::6] = b[:-1,:] * (2/6) + b[1:,:] * (4/6) | |
a[5::6,::6] = b[:-1,:] * (1/6) + b[1:,:] * (5/6) | |
a[::,1::6] = a[::,:-1:6] * (5/6) + a[::,6::6] * (1/6) | |
a[::,2::6] = a[::,:-1:6] * (4/6) + a[::,6::6] * (2/6) | |
a[::,3::6] = a[::,:-1:6] * (3/6) + a[::,6::6] * (3/6) | |
a[::,4::6] = a[::,:-1:6] * (2/6) + a[::,6::6] * (4/6) | |
a[::,5::6] = a[::,:-1:6] * (1/6) + a[::,6::6] * (5/6) | |
else: | |
print("Unknown other_factor: ", other_factor) | |
print(42/0) | |
gc.collect(); mid_mem = gc.mem_free(); print("Memory now:", mid_mem) | |
# min_t_a=ulab.numerical.min(a) | |
# max_t_a=ulab.numerical.max(a) | |
# Going from int16 to int8 because that is what we need for bitmap conversion | |
inta=ulab.array((a),dtype=ulab.int8) | |
# min_t_inta=ulab.numerical.min(a) | |
# max_t_inta=ulab.numerical.max(a) | |
# print("Min: ", min_t, min_t_a, min_t_inta) | |
# print("Max: ", max_t, max_t_a, max_t_inta) | |
#°# minx = 0 | |
#°# miny = 0 | |
#°# maxx = 23 | |
#°# maxy = 31 | |
print("ulab processing: %0.2f s" % (time.monotonic()-stamp)) | |
print("Memory now:", gc.mem_free()) | |
stamp_copy = time.monotonic() | |
bitmaptools.arrayblit(image_bitmap, inta) | |
print("Copy from uLab to bitmap: %0.2f s" % (time.monotonic()-stamp_copy)) | |
# min and max temperature indicator | |
#°# min_label.text="%0.2f" % (min_t) | |
#°# max_label.text="%0.2f" % (max_t) | |
# Compute average_center temperature of the middle of sensor and convert to palette color | |
#_# center_average = (frame[11*32 + 15] + frame[12*32 + 15] + frame[11*32 + 16] + frame[12*32 + 16]) / 4 | |
#_# center_color = int(map_range(center_average, min_t, max_t, 0, last_color )) | |
#_# center_label.text = "%0.2f" % (center_average) | |
#_# center_label.color = palette[center_color] | |
# Set the location of X for lowest temperature | |
#°# x_label.x = maxx * total_factor | |
#°# x_label.y = (23-maxy) * total_factor | |
# Set the location of O for highest temperature | |
#°# o_label.x = minx * total_factor | |
#°# o_label.y = (23-miny) * total_factor | |
# print("Total time for aquisition and display %0.2f s" % (time.monotonic()-stamp)) | |
stop_time = time.monotonic_ns() | |
gc.collect() | |
stop_mem = gc.mem_free() | |
print(stop_time - start_time, stop_mem - start_mem) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am merging all of my thermal camera with interpolation into a single source file: https://gist.github.com/dglaude/cdd4ede9e43fe620637a2199e05ba8cb