upgrade to support CircuitPython 8.0.0
This commit is contained in:
parent
e85845c776
commit
ee52aeb34d
11 changed files with 438 additions and 349 deletions
493
PyGamer_Improved_Thermal_Camera/code.py
Normal file → Executable file
493
PyGamer_Improved_Thermal_Camera/code.py
Normal file → Executable file
|
|
@ -1,14 +1,18 @@
|
|||
# SPDX-FileCopyrightText: 2021 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-FileCopyrightText: 2022 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Thermal_Cam_v70_PyBadge_code.py
|
||||
# 2021-12-21 v7.0 # CircuitPython v7.x compatible
|
||||
"""
|
||||
`thermalcamera`
|
||||
================================================================================
|
||||
PyGamer/PyBadge Thermal Camera Project
|
||||
"""
|
||||
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
import gc
|
||||
import ulab
|
||||
import board
|
||||
import keypad
|
||||
import busio
|
||||
from ulab import numpy as np
|
||||
import displayio
|
||||
import neopixel
|
||||
from analogio import AnalogIn
|
||||
|
|
@ -18,79 +22,93 @@ from adafruit_display_text.label import Label
|
|||
from adafruit_bitmap_font import bitmap_font
|
||||
from adafruit_display_shapes.rect import Rect
|
||||
import adafruit_amg88xx
|
||||
from gamepadshift import GamePadShift
|
||||
from index_to_rgb.iron_spectrum import index_to_rgb
|
||||
from thermal_cam_converters import celsius_to_fahrenheit, fahrenheit_to_celsius
|
||||
from thermal_cam_config import ALARM_F, MIN_RANGE_F, MAX_RANGE_F, SELFIE
|
||||
from index_to_rgb.iron import index_to_rgb
|
||||
from thermalcamera_converters import celsius_to_fahrenheit, fahrenheit_to_celsius
|
||||
from thermalcamera_config import ALARM_F, MIN_RANGE_F, MAX_RANGE_F, SELFIE
|
||||
|
||||
# Instantiate display, joystick, speaker, and neopixels
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/CedarGroveStudios/ThermalCamera.git"
|
||||
|
||||
# Instantiate the integral display and define its size
|
||||
display = board.DISPLAY
|
||||
display.brightness = 1.0
|
||||
WIDTH = display.width
|
||||
HEIGHT = display.height
|
||||
|
||||
# Load the text font from the fonts folder
|
||||
font_0 = bitmap_font.load_font("/fonts/OpenSans-9.bdf")
|
||||
|
||||
# Instantiate the joystick if available
|
||||
if hasattr(board, "JOYSTICK_X"):
|
||||
has_joystick = True # PyGamer with joystick
|
||||
# PyGamer with joystick
|
||||
HAS_JOYSTICK = True
|
||||
joystick_x = AnalogIn(board.JOYSTICK_X)
|
||||
joystick_y = AnalogIn(board.JOYSTICK_Y)
|
||||
else:
|
||||
has_joystick = False # PyBadge with buttons
|
||||
# PyBadge with buttons
|
||||
HAS_JOYSTICK = False # PyBadge with buttons
|
||||
|
||||
speaker_enable = DigitalInOut(board.SPEAKER_ENABLE)
|
||||
speaker_enable.switch_to_output(value=True)
|
||||
# Enable the speaker
|
||||
DigitalInOut(board.SPEAKER_ENABLE).switch_to_output(value=True)
|
||||
|
||||
# Instantiate and clear the NeoPixels
|
||||
pixels = neopixel.NeoPixel(board.NEOPIXEL, 5, pixel_order=neopixel.GRB)
|
||||
pixels.brightness = 0.25 # Set NeoPixel brightness
|
||||
pixels.fill(0x000000) # Clear all NeoPixels
|
||||
pixels.brightness = 0.25
|
||||
pixels.fill(0x000000)
|
||||
|
||||
# Define and instantiate front panel buttons
|
||||
BUTTON_LEFT = 0b10000000
|
||||
BUTTON_UP = 0b01000000
|
||||
BUTTON_DOWN = 0b00100000
|
||||
BUTTON_RIGHT = 0b00010000
|
||||
BUTTON_SELECT = 0b00001000
|
||||
BUTTON_START = 0b00000100
|
||||
BUTTON_A = 0b00000010
|
||||
BUTTON_B = 0b00000001
|
||||
|
||||
panel = GamePadShift(
|
||||
DigitalInOut(board.BUTTON_CLOCK),
|
||||
DigitalInOut(board.BUTTON_OUT),
|
||||
DigitalInOut(board.BUTTON_LATCH),
|
||||
# Initialize ShiftRegisterKeys to read PyGamer/PyBadge buttons
|
||||
panel = keypad.ShiftRegisterKeys(
|
||||
clock=board.BUTTON_CLOCK,
|
||||
data=board.BUTTON_OUT,
|
||||
latch=board.BUTTON_LATCH,
|
||||
key_count=8,
|
||||
value_when_pressed=True,
|
||||
)
|
||||
|
||||
# Establish I2C interface for the AMG8833 Thermal Camera
|
||||
# Define front panel button event values
|
||||
BUTTON_LEFT = 7 # LEFT button
|
||||
BUTTON_UP = 6 # UP button
|
||||
BUTTON_DOWN = 5 # DOWN button
|
||||
BUTTON_RIGHT = 4 # RIGHT button
|
||||
BUTTON_FOCUS = 3 # SELECT button
|
||||
BUTTON_SET = 2 # START button
|
||||
BUTTON_HOLD = 1 # button A
|
||||
BUTTON_IMAGE = 0 # button B
|
||||
|
||||
# Initiate the AMG8833 Thermal Camera
|
||||
i2c = busio.I2C(board.SCL, board.SDA, frequency=400000)
|
||||
amg8833 = adafruit_amg88xx.AMG88XX(i2c)
|
||||
|
||||
# Display splash graphics
|
||||
splash = displayio.Group(scale=display.width // 160)
|
||||
bitmap = displayio.OnDiskBitmap("/thermal_cam_splash.bmp")
|
||||
bitmap = displayio.OnDiskBitmap("/thermalcamera_splash.bmp")
|
||||
splash.append(displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader))
|
||||
board.DISPLAY.show(splash)
|
||||
time.sleep(0.1) # Allow the splash to display
|
||||
|
||||
# Set up ulab arrays
|
||||
n = 8 # Thermal sensor grid axis size; AMG8833 sensor is 8x8
|
||||
sensor_data = ulab.numpy.array(range(n * n)).reshape((n, n)) # Color index narray
|
||||
grid_data = ulab.numpy.zeros(((2 * n) - 1, (2 * n) - 1)) # 15x15 color index narray
|
||||
histogram = ulab.numpy.zeros((2 * n) - 1) # Histogram accumulation narray
|
||||
# Thermal sensor grid axis size; AMG8833 sensor is 8x8
|
||||
SENSOR_AXIS = 8
|
||||
|
||||
# Display grid parameters
|
||||
GRID_AXIS = (2 * SENSOR_AXIS) - 1 # Number of cells per axis
|
||||
GRID_SIZE = HEIGHT # Axis size (pixels) for a square grid
|
||||
GRID_X_OFFSET = WIDTH - GRID_SIZE # Right-align grid with display boundary
|
||||
CELL_SIZE = GRID_SIZE // GRID_AXIS # Size of a grid cell in pixels
|
||||
PALETTE_SIZE = 100 # Number of display colors in spectral palette (must be > 0)
|
||||
|
||||
# Set up the 2-D sensor data narray
|
||||
SENSOR_DATA = np.array(range(SENSOR_AXIS**2)).reshape((SENSOR_AXIS, SENSOR_AXIS))
|
||||
# Set up and load the 2-D display color index narray with a spectrum
|
||||
GRID_DATA = np.array(range(GRID_AXIS**2)).reshape((GRID_AXIS, GRID_AXIS)) / (
|
||||
GRID_AXIS**2
|
||||
)
|
||||
# Set up the histogram accumulation narray
|
||||
# HISTOGRAM = np.zeros(GRID_AXIS)
|
||||
|
||||
# Convert default alarm and min/max range values from config file
|
||||
ALARM_C = fahrenheit_to_celsius(ALARM_F)
|
||||
MIN_RANGE_C = fahrenheit_to_celsius(MIN_RANGE_F)
|
||||
MAX_RANGE_C = fahrenheit_to_celsius(MAX_RANGE_F)
|
||||
|
||||
# The board's integral display size
|
||||
WIDTH = display.width
|
||||
HEIGHT = display.height
|
||||
|
||||
GRID_AXIS = (2 * n) - 1 # Number of cells along the grid x or y axis
|
||||
GRID_SIZE = HEIGHT # Maximum number of pixels for a square grid
|
||||
GRID_X_OFFSET = WIDTH - GRID_SIZE # Right-align grid with display boundary
|
||||
CELL_SIZE = GRID_SIZE // GRID_AXIS # Size of a grid cell in pixels
|
||||
|
||||
PALETTE_SIZE = 100 # Number of colors in spectral palette (must be > 0)
|
||||
|
||||
# Default colors for temperature value sidebar
|
||||
BLACK = 0x000000
|
||||
RED = 0xFF0000
|
||||
|
|
@ -100,81 +118,79 @@ BLUE = 0x0000FF
|
|||
WHITE = 0xFFFFFF
|
||||
|
||||
# Text colors for setup helper's on-screen parameters
|
||||
param_colors = [("ALARM", WHITE), ("RANGE", RED), ("RANGE", CYAN)]
|
||||
SETUP_COLORS = [("ALARM", WHITE), ("RANGE", RED), ("RANGE", CYAN)]
|
||||
|
||||
# ### Helpers ###
|
||||
def play_tone(freq=440, duration=0.01):
|
||||
"""Play a tone over the speaker"""
|
||||
tone(board.A0, freq, duration)
|
||||
return
|
||||
|
||||
|
||||
def flash_status(text="", duration=0.05): # Flash status message once
|
||||
def flash_status(text="", duration=0.05):
|
||||
"""Flash status message once"""
|
||||
status_label.color = WHITE
|
||||
status_label.text = text
|
||||
time.sleep(duration)
|
||||
status_label.color = BLACK
|
||||
time.sleep(duration)
|
||||
status_label.text = ""
|
||||
return
|
||||
|
||||
|
||||
def spectrum(): # Load a test spectrum into the grid_data array
|
||||
for row in range(0, GRID_AXIS):
|
||||
for col in range(0, GRID_AXIS):
|
||||
grid_data[row][col] = ((row * GRID_AXIS) + col) * 1 / 235
|
||||
return
|
||||
|
||||
|
||||
def update_image_frame(selfie=False): # Get camera data and update display
|
||||
for row in range(0, GRID_AXIS):
|
||||
for col in range(0, GRID_AXIS):
|
||||
def update_image_frame(selfie=False):
|
||||
"""Get camera data and update display"""
|
||||
for _row in range(0, GRID_AXIS):
|
||||
for _col in range(0, GRID_AXIS):
|
||||
if selfie:
|
||||
color_index = grid_data[GRID_AXIS - 1 - row][col]
|
||||
color_index = GRID_DATA[GRID_AXIS - 1 - _row][_col]
|
||||
else:
|
||||
color_index = grid_data[GRID_AXIS - 1 - row][GRID_AXIS - 1 - col]
|
||||
color_index = GRID_DATA[GRID_AXIS - 1 - _row][GRID_AXIS - 1 - _col]
|
||||
color = index_to_rgb(round(color_index * PALETTE_SIZE, 0) / PALETTE_SIZE)
|
||||
if color != image_group[((row * GRID_AXIS) + col)].fill:
|
||||
image_group[((row * GRID_AXIS) + col)].fill = color
|
||||
return
|
||||
if color != image_group[((_row * GRID_AXIS) + _col)].fill:
|
||||
image_group[((_row * GRID_AXIS) + _col)].fill = color
|
||||
|
||||
|
||||
def update_histo_frame(): # Calculate and display histogram
|
||||
min_histo.text = str(MIN_RANGE_F) # Display histogram legend
|
||||
def update_histo_frame():
|
||||
"""Calculate and display histogram"""
|
||||
min_histo.text = str(MIN_RANGE_F) # Display the legend
|
||||
max_histo.text = str(MAX_RANGE_F)
|
||||
|
||||
histogram = ulab.numpy.zeros(GRID_AXIS) # Clear histogram accumulation array
|
||||
for row in range(0, GRID_AXIS): # Collect camera data and calculate histo
|
||||
for col in range(0, GRID_AXIS):
|
||||
histo_index = int(map_range(grid_data[col, row], 0, 1, 0, GRID_AXIS - 1))
|
||||
histogram = np.zeros(GRID_AXIS) # Clear histogram accumulation array
|
||||
# Collect camera data and calculate the histogram
|
||||
for _row in range(0, GRID_AXIS):
|
||||
for _col in range(0, GRID_AXIS):
|
||||
histo_index = int(map_range(GRID_DATA[_col, _row], 0, 1, 0, GRID_AXIS - 1))
|
||||
histogram[histo_index] = histogram[histo_index] + 1
|
||||
|
||||
histo_scale = ulab.numpy.max(histogram) / (GRID_AXIS - 1)
|
||||
histo_scale = np.max(histogram) / (GRID_AXIS - 1)
|
||||
if histo_scale <= 0:
|
||||
histo_scale = 1
|
||||
|
||||
for col in range(0, GRID_AXIS): # Display histogram
|
||||
for row in range(0, GRID_AXIS):
|
||||
if histogram[col] / histo_scale > GRID_AXIS - 1 - row:
|
||||
image_group[((row * GRID_AXIS) + col)].fill = index_to_rgb(
|
||||
round((col / GRID_AXIS), 3)
|
||||
# Display the histogram
|
||||
for _col in range(0, GRID_AXIS):
|
||||
for _row in range(0, GRID_AXIS):
|
||||
if histogram[_col] / histo_scale > GRID_AXIS - 1 - _row:
|
||||
image_group[((_row * GRID_AXIS) + _col)].fill = index_to_rgb(
|
||||
round((_col / GRID_AXIS), 3)
|
||||
)
|
||||
else:
|
||||
image_group[((row * GRID_AXIS) + col)].fill = BLACK
|
||||
return
|
||||
image_group[((_row * GRID_AXIS) + _col)].fill = BLACK
|
||||
|
||||
|
||||
def ulab_bilinear_interpolation(): # 2x bilinear interpolation
|
||||
# Upscale sensor data array; by @v923z and @David.Glaude
|
||||
grid_data[1::2, ::2] = sensor_data[:-1, :]
|
||||
grid_data[1::2, ::2] += sensor_data[1:, :]
|
||||
grid_data[1::2, ::2] /= 2
|
||||
grid_data[::, 1::2] = grid_data[::, :-1:2]
|
||||
grid_data[::, 1::2] += grid_data[::, 2::2]
|
||||
grid_data[::, 1::2] /= 2
|
||||
return
|
||||
def ulab_bilinear_interpolation():
|
||||
"""2x bilinear interpolation to upscale the sensor data array; by @v923z
|
||||
and @David.Glaude."""
|
||||
GRID_DATA[1::2, ::2] = SENSOR_DATA[:-1, :]
|
||||
GRID_DATA[1::2, ::2] += SENSOR_DATA[1:, :]
|
||||
GRID_DATA[1::2, ::2] /= 2
|
||||
GRID_DATA[::, 1::2] = GRID_DATA[::, :-1:2]
|
||||
GRID_DATA[::, 1::2] += GRID_DATA[::, 2::2]
|
||||
GRID_DATA[::, 1::2] /= 2
|
||||
|
||||
|
||||
def setup_mode(): # Set alarm threshold and minimum/maximum range values
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
def setup_mode():
|
||||
"""Change alarm threshold and minimum/maximum range values"""
|
||||
status_label.color = WHITE
|
||||
status_label.text = "-SET-"
|
||||
|
||||
|
|
@ -189,68 +205,64 @@ def setup_mode(): # Set alarm threshold and minimum/maximum range values
|
|||
|
||||
param_index = 0 # Reset index of parameter to set
|
||||
|
||||
# Select parameter to set
|
||||
|
||||
buttons = panel.get_pressed()
|
||||
while not buttons & BUTTON_START:
|
||||
buttons = panel.get_pressed()
|
||||
while (not buttons & BUTTON_A) and (not buttons & BUTTON_START):
|
||||
up, down = move_buttons(joystick=has_joystick)
|
||||
if up:
|
||||
param_index = param_index - 1
|
||||
if down:
|
||||
param_index = param_index + 1
|
||||
setup_state = "SETUP" # Set initial state
|
||||
while setup_state == "SETUP":
|
||||
# Select parameter to set
|
||||
setup_state = "SELECT_PARAM" # Parameter selection state
|
||||
while setup_state == "SELECT_PARAM":
|
||||
param_index = max(0, min(2, param_index))
|
||||
status_label.text = param_colors[param_index][0]
|
||||
status_label.text = SETUP_COLORS[param_index][0]
|
||||
image_group[param_index + 226].color = BLACK
|
||||
status_label.color = BLACK
|
||||
time.sleep(0.25)
|
||||
image_group[param_index + 226].color = param_colors[param_index][1]
|
||||
image_group[param_index + 226].color = SETUP_COLORS[param_index][1]
|
||||
status_label.color = WHITE
|
||||
time.sleep(0.25)
|
||||
buttons = panel.get_pressed()
|
||||
|
||||
buttons = panel.get_pressed()
|
||||
if buttons & BUTTON_A: # Hold (button A) pressed
|
||||
play_tone(1319, 0.030) # E6
|
||||
while buttons & BUTTON_A: # Wait for button release
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
param_index -= get_joystick()
|
||||
|
||||
_buttons = panel.events.get()
|
||||
if _buttons and _buttons.pressed:
|
||||
if _buttons.key_number == BUTTON_UP: # HOLD button pressed
|
||||
param_index = param_index - 1
|
||||
if _buttons.key_number == BUTTON_DOWN: # SET button pressed
|
||||
param_index = param_index + 1
|
||||
if _buttons.key_number == BUTTON_HOLD: # HOLD button pressed
|
||||
play_tone(1319, 0.030) # Musical note E6
|
||||
setup_state = "ADJUST_VALUE" # Next state
|
||||
if _buttons.key_number == BUTTON_SET: # SET button pressed
|
||||
play_tone(1319, 0.030) # Musical note E6
|
||||
setup_state = "EXIT" # Next state
|
||||
|
||||
# Adjust parameter value
|
||||
param_value = int(image_group[param_index + 230].text)
|
||||
buttons = panel.get_pressed()
|
||||
while (not buttons & BUTTON_A) and (not buttons & BUTTON_START):
|
||||
up, down = move_buttons(joystick=has_joystick)
|
||||
if up:
|
||||
param_value = param_value + 1
|
||||
if down:
|
||||
param_value = param_value - 1
|
||||
|
||||
while setup_state == "ADJUST_VALUE":
|
||||
param_value = max(32, min(157, param_value))
|
||||
image_group[param_index + 230].text = str(param_value)
|
||||
image_group[param_index + 230].color = BLACK
|
||||
status_label.color = BLACK
|
||||
time.sleep(0.05)
|
||||
image_group[param_index + 230].color = param_colors[param_index][1]
|
||||
image_group[param_index + 230].color = SETUP_COLORS[param_index][1]
|
||||
status_label.color = WHITE
|
||||
time.sleep(0.2)
|
||||
buttons = panel.get_pressed()
|
||||
|
||||
buttons = panel.get_pressed()
|
||||
if buttons & BUTTON_A: # Button A pressed
|
||||
play_tone(1319, 0.030) # E6
|
||||
while buttons & BUTTON_A: # Wait for button release
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
param_value += get_joystick()
|
||||
|
||||
_buttons = panel.events.get()
|
||||
if _buttons and _buttons.pressed:
|
||||
if _buttons.key_number == BUTTON_UP: # HOLD button pressed
|
||||
param_value = param_value + 1
|
||||
if _buttons.key_number == BUTTON_DOWN: # SET button pressed
|
||||
param_value = param_value - 1
|
||||
if _buttons.key_number == BUTTON_HOLD: # HOLD button pressed
|
||||
play_tone(1319, 0.030) # Musical note E6
|
||||
setup_state = "SETUP" # Next state
|
||||
if _buttons.key_number == BUTTON_SET: # SET button pressed
|
||||
play_tone(1319, 0.030) # Musical note E6
|
||||
setup_state = "EXIT" # Next state
|
||||
|
||||
# Exit setup process
|
||||
buttons = panel.get_pressed()
|
||||
if buttons & BUTTON_START: # Start button pressed
|
||||
play_tone(784, 0.030) # G5
|
||||
while buttons & BUTTON_START: # Wait for button release
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
|
||||
status_label.text = "RESUME"
|
||||
time.sleep(0.5)
|
||||
status_label.text = ""
|
||||
|
|
@ -261,27 +273,23 @@ def setup_mode(): # Set alarm threshold and minimum/maximum range values
|
|||
return int(alarm_value.text), int(max_value.text), int(min_value.text)
|
||||
|
||||
|
||||
def move_buttons(joystick=False): # Read position buttons and joystick
|
||||
move_u = move_d = False
|
||||
if joystick: # For PyGamer: interpret joystick as buttons
|
||||
def get_joystick():
|
||||
"""Read the joystick and interpret as up/down buttons (PyGamer)"""
|
||||
if HAS_JOYSTICK:
|
||||
if joystick_y.value < 20000:
|
||||
move_u = True
|
||||
elif joystick_y.value > 44000:
|
||||
move_d = True
|
||||
else: # For PyBadge read the buttons
|
||||
buttons = panel.get_pressed()
|
||||
if buttons & BUTTON_UP:
|
||||
move_u = True
|
||||
if buttons & BUTTON_DOWN:
|
||||
move_d = True
|
||||
return move_u, move_d
|
||||
# Up
|
||||
return 1
|
||||
if joystick_y.value > 44000:
|
||||
# Down
|
||||
return -1
|
||||
return 0
|
||||
|
||||
|
||||
play_tone(440, 0.1) # A4
|
||||
play_tone(880, 0.1) # A5
|
||||
play_tone(440, 0.1) # Musical note A4
|
||||
play_tone(880, 0.1) # Musical note A5
|
||||
|
||||
# ### Define the display group ###
|
||||
t0 = time.monotonic() # Time marker: Define Display Elements
|
||||
mkr_t0 = time.monotonic() # Time marker: Define Display Elements
|
||||
image_group = displayio.Group(scale=1)
|
||||
|
||||
# Define the foundational thermal image grid cells; image_group[0:224]
|
||||
|
|
@ -363,40 +371,38 @@ range_histo.anchored_position = ((WIDTH // 2) + (GRID_X_OFFSET // 2), 121)
|
|||
image_group.append(range_histo) # image_group[236]
|
||||
|
||||
# ###--- PRIMARY PROCESS SETUP ---###
|
||||
t1 = time.monotonic() # Time marker: Primary Process Setup
|
||||
fm1 = gc.mem_free() # Monitor free memory
|
||||
display_image = True # Image display mode; False for histogram
|
||||
display_hold = False # Active display mode; True to hold display
|
||||
display_focus = False # Standard display range; True to focus display range
|
||||
mkr_t1 = time.monotonic() # Time marker: Primary Process Setup
|
||||
# pylint: disable=no-member
|
||||
mem_fm1 = gc.mem_free() # Monitor free memory
|
||||
DISPLAY_IMAGE = True # Image display mode; False for histogram
|
||||
DISPLAY_HOLD = False # Active display mode; True to hold display
|
||||
DISPLAY_FOCUS = False # Standard display range; True to focus display range
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
orig_max_range_f = 0 # Establish temporary range variables
|
||||
orig_min_range_f = 0
|
||||
|
||||
# Activate display and play welcome tone
|
||||
# Activate display, show preloaded sample spectrum, and play welcome tone
|
||||
display.show(image_group)
|
||||
spectrum()
|
||||
update_image_frame()
|
||||
flash_status("IRON", 0.75)
|
||||
play_tone(880, 0.010) # A5
|
||||
play_tone(880, 0.010) # Musical note A5
|
||||
|
||||
# ###--- PRIMARY PROCESS LOOP ---###
|
||||
while True:
|
||||
t2 = time.monotonic() # Time marker: Acquire Sensor Data
|
||||
if display_hold:
|
||||
mkr_t2 = time.monotonic() # Time marker: Acquire Sensor Data
|
||||
if DISPLAY_HOLD:
|
||||
flash_status("-HOLD-", 0.25)
|
||||
else:
|
||||
sensor = amg8833.pixels # Get sensor_data data
|
||||
sensor_data = ulab.numpy.array(sensor) # Copy to narray
|
||||
|
||||
t3 = time.monotonic() # Time marker: Constrain Sensor Values
|
||||
for row in range(0, 8):
|
||||
for col in range(0, 8):
|
||||
sensor_data[col, row] = min(max(sensor_data[col, row], 0), 80)
|
||||
# Put sensor data in array; limit to the range of 0, 80
|
||||
SENSOR_DATA = np.clip(np.array(sensor), 0, 80)
|
||||
|
||||
# Update and display alarm setting and max, min, and ave stats
|
||||
t4 = time.monotonic() # Time marker: Display Statistics
|
||||
v_max = ulab.numpy.max(sensor_data)
|
||||
v_min = ulab.numpy.min(sensor_data)
|
||||
v_ave = ulab.numpy.mean(sensor_data)
|
||||
mkr_t4 = time.monotonic() # Time marker: Display Statistics
|
||||
v_max = np.max(SENSOR_DATA)
|
||||
v_min = np.min(SENSOR_DATA)
|
||||
v_ave = np.mean(SENSOR_DATA)
|
||||
|
||||
alarm_value.text = str(ALARM_F)
|
||||
max_value.text = str(celsius_to_fahrenheit(v_max))
|
||||
|
|
@ -404,14 +410,14 @@ while True:
|
|||
ave_value.text = str(celsius_to_fahrenheit(v_ave))
|
||||
|
||||
# Normalize temperature to index values and interpolate
|
||||
t5 = time.monotonic() # Time marker: Normalize and Interpolate
|
||||
sensor_data = (sensor_data - MIN_RANGE_C) / (MAX_RANGE_C - MIN_RANGE_C)
|
||||
grid_data[::2, ::2] = sensor_data # Copy sensor data to the grid array
|
||||
mkr_t5 = time.monotonic() # Time marker: Normalize and Interpolate
|
||||
SENSOR_DATA = (SENSOR_DATA - MIN_RANGE_C) / (MAX_RANGE_C - MIN_RANGE_C)
|
||||
GRID_DATA[::2, ::2] = SENSOR_DATA # Copy sensor data to the grid array
|
||||
ulab_bilinear_interpolation() # Interpolate to produce 15x15 result
|
||||
|
||||
# Display image or histogram
|
||||
t6 = time.monotonic() # Time marker: Display Image
|
||||
if display_image:
|
||||
mkr_t6 = time.monotonic() # Time marker: Display Image
|
||||
if DISPLAY_IMAGE:
|
||||
update_image_frame(selfie=SELFIE)
|
||||
else:
|
||||
update_histo_frame()
|
||||
|
|
@ -419,89 +425,80 @@ while True:
|
|||
# If alarm threshold is reached, flash NeoPixels and play alarm tone
|
||||
if v_max >= ALARM_C:
|
||||
pixels.fill(RED)
|
||||
play_tone(880, 0.015) # A5
|
||||
play_tone(880, 0.015) # Musical note A5
|
||||
pixels.fill(BLACK)
|
||||
|
||||
# See if a panel button is pressed
|
||||
buttons = panel.get_pressed()
|
||||
if buttons & BUTTON_A: # Toggle display hold (shutter)
|
||||
play_tone(1319, 0.030) # E6
|
||||
display_hold = not display_hold
|
||||
buttons = panel.events.get()
|
||||
if buttons and buttons.pressed:
|
||||
if buttons.key_number == BUTTON_HOLD:
|
||||
# Toggle display hold (shutter)
|
||||
play_tone(1319, 0.030) # Musical note E6
|
||||
DISPLAY_HOLD = not DISPLAY_HOLD
|
||||
|
||||
while buttons & BUTTON_A:
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
if buttons.key_number == BUTTON_IMAGE:
|
||||
# Toggle image/histogram mode (display image)
|
||||
play_tone(659, 0.030) # Musical note E5
|
||||
DISPLAY_IMAGE = not DISPLAY_IMAGE
|
||||
|
||||
if buttons & BUTTON_B: # Toggle image/histogram mode (display image)
|
||||
play_tone(659, 0.030) # E5
|
||||
display_image = not display_image
|
||||
while buttons & BUTTON_B:
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
if DISPLAY_IMAGE:
|
||||
min_histo.color = None
|
||||
max_histo.color = None
|
||||
range_histo.color = None
|
||||
else:
|
||||
min_histo.color = CYAN
|
||||
max_histo.color = RED
|
||||
range_histo.color = BLUE
|
||||
|
||||
if display_image:
|
||||
min_histo.color = None
|
||||
max_histo.color = None
|
||||
range_histo.color = None
|
||||
else:
|
||||
min_histo.color = CYAN
|
||||
max_histo.color = RED
|
||||
range_histo.color = BLUE
|
||||
if buttons.key_number == BUTTON_FOCUS: # Toggle display focus mode
|
||||
play_tone(698, 0.030) # Musical note F5
|
||||
DISPLAY_FOCUS = not DISPLAY_FOCUS
|
||||
if DISPLAY_FOCUS:
|
||||
# Set range values to image min/max for focused image display
|
||||
orig_min_range_f = MIN_RANGE_F
|
||||
orig_max_range_f = MAX_RANGE_F
|
||||
MIN_RANGE_F = celsius_to_fahrenheit(v_min)
|
||||
MAX_RANGE_F = celsius_to_fahrenheit(v_max)
|
||||
# Update range min and max values in Celsius
|
||||
MIN_RANGE_C = v_min
|
||||
MAX_RANGE_C = v_max
|
||||
flash_status("FOCUS", 0.2)
|
||||
else:
|
||||
# Restore previous (original) range values for image display
|
||||
MIN_RANGE_F = orig_min_range_f
|
||||
MAX_RANGE_F = orig_max_range_f
|
||||
# Update range min and max values in Celsius
|
||||
MIN_RANGE_C = fahrenheit_to_celsius(MIN_RANGE_F)
|
||||
MAX_RANGE_C = fahrenheit_to_celsius(MAX_RANGE_F)
|
||||
flash_status("ORIG", 0.2)
|
||||
|
||||
if buttons & BUTTON_SELECT: # Toggle focus mode (display focus)
|
||||
play_tone(698, 0.030) # F5
|
||||
display_focus = not display_focus
|
||||
if display_focus:
|
||||
# Set range values to image min/max for focused image display
|
||||
orig_min_range_f = MIN_RANGE_F
|
||||
orig_max_range_f = MAX_RANGE_F
|
||||
MIN_RANGE_F = celsius_to_fahrenheit(v_min)
|
||||
MAX_RANGE_F = celsius_to_fahrenheit(v_max)
|
||||
# Update range min and max values in Celsius
|
||||
MIN_RANGE_C = v_min
|
||||
MAX_RANGE_C = v_max
|
||||
flash_status("FOCUS", 0.2)
|
||||
else:
|
||||
# Restore previous (original) range values for image display
|
||||
MIN_RANGE_F = orig_min_range_f
|
||||
MAX_RANGE_F = orig_max_range_f
|
||||
# Update range min and max values in Celsius
|
||||
if buttons.key_number == BUTTON_SET:
|
||||
# Activate setup mode
|
||||
play_tone(784, 0.030) # Musical note G5
|
||||
|
||||
# Invoke startup helper; update alarm and range values
|
||||
ALARM_F, MAX_RANGE_F, MIN_RANGE_F = setup_mode()
|
||||
ALARM_C = fahrenheit_to_celsius(ALARM_F)
|
||||
MIN_RANGE_C = fahrenheit_to_celsius(MIN_RANGE_F)
|
||||
MAX_RANGE_C = fahrenheit_to_celsius(MAX_RANGE_F)
|
||||
flash_status("ORIG", 0.2)
|
||||
|
||||
while buttons & BUTTON_SELECT:
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
|
||||
if buttons & BUTTON_START: # Activate setup mode
|
||||
play_tone(784, 0.030) # G5
|
||||
while buttons & BUTTON_START:
|
||||
buttons = panel.get_pressed()
|
||||
time.sleep(0.1)
|
||||
|
||||
# Invoke startup helper; update alarm and range values
|
||||
ALARM_F, MAX_RANGE_F, MIN_RANGE_F = setup_mode()
|
||||
ALARM_C = fahrenheit_to_celsius(ALARM_F)
|
||||
MIN_RANGE_C = fahrenheit_to_celsius(MIN_RANGE_F)
|
||||
MAX_RANGE_C = fahrenheit_to_celsius(MAX_RANGE_F)
|
||||
|
||||
t7 = time.monotonic() # Time marker: End of Primary Process
|
||||
mkr_t7 = time.monotonic() # Time marker: End of Primary Process
|
||||
gc.collect()
|
||||
fm7 = gc.mem_free()
|
||||
mem_fm7 = gc.mem_free()
|
||||
|
||||
# Print frame performance report
|
||||
print("*** PyBadge/Gamer Performance Stats ***")
|
||||
print(f" define displayio: {(t1 - t0):6.3f} sec")
|
||||
print(f" startup free memory: {fm1/1000:6.3} Kb")
|
||||
print(f" define display: {(mkr_t1 - mkr_t0):6.3f} sec")
|
||||
print(f" free memory: {mem_fm1 / 1000:6.3f} Kb")
|
||||
print("")
|
||||
print(
|
||||
f" 1) data acquisition: {(t4 - t2):6.3f} rate: {(1 / (t4 - t2)):5.1f} /sec"
|
||||
)
|
||||
print(f" 2) display stats: {(t5 - t4):6.3f}")
|
||||
print(f" 3) interpolate: {(t6 - t5):6.3f}")
|
||||
print(f" 4) display image: {(t7 - t6):6.3f}")
|
||||
print(f" =======")
|
||||
print(
|
||||
f"total frame: {(t7 - t2):6.3f} sec rate: {(1 / (t7 - t2)):5.1f} /sec"
|
||||
)
|
||||
print(f" free memory: {fm7/1000:6.3} Kb")
|
||||
print(" rate")
|
||||
print(f" 1) acquire: {(mkr_t4 - mkr_t2):6.3f} sec ", end="")
|
||||
print(f"{(1 / (mkr_t4 - mkr_t2)):5.1f} /sec")
|
||||
print(f" 2) stats: {(mkr_t5 - mkr_t4):6.3f} sec")
|
||||
print(f" 3) convert: {(mkr_t6 - mkr_t5):6.3f} sec")
|
||||
print(f" 4) display: {(mkr_t7 - mkr_t6):6.3f} sec")
|
||||
print(" =======")
|
||||
print(f"total frame: {(mkr_t7 - mkr_t2):6.3f} sec ", end="")
|
||||
print(f"{(1 / (mkr_t7 - mkr_t2)):5.1f} /sec")
|
||||
print(f" free memory: {mem_fm7 / 1000:6.3f} Kb")
|
||||
print("")
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py 42: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py 46: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py 50: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py 54: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible_spectrum.py 25: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible_spectrum.py 29: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible_spectrum.py 33: Simplify chained comparison between the operands (chained-comparison)
|
||||
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible_spectrum.py 37: Simplify chained comparison between the operands (chained-comparison)
|
||||
40
PyGamer_Improved_Thermal_Camera/index_to_rgb/grayscale_spectrum.py → PyGamer_Improved_Thermal_Camera/index_to_rgb/grayscale.py
Normal file → Executable file
40
PyGamer_Improved_Thermal_Camera/index_to_rgb/grayscale_spectrum.py → PyGamer_Improved_Thermal_Camera/index_to_rgb/grayscale.py
Normal file → Executable file
|
|
@ -1,16 +1,41 @@
|
|||
# SPDX-FileCopyrightText: 2021 Cedar Grove Studios for Adafruit Industries
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 JG for Cedar Grove Maker Studios
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
`cedargrove_rgb_spectrumtools.grayscale`
|
||||
================================================================================
|
||||
|
||||
Spectral Index to Grayscale RGB Converter Helper
|
||||
|
||||
* Author(s): JG
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://circuitpython.org/downloads
|
||||
|
||||
"""
|
||||
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/CedarGroveStudios/CircuitPython_RGB_SpectrumTools.git"
|
||||
|
||||
# grayscale_spectrum.py
|
||||
# 2021-05-19 version 1.1
|
||||
# Copyright 2021 Cedar Grove Studios
|
||||
# Spectral Index to Grayscale RGB Converter Helper
|
||||
|
||||
def map_range(x, in_min, in_max, out_min, out_max):
|
||||
"""
|
||||
Maps and constrains an input value from one range of values to another.
|
||||
(from adafruit_simpleio)
|
||||
|
||||
:param float x: The value to be mapped. No default.
|
||||
:param float in_min: The beginning of the input range. No default.
|
||||
:param float in_max: The end of the input range. No default.
|
||||
:param float out_min: The beginning of the output range. No default.
|
||||
:param float out_max: The end of the output range. No default.
|
||||
|
||||
:return: Returns value mapped to new range
|
||||
:rtype: float
|
||||
"""
|
||||
|
|
@ -28,11 +53,16 @@ def map_range(x, in_min, in_max, out_min, out_max):
|
|||
return max(min(mapped, out_max), out_min)
|
||||
return min(max(mapped, out_max), out_min)
|
||||
|
||||
|
||||
def index_to_rgb(index=0, gamma=0.8):
|
||||
"""
|
||||
Converts a spectral index to a grayscale RGB value. Spectral index in
|
||||
range of 0.0 to 1.0. Gamma in range of 0.0 to 1.0 (1.0=linear),
|
||||
default 0.8 for color TFT displays.
|
||||
|
||||
:param float index: The normalized index value, range 0 to 1.0. Defaults to 0.
|
||||
:param float gamma: The gamma color perception value. Defaults to 0.8.
|
||||
|
||||
:return: Returns a 24-bit RGB value
|
||||
:rtype: integer
|
||||
"""
|
||||
61
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py → PyGamer_Improved_Thermal_Camera/index_to_rgb/iron.py
Normal file → Executable file
61
PyGamer_Improved_Thermal_Camera/index_to_rgb/iron_spectrum.py → PyGamer_Improved_Thermal_Camera/index_to_rgb/iron.py
Normal file → Executable file
|
|
@ -1,16 +1,40 @@
|
|||
# SPDX-FileCopyrightText: 2021 Cedar Grove Studios for Adafruit Industries
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022 JG for Cedar Grove Maker Studios
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
`cedargrove_rgb_spectrumtools.iron`
|
||||
================================================================================
|
||||
|
||||
Temperature Index to Iron Pseudocolor Spectrum RGB Converter Helper
|
||||
|
||||
* Author(s): JG
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://circuitpython.org/downloads
|
||||
"""
|
||||
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/CedarGroveStudios/CircuitPython_RGB_SpectrumTools.git"
|
||||
|
||||
# iron_spectrum.py
|
||||
# 2021-05-27 version 1.2
|
||||
# Copyright 2021 Cedar Grove Studios
|
||||
# Temperature Index to Iron Pseudocolor Spectrum RGB Converter Helper
|
||||
|
||||
def map_range(x, in_min, in_max, out_min, out_max):
|
||||
"""
|
||||
Maps and constrains an input value from one range of values to another.
|
||||
(from adafruit_simpleio)
|
||||
|
||||
:param float x: The value to be mapped. No default.
|
||||
:param float in_min: The beginning of the input range. No default.
|
||||
:param float in_max: The end of the input range. No default.
|
||||
:param float out_min: The beginning of the output range. No default.
|
||||
:param float out_max: The end of the output range. No default.
|
||||
|
||||
:return: Returns value mapped to new range
|
||||
:rtype: float
|
||||
"""
|
||||
|
|
@ -28,11 +52,16 @@ def map_range(x, in_min, in_max, out_min, out_max):
|
|||
return max(min(mapped, out_max), out_min)
|
||||
return min(max(mapped, out_max), out_min)
|
||||
|
||||
|
||||
def index_to_rgb(index=0, gamma=0.5):
|
||||
"""
|
||||
Converts a temperature index to an iron thermographic pseudocolor spectrum
|
||||
RGB value. Temperature index in range of 0.0 to 1.0. Gamma in range of
|
||||
0.0 to 1.0 (1.0=linear), default 0.5 for color TFT displays.
|
||||
|
||||
:param float index: The normalized index value, range 0 to 1.0. Defaults to 0.
|
||||
:param float gamma: The gamma color perception value. Defaults to 0.5.
|
||||
|
||||
:return: Returns a 24-bit RGB value
|
||||
:rtype: integer
|
||||
"""
|
||||
|
|
@ -43,25 +72,29 @@ def index_to_rgb(index=0, gamma=0.5):
|
|||
red = 0.1
|
||||
grn = 0.1
|
||||
blu = (0.2 + (0.8 * map_range(band, 0, 70, 0.0, 1.0))) ** gamma
|
||||
if band >= 70 and band < 200: # blue to violet
|
||||
# if band >= 70 and band < 200: # blue to violet
|
||||
if 70 <= band < 200: # blue to violet
|
||||
red = map_range(band, 70, 200, 0.0, 0.6) ** gamma
|
||||
grn = 0.0
|
||||
blu = 1.0 ** gamma
|
||||
if band >= 200 and band < 300: # violet to red
|
||||
blu = 1.0**gamma
|
||||
# if band >= 200 and band < 300: # violet to red
|
||||
if 200 <= band < 300: # violet to red
|
||||
red = map_range(band, 200, 300, 0.6, 1.0) ** gamma
|
||||
grn = 0.0
|
||||
blu = map_range(band, 200, 300, 1.0, 0.0) ** gamma
|
||||
if band >= 300 and band < 400: # red to orange
|
||||
red = 1.0 ** gamma
|
||||
# if band >= 300 and band < 400: # red to orange
|
||||
if 300 <= band < 400: # red to orange
|
||||
red = 1.0**gamma
|
||||
grn = map_range(band, 300, 400, 0.0, 0.5) ** gamma
|
||||
blu = 0.0
|
||||
if band >= 400 and band < 500: # orange to yellow
|
||||
red = 1.0 ** gamma
|
||||
# if band >= 400 and band < 500: # orange to yellow
|
||||
if 400 <= band < 500: # orange to yellow
|
||||
red = 1.0**gamma
|
||||
grn = map_range(band, 400, 500, 0.5, 1.0) ** gamma
|
||||
blu = 0.0
|
||||
if band >= 500: # yellow to white
|
||||
red = 1.0 ** gamma
|
||||
grn = 1.0 ** gamma
|
||||
red = 1.0**gamma
|
||||
grn = 1.0**gamma
|
||||
blu = map_range(band, 500, 580, 0.0, 1.0) ** gamma
|
||||
|
||||
return (int(red * 255) << 16) + (int(grn * 255) << 8) + int(blu * 255)
|
||||
77
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible.py
Executable file
77
PyGamer_Improved_Thermal_Camera/index_to_rgb/visible.py
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
# SPDX-FileCopyrightText: Copyright (c) 2022 JG for Cedar Grove Maker Studios
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
`cedargrove_rgb_spectrumtools.visible`
|
||||
================================================================================
|
||||
|
||||
A Spectral Index to Visible (Rainbow) Spectrum RGB Converter Helper
|
||||
|
||||
Based on original 1996 Fortran code by Dan Bruton:
|
||||
physics.sfasu.edu/astro/color/spectra.html
|
||||
|
||||
* Author(s): JG
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Adafruit CircuitPython firmware for the supported boards:
|
||||
https://circuitpython.org/downloads
|
||||
"""
|
||||
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/CedarGroveStudios/CircuitPython_RGB_SpectrumTools.git"
|
||||
|
||||
|
||||
def index_to_rgb(index=0, gamma=0.5):
|
||||
"""
|
||||
Converts a spectral index to rainbow (visible light wavelength)
|
||||
spectrum to an RGB value. Spectral index in range of 0.0 to 1.0
|
||||
(violet --> white). Gamma in range of 0.0 to 1.0 (1.0=linear),
|
||||
default 0.5 for color TFT displays.
|
||||
|
||||
:param float index: The normalized index value, range 0 to 1.0. Defaults to 0.
|
||||
:param float gamma: The gamma color perception value. Defaults to 0.5.
|
||||
|
||||
:return: Returns a 24-bit RGB value
|
||||
:rtype: integer
|
||||
"""
|
||||
|
||||
wavelength = (index * 320) + 380
|
||||
|
||||
if wavelength < 440:
|
||||
intensity = 0.1 + (0.9 * (wavelength - 380) / (440 - 380))
|
||||
red = ((-1.0 * (wavelength - 440) / (440 - 380)) * intensity) ** gamma
|
||||
grn = 0.0
|
||||
blu = (1.0 * intensity) ** gamma
|
||||
# if wavelength >= 440 and wavelength < 490:
|
||||
if 440 <= wavelength < 490:
|
||||
red = 0.0
|
||||
grn = (1.0 * (wavelength - 440) / (490 - 440)) ** gamma
|
||||
blu = 1.0**gamma
|
||||
# if wavelength >= 490 and wavelength < 510:
|
||||
if 490 <= wavelength < 510:
|
||||
red = 0.0
|
||||
grn = 1.0**gamma
|
||||
blu = (-1.0 * (wavelength - 510) / (510 - 490)) ** gamma
|
||||
# if wavelength >= 510 and wavelength < 580:
|
||||
if 510 <= wavelength < 580:
|
||||
red = (1.0 * (wavelength - 510) / (580 - 510)) ** gamma
|
||||
grn = 1.0**gamma
|
||||
blu = 0.0
|
||||
# if wavelength >= 580 and wavelength < 645:
|
||||
if 580 <= wavelength < 645:
|
||||
red = 1.0**gamma
|
||||
grn = (-1.0 * (wavelength - 645) / (645 - 580)) ** gamma
|
||||
blu = 0.0
|
||||
if wavelength >= 645:
|
||||
intensity = 0.3 + (0.7 * (700 - wavelength) / (700 - 645))
|
||||
red = (1.0) ** gamma
|
||||
grn = (1.0 - intensity) ** gamma
|
||||
blu = (1.0 - intensity) ** gamma
|
||||
|
||||
return (int(red * 255) << 16) + (int(grn * 255) << 8) + int(blu * 255)
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2021 Cedar Grove Studios for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# visible_spectrum.py
|
||||
# 2021-05-27 version 1.2
|
||||
# Copyright 2021 Cedar Grove Studios
|
||||
# Spectral Index to Visible (Rainbow) Spectrum RGB Converter Helper
|
||||
# Based on original 1996 Fortran code by Dan Bruton:
|
||||
# physics.sfasu.edu/astro/color/spectra.html
|
||||
|
||||
def index_to_rgb(index=0, gamma=0.5):
|
||||
"""
|
||||
Converts a spectral index to rainbow (visible light wavelength)
|
||||
spectrum to an RGB value. Spectral index in range of 0.0 to 1.0
|
||||
(violet --> white). Gamma in range of 0.0 to 1.0 (1.0=linear),
|
||||
default 0.5 for color TFT displays.
|
||||
:return: Returns a 24-bit RGB value
|
||||
:rtype: integer
|
||||
"""
|
||||
|
||||
wl = (index * 320) + 380
|
||||
|
||||
if wl < 440:
|
||||
intensity = 0.1 + (0.9 * (wl - 380) / (440 - 380))
|
||||
red = ((-1.0 * (wl - 440) / (440 - 380)) * intensity) ** gamma
|
||||
grn = 0.0
|
||||
blu = (1.0 * intensity) ** gamma
|
||||
if wl >= 440 and wl < 490:
|
||||
red = 0.0
|
||||
grn = (1.0 * (wl - 440) / (490 - 440)) ** gamma
|
||||
blu = 1.0 ** gamma
|
||||
if wl >= 490 and wl < 510:
|
||||
red = 0.0
|
||||
grn = 1.0 ** gamma
|
||||
blu = (-1.0 * (wl - 510) / (510 - 490)) ** gamma
|
||||
if wl >= 510 and wl < 580:
|
||||
red = (1.0 * (wl - 510) / (580 - 510)) ** gamma
|
||||
grn = 1.0 ** gamma
|
||||
blu = 0.0
|
||||
if wl >= 580 and wl < 645:
|
||||
red = 1.0 ** gamma
|
||||
grn = (-1.0 * (wl - 645) / (645 - 580)) ** gamma
|
||||
blu = 0.0
|
||||
if wl >= 645:
|
||||
intensity = 0.3 + (0.7 * (700 - wl) / (700 - 645))
|
||||
red = (1.0) ** gamma
|
||||
grn = (1.0 - intensity) ** gamma
|
||||
blu = (1.0 - intensity) ** gamma
|
||||
|
||||
return (int(red * 255) << 16) + (int(grn * 255) << 8) + int(blu * 255)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2021 Anne Barela for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# thermal_cam_config.py
|
||||
# ### Alarm and range default values in Farenheit ###
|
||||
ALARM_F = 120
|
||||
MIN_RANGE_F = 60
|
||||
MAX_RANGE_F = 120
|
||||
|
||||
# ### Display characteristics
|
||||
SELFIE = False # Rear camera view; True for front view
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2020 CedarGroveStudios for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# thermal_cam_converters.py
|
||||
|
||||
def celsius_to_fahrenheit(deg_c=None): # convert C to F; round to 1 degree C
|
||||
return round(((9 / 5) * deg_c) + 32)
|
||||
|
||||
def fahrenheit_to_celsius(deg_f=None): # convert F to C; round to 1 degree F
|
||||
return round((deg_f - 32) * (5 / 9))
|
||||
16
PyGamer_Improved_Thermal_Camera/thermalcamera_config.py
Executable file
16
PyGamer_Improved_Thermal_Camera/thermalcamera_config.py
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
`thermalcamera_config`
|
||||
================================================================================
|
||||
Thermal Camera configuration parameters.
|
||||
"""
|
||||
|
||||
# ### Alarm and range default values in Farenheit ###
|
||||
ALARM_F = 120
|
||||
MIN_RANGE_F = 60
|
||||
MAX_RANGE_F = 120
|
||||
|
||||
# ### Display characteristics
|
||||
SELFIE = False # Rear camera view; True for front view
|
||||
18
PyGamer_Improved_Thermal_Camera/thermalcamera_converters.py
Normal file
18
PyGamer_Improved_Thermal_Camera/thermalcamera_converters.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# SPDX-FileCopyrightText: 2022 Jan Goolsbey for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
`thermalcamera_converters`
|
||||
================================================================================
|
||||
Celsius-to-Fahrenheit and Fahrenheit-to-Celsius converter helpers.
|
||||
"""
|
||||
|
||||
|
||||
def celsius_to_fahrenheit(deg_c=None):
|
||||
"""Convert C to F; round to 1 degree C"""
|
||||
return round(((9 / 5) * deg_c) + 32)
|
||||
|
||||
|
||||
def fahrenheit_to_celsius(deg_f=None):
|
||||
"""Convert F to C; round to 1 degree F"""
|
||||
return round((deg_f - 32) * (5 / 9))
|
||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Loading…
Reference in a new issue