From a2a96516625b02238bc15cdee3db7e24077b3ce3 Mon Sep 17 00:00:00 2001 From: David Glaude Date: Thu, 2 Jan 2020 00:26:41 +0100 Subject: [PATCH 1/5] New example of mlx90640 on PyGamer This example does the following: 1) Create a color gradient into a palette of 64 colors ( using code from http://www.andrewnoske.com/wiki/Code_-_heatmaps_and_color_gradients ) In Loop: 2) Scan the mlx90640 at 4HZ (works for me with a refresh ever 0.4x seconds) 3) Map the temperature to palette index in a min to max range (anything below min goes to index 0 and above max to index 63) 4) While mapping the color, compute a new min and a new max for adjusting the color scale. --- examples/mlx90640_pygamer.py | 127 +++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 examples/mlx90640_pygamer.py diff --git a/examples/mlx90640_pygamer.py b/examples/mlx90640_pygamer.py new file mode 100644 index 0000000..fa62376 --- /dev/null +++ b/examples/mlx90640_pygamer.py @@ -0,0 +1,127 @@ +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): + 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 From 9dd0882be0e6ae473b7be8f21838bfbf4934cd60 Mon Sep 17 00:00:00 2001 From: David Glaude Date: Sun, 5 Jan 2020 01:25:16 +0100 Subject: [PATCH 2/5] Update mlx90640_pygamer.py Make pylint happy ? --- examples/mlx90640_pygamer.py | 49 ++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/examples/mlx90640_pygamer.py b/examples/mlx90640_pygamer.py index fa62376..f97ac6e 100644 --- a/examples/mlx90640_pygamer.py +++ b/examples/mlx90640_pygamer.py @@ -10,39 +10,43 @@ 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_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. + for c in range(number_of_colors): + value = c * (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 ) + 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[c]= ( 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 +# Bitmap for colour coded thermal value +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 that scale 32*24 to 128*96 +image_group = displayio.Group(scale=4) 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_bitmap = displayio.Bitmap( number_of_colors, 1, number_of_colors ) +# Create a Group Scale must be 128 divided by number_of_colors +scale_group = displayio.Group(scale=2) scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = 60) scale_group.append(scale_tile) @@ -83,12 +87,12 @@ def temp2index(s): mini = s if s < a1: - i = b1 + r = b1 elif s > a2: - i = b2 + r = b2 else: - i = int( round( b1 + ( (s - a1) * (b2 - b1) / (a2 - a1) ) ) ) - return i + r = int( round( b1 + ( (s - a1) * (b2 - b1) / (a2 - a1) ) ) ) + return r i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) @@ -125,3 +129,4 @@ def temp2index(s): a1 = mini # Automatically change the color scale a2 = maxi + From 631b916c5787096d50c5afc639cf0ad13921128a Mon Sep 17 00:00:00 2001 From: David Glaude Date: Sun, 5 Jan 2020 01:39:37 +0100 Subject: [PATCH 3/5] Update mlx90640_pygamer.py pylint will never like my use of global for min and max computation... --- examples/mlx90640_pygamer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/mlx90640_pygamer.py b/examples/mlx90640_pygamer.py index f97ac6e..d82d3dc 100644 --- a/examples/mlx90640_pygamer.py +++ b/examples/mlx90640_pygamer.py @@ -10,7 +10,8 @@ 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_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]] @@ -46,7 +47,7 @@ def MakeHeatMapColor(): scale_bitmap = displayio.Bitmap( number_of_colors, 1, number_of_colors ) # Create a Group Scale must be 128 divided by number_of_colors -scale_group = displayio.Group(scale=2) +scale_group = displayio.Group(scale=2) scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x = 0, y = 60) scale_group.append(scale_tile) @@ -57,7 +58,8 @@ def MakeHeatMapColor(): 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) +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) @@ -129,4 +131,3 @@ def temp2index(s): a1 = mini # Automatically change the color scale a2 = maxi - From 5bb485fab341f2e0c5de77a4efa1fd2ed912ba00 Mon Sep 17 00:00:00 2001 From: David Glaude Date: Sun, 5 Jan 2020 01:58:35 +0100 Subject: [PATCH 4/5] Update mlx90640_pygamer.py Remove the use of global to compute mini and maxi. Require a1 and a2 as parameter and moving the min/max computation. Also b1=0 to use all the color. --- examples/mlx90640_pygamer.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/examples/mlx90640_pygamer.py b/examples/mlx90640_pygamer.py index d82d3dc..f5b46dd 100644 --- a/examples/mlx90640_pygamer.py +++ b/examples/mlx90640_pygamer.py @@ -73,21 +73,15 @@ def MakeHeatMapColor(): mini = 0 maxi = 0 -a1 = 20 -a2 = 37 +my_a1 = 20 +my_a2 = 37 -def temp2index(s): +def temp2index(s, a1, a2): global mini, maxi - global a1, a2 - b1 = 1 + b1 = 0 b2 = number_of_colors - 1 - if s > maxi: - maxi = s - if s < mini: - mini = s - if s < a1: r = b1 elif s > a2: @@ -106,6 +100,7 @@ def temp2index(s): mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ frame = [0] * 768 + while True: stamp = time.monotonic() try: @@ -121,13 +116,17 @@ def temp2index(s): for h in range(24): for w in range(32): t = frame[h*32 + w] - image_bitmap[w, (23-h)] = temp2index(t) # Convert temperature to palette index + if t > maxi: + maxi = t + if t < mini: + mini = t + image_bitmap[w, (23-h)] = temp2index(t, my_a1, my_a2) - min_label.text="%0.2f" % (mini) + min_label.text="%0.2f" % (my_a1) - max_string="%0.2f" % (maxi) + max_string="%0.2f" % (my_a2) 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 + my_a1 = mini # Automatically change the color scale + my_a2 = maxi From 919a3a33665f3036f475e9b9d92ed81728c5e14f Mon Sep 17 00:00:00 2001 From: David Glaude Date: Sun, 5 Jan 2020 02:02:08 +0100 Subject: [PATCH 5/5] Update mlx90640_pygamer.py remove one more global --- examples/mlx90640_pygamer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/mlx90640_pygamer.py b/examples/mlx90640_pygamer.py index f5b46dd..8ad2b9e 100644 --- a/examples/mlx90640_pygamer.py +++ b/examples/mlx90640_pygamer.py @@ -77,8 +77,6 @@ def MakeHeatMapColor(): my_a2 = 37 def temp2index(s, a1, a2): - global mini, maxi - b1 = 0 b2 = number_of_colors - 1