mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
Finish refactor of the fir module
This commit is contained in:
parent
4914ea4096
commit
53f2248b86
@ -3,10 +3,14 @@
|
||||
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
|
||||
# live video output from the main camera.
|
||||
|
||||
import image, time, fir
|
||||
import sensor, image, time, fir
|
||||
|
||||
drawing_hint = image.BICUBIC # or image.BILINEAR or 0 (nearest neighbor)
|
||||
|
||||
# Initialize the thermal sensor
|
||||
fir.init(type=fir.FIR_AMG8833)
|
||||
w = fir.width() * 20
|
||||
h = fir.height() * 20
|
||||
|
||||
# FPS clock
|
||||
clock = time.clock()
|
||||
@ -15,7 +19,9 @@ while (True):
|
||||
clock.tick()
|
||||
|
||||
try:
|
||||
img = fir.snapshot(copy_to_fb=True)
|
||||
img = fir.snapshot(x_size=w, y_size=h,
|
||||
color_palette=sensor.PALETTE_IRONBOW, hint=drawing_hint,
|
||||
copy_to_fb=True)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
|
@ -3,10 +3,14 @@
|
||||
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
|
||||
# live video output from the main camera.
|
||||
|
||||
import image, time, fir
|
||||
import sensor, image, time, fir
|
||||
|
||||
drawing_hint = image.BICUBIC # or image.BILINEAR or 0 (nearest neighbor)
|
||||
|
||||
# Initialize the thermal sensor
|
||||
fir.init(type=fir.FIR_MLX90621)
|
||||
w = fir.width() * 20
|
||||
h = fir.height() * 20
|
||||
|
||||
# FPS clock
|
||||
clock = time.clock()
|
||||
@ -15,7 +19,9 @@ while (True):
|
||||
clock.tick()
|
||||
|
||||
try:
|
||||
img = fir.snapshot(copy_to_fb=True)
|
||||
img = fir.snapshot(x_size=w, y_size=h,
|
||||
color_palette=sensor.PALETTE_IRONBOW, hint=drawing_hint,
|
||||
copy_to_fb=True)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
|
@ -3,10 +3,14 @@
|
||||
# This example shows off how to overlay a heatmap onto your OpenMV Cam's
|
||||
# live video output from the main camera.
|
||||
|
||||
import image, time, fir
|
||||
import sensor, image, time, fir
|
||||
|
||||
drawing_hint = image.BICUBIC # or image.BILINEAR or 0 (nearest neighbor)
|
||||
|
||||
# Initialize the thermal sensor
|
||||
fir.init(type=fir.FIR_MLX90640, refresh=32) # 16Hz, 32Hz or 64Hz.
|
||||
fir.init(type=fir.FIR_MLX90640)
|
||||
w = fir.width() * 10
|
||||
h = fir.height() * 10
|
||||
|
||||
# FPS clock
|
||||
clock = time.clock()
|
||||
@ -15,7 +19,9 @@ while (True):
|
||||
clock.tick()
|
||||
|
||||
try:
|
||||
img = fir.snapshot(copy_to_fb=True)
|
||||
img = fir.snapshot(x_size=w, y_size=h,
|
||||
color_palette=sensor.PALETTE_IRONBOW, hint=drawing_hint,
|
||||
copy_to_fb=True)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
* FIR Python module.
|
||||
*/
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objlist.h"
|
||||
|
||||
#include "cambus.h"
|
||||
@ -17,13 +16,12 @@
|
||||
#include "MLX90621_I2C_Driver.h"
|
||||
#include "MLX90640_API.h"
|
||||
#include "MLX90640_I2C_Driver.h"
|
||||
#include "omv_boardconfig.h"
|
||||
#include "framebuffer.h"
|
||||
#include "omv_boardconfig.h"
|
||||
|
||||
#include "py_assert.h"
|
||||
#include "py_helper.h"
|
||||
#include "py_image.h"
|
||||
#include "py_fir.h"
|
||||
|
||||
#define MLX90621_ADDR 0xC0
|
||||
#define MLX90621_WIDTH 16
|
||||
@ -46,11 +44,6 @@
|
||||
#define AMG8833_INITIAL_RESET_VALUE 0x3F
|
||||
|
||||
static cambus_t fir_bus = {};
|
||||
static int fir_width = 0;
|
||||
static int fir_height = 0;
|
||||
static bool fir_transposed = false;
|
||||
static int fir_adc_resolution = 0;
|
||||
static int fir_ir_fresh_rate = 0;
|
||||
static void *fir_mlx_data = NULL;
|
||||
|
||||
static enum {
|
||||
@ -60,10 +53,72 @@ static enum {
|
||||
FIR_AMG8833
|
||||
} fir_sensor = FIR_NONE;
|
||||
|
||||
static int16_t fir_AMG8833_12_to_16(int16_t value)
|
||||
static int fir_width = 0;
|
||||
static int fir_height = 0;
|
||||
static int fir_ir_fresh_rate = 0;
|
||||
static int fir_adc_resolution = 0;
|
||||
static bool fir_transposed = false;
|
||||
|
||||
static void fir_get_minmax(float *data, size_t len, float *p_min, float *p_max)
|
||||
{
|
||||
if ((value >> 11) & 1) value |= 1 << 15;
|
||||
return value & 0x87FF;
|
||||
float min = FLT_MAX, max = FLT_MIN;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
float temp = data[i];
|
||||
if (temp < min) min = temp;
|
||||
if (temp > max) max = temp;
|
||||
}
|
||||
|
||||
*p_min = min;
|
||||
*p_max = max;
|
||||
}
|
||||
|
||||
// img->w == data_w && img->h == data_h && img->bpp == IMAGE_BPP_GRAYSCALE
|
||||
static void fir_fill_image_float(image_t *img, int w, int h, float *data, float min, float max,
|
||||
bool mirror, bool flip, bool dst_transpose, bool src_transpose)
|
||||
{
|
||||
float tmp = min;
|
||||
min = (min < max) ? min : max;
|
||||
max = (max > tmp) ? max : tmp;
|
||||
|
||||
float diff = 255.f / (max - min);
|
||||
int w_1 = w - 1, h_1 = h - 1;
|
||||
|
||||
if (!src_transpose) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
int y_dst = flip ? (h_1 - y) : y;
|
||||
float *raw_row = data + (y * w);
|
||||
uint8_t *row_pointer = ((uint8_t *) img->data) + (y_dst * w), *t_row_pointer = ((uint8_t *) img->data) + y_dst;
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
int x_dst = mirror ? (w_1 - x) : x;
|
||||
float raw = raw_row[x];
|
||||
if (raw < min) raw = min;
|
||||
if (raw > max) raw = max;
|
||||
int pixel = fast_roundf((raw - min) * diff);
|
||||
pixel = __USAT(pixel, 8);
|
||||
if (!dst_transpose) row_pointer[x_dst] = pixel;
|
||||
else t_row_pointer[x_dst * h] = pixel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int x_dst = mirror ? (w_1 - x) : x;
|
||||
float *raw_row = data + (x * h);
|
||||
uint8_t *t_row_pointer = ((uint8_t *) img->data) + (x_dst * h), *row_pointer = ((uint8_t *) img->data) + x_dst;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
int y_dst = flip ? (h_1 - y) : y;
|
||||
float raw = raw_row[y];
|
||||
if (raw < min) raw = min;
|
||||
if (raw > max) raw = max;
|
||||
int pixel = fast_roundf((raw - min) * diff);
|
||||
pixel = __USAT(pixel, 8);
|
||||
if (!dst_transpose) row_pointer[y_dst * w] = pixel;
|
||||
else t_row_pointer[y_dst] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// img->w == data_w && img->h == data_h && img->bpp == IMAGE_BPP_GRAYSCALE
|
||||
@ -92,7 +147,7 @@ static void fir_fill_image_float_obj(image_t *img, mp_obj_t *data, float min, fl
|
||||
|
||||
static void fir_MLX90621_get_frame(float *Ta, float *To)
|
||||
{
|
||||
uint16_t *data = fb_alloc0(MLX90621_FRAME_DATA_SIZE * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||
uint16_t *data = fb_alloc(MLX90621_FRAME_DATA_SIZE * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||
|
||||
PY_ASSERT_TRUE_MSG(MLX90621_GetFrameData(data) >= 0,
|
||||
"Failed to read the MLX90621 sensor data!");
|
||||
@ -118,12 +173,15 @@ static void fir_MLX90640_get_frame(float *Ta, float *To)
|
||||
*Ta = MLX90640_GetTa(data, fir_mlx_data);
|
||||
MLX90640_CalculateTo(data, fir_mlx_data, 0.95f, *Ta - 8, To);
|
||||
|
||||
MLX90640_BadPixelsCorrection(((paramsMLX90640 *) fir_mlx_data)->brokenPixels, To, 1, fir_mlx_data);
|
||||
MLX90640_BadPixelsCorrection(((paramsMLX90640 *) fir_mlx_data)->outlierPixels, To, 1, fir_mlx_data);
|
||||
|
||||
fb_free();
|
||||
}
|
||||
|
||||
static inline int16_t fir_AMG8833_12_to_16(int16_t value)
|
||||
{
|
||||
if ((value >> 11) & 1) value |= 1 << 15;
|
||||
return value & 0x87FF;
|
||||
}
|
||||
|
||||
static void fir_AMG8833_get_frame(float *Ta, float *To)
|
||||
{
|
||||
int16_t temp;
|
||||
@ -195,22 +253,21 @@ static mp_obj_t fir_get_ir(int w, int h, float Ta, float *To, bool mirror, bool
|
||||
|
||||
static mp_obj_t py_fir_deinit()
|
||||
{
|
||||
fir_width = 0;
|
||||
fir_height = 0;
|
||||
fir_transposed = false;
|
||||
fir_adc_resolution = 0;
|
||||
fir_ir_fresh_rate = 0;
|
||||
if (fir_sensor != FIR_NONE) {
|
||||
cambus_deinit(&fir_bus);
|
||||
fir_sensor = FIR_NONE;
|
||||
}
|
||||
|
||||
if (fir_mlx_data != NULL) {
|
||||
xfree(fir_mlx_data);
|
||||
fir_mlx_data = NULL;
|
||||
}
|
||||
|
||||
if (fir_sensor != FIR_NONE) {
|
||||
cambus_deinit(&fir_bus);
|
||||
fir_sensor = FIR_NONE;
|
||||
}
|
||||
|
||||
fir_width = 0;
|
||||
fir_height = 0;
|
||||
fir_ir_fresh_rate = 0;
|
||||
fir_adc_resolution = 0;
|
||||
fir_transposed = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_deinit_obj, py_fir_deinit);
|
||||
@ -218,119 +275,119 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_deinit_obj, py_fir_deinit);
|
||||
mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
py_fir_deinit();
|
||||
|
||||
bool first_init = true;
|
||||
|
||||
switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_MLX90621)) {
|
||||
case FIR_NONE: {
|
||||
return mp_const_none;
|
||||
}
|
||||
case FIR_MLX90621: {
|
||||
FIR_MLX90621:
|
||||
fir_width = MLX90621_WIDTH;
|
||||
fir_height = MLX90621_HEIGHT;
|
||||
fir_sensor = FIR_MLX90621;
|
||||
MLX90621_I2CInit(&fir_bus);
|
||||
// The EEPROM must be read at <= 400KHz.
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FULL);
|
||||
|
||||
// parse refresh rate and ADC resolution
|
||||
fir_ir_fresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64); // 64Hz
|
||||
fir_adc_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits
|
||||
int ir_fresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64);
|
||||
int adc_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18);
|
||||
|
||||
// sanitize values
|
||||
fir_adc_resolution = ((fir_adc_resolution > 18) ? 18 : (fir_adc_resolution < 15) ? 15 : fir_adc_resolution) - 15;
|
||||
fir_ir_fresh_rate = 14 - __CLZ(__RBIT((fir_ir_fresh_rate > 512) ? 512 : (fir_ir_fresh_rate < 1) ? 1 : fir_ir_fresh_rate));
|
||||
ir_fresh_rate = 14 - __CLZ(__RBIT((ir_fresh_rate > 512) ? 512 : ((ir_fresh_rate < 1) ? 1 : ir_fresh_rate)));
|
||||
adc_resolution = ((adc_resolution > 18) ? 18 : ((adc_resolution < 15) ? 15 : adc_resolution)) - 15;
|
||||
|
||||
fir_mlx_data = xalloc(sizeof(paramsMLX90621));
|
||||
|
||||
fir_sensor = FIR_MLX90621;
|
||||
FIR_MLX90621_RETRY:
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FULL); // The EEPROM must be read at <= 400KHz.
|
||||
MLX90621_I2CInit(&fir_bus);
|
||||
|
||||
fb_alloc_mark();
|
||||
uint8_t *eeprom = fb_alloc0(MLX90621_EEPROM_DATA_SIZE * sizeof(uint8_t), FB_ALLOC_NO_HINT);
|
||||
int error = 0;
|
||||
error |= MLX90621_DumpEE(eeprom);
|
||||
uint8_t *eeprom = fb_alloc(MLX90621_EEPROM_DATA_SIZE * sizeof(uint8_t), FB_ALLOC_NO_HINT);
|
||||
int error = MLX90621_DumpEE(eeprom);
|
||||
error |= MLX90621_Configure(eeprom);
|
||||
error |= MLX90621_SetResolution(fir_adc_resolution);
|
||||
error |= MLX90621_SetRefreshRate(fir_ir_fresh_rate);
|
||||
error |= MLX90621_SetRefreshRate(ir_fresh_rate);
|
||||
error |= MLX90621_SetResolution(adc_resolution);
|
||||
error |= MLX90621_ExtractParameters(eeprom, fir_mlx_data);
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
if (error != 0 && first_init == true) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
xfree(fir_mlx_data);
|
||||
fir_mlx_data = NULL;
|
||||
goto FIR_MLX90621;
|
||||
if (error != 0) {
|
||||
if (first_init) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
goto FIR_MLX90621_RETRY;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Failed to init the MLX90621!"));
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to FAST speed
|
||||
cambus_deinit(&fir_bus);
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FAST);
|
||||
|
||||
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90621!");
|
||||
fir_width = MLX90621_WIDTH;
|
||||
fir_height = MLX90621_HEIGHT;
|
||||
fir_ir_fresh_rate = ir_fresh_rate;
|
||||
fir_adc_resolution = adc_resolution;
|
||||
return mp_const_none;
|
||||
}
|
||||
case FIR_MLX90640: {
|
||||
FIR_MLX90640:
|
||||
fir_width = MLX90640_WIDTH;
|
||||
fir_height = MLX90640_HEIGHT;
|
||||
fir_sensor = FIR_MLX90640;
|
||||
MLX90640_I2CInit(&fir_bus);
|
||||
// The EEPROM must be read at <= 400KHz.
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FULL);
|
||||
|
||||
// parse refresh rate and ADC resolution
|
||||
fir_ir_fresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 32); // 32Hz
|
||||
fir_adc_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 19); // 19-bits
|
||||
int ir_fresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 32);
|
||||
int adc_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 19);
|
||||
|
||||
// sanitize values
|
||||
fir_adc_resolution = ((fir_adc_resolution > 19) ? 19 : (fir_adc_resolution < 16) ? 16 : fir_adc_resolution) - 16;
|
||||
fir_ir_fresh_rate = __CLZ(__RBIT((fir_ir_fresh_rate > 64) ? 64 : (fir_ir_fresh_rate < 1) ? 1 : fir_ir_fresh_rate)) + 1;
|
||||
ir_fresh_rate = __CLZ(__RBIT((ir_fresh_rate > 64) ? 64 : ((ir_fresh_rate < 1) ? 1 : ir_fresh_rate))) + 1;
|
||||
adc_resolution = ((adc_resolution > 19) ? 19 : ((adc_resolution < 16) ? 16 : adc_resolution)) - 16;
|
||||
|
||||
fir_mlx_data = xalloc(sizeof(paramsMLX90640));
|
||||
|
||||
fir_sensor = FIR_MLX90640;
|
||||
FIR_MLX90640_RETRY:
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FULL); // The EEPROM must be read at <= 400KHz.
|
||||
MLX90640_I2CInit(&fir_bus);
|
||||
|
||||
fb_alloc_mark();
|
||||
uint16_t *eeprom = fb_alloc(MLX90640_EEPROM_DATA_SIZE * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||
int error = 0;
|
||||
error |= MLX90640_DumpEE(MLX90640_ADDR, eeprom);
|
||||
error |= MLX90640_SetResolution(MLX90640_ADDR, fir_adc_resolution);
|
||||
error |= MLX90640_SetRefreshRate(MLX90640_ADDR, fir_ir_fresh_rate);
|
||||
int error = MLX90640_DumpEE(MLX90640_ADDR, eeprom);
|
||||
error |= MLX90640_SetRefreshRate(MLX90640_ADDR, ir_fresh_rate);
|
||||
error |= MLX90640_SetResolution(MLX90640_ADDR, adc_resolution);
|
||||
error |= MLX90640_ExtractParameters(eeprom, fir_mlx_data);
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
if (error != 0 && first_init == true) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
xfree(fir_mlx_data);
|
||||
fir_mlx_data = NULL;
|
||||
goto FIR_MLX90640;
|
||||
if (error != 0) {
|
||||
if (first_init) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
goto FIR_MLX90640_RETRY;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Failed to init the MLX90640!"));
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to FAST speed
|
||||
cambus_deinit(&fir_bus);
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_FAST);
|
||||
|
||||
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the MLX90640!");
|
||||
fir_width = MLX90640_WIDTH;
|
||||
fir_height = MLX90640_HEIGHT;
|
||||
fir_ir_fresh_rate = ir_fresh_rate;
|
||||
fir_adc_resolution = adc_resolution;
|
||||
return mp_const_none;
|
||||
}
|
||||
case FIR_AMG8833: {
|
||||
FIR_AMG8833:
|
||||
fir_width = AMG8833_WIDTH;
|
||||
fir_height = AMG8833_HEIGHT;
|
||||
fir_sensor = FIR_AMG8833;
|
||||
FIR_AMG8833_RETRY:
|
||||
cambus_init(&fir_bus, FIR_I2C_ID, CAMBUS_SPEED_STANDARD);
|
||||
|
||||
fir_ir_fresh_rate = 10; // 10Hz
|
||||
fir_adc_resolution = 12; // 12-bits
|
||||
|
||||
int error = cambus_write_bytes(&fir_bus, AMG8833_ADDR, AMG8833_RESET_REGISTER, (uint8_t [1]){AMG8833_INITIAL_RESET_VALUE}, 1);
|
||||
|
||||
if (error != 0 && first_init == true) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
goto FIR_AMG8833;
|
||||
if (error != 0) {
|
||||
if (first_init) {
|
||||
first_init = false;
|
||||
cambus_pulse_scl(&fir_bus);
|
||||
goto FIR_AMG8833_RETRY;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Failed to init the AMG8833!"));
|
||||
}
|
||||
}
|
||||
|
||||
PY_ASSERT_TRUE_MSG(error == 0, "Failed to init the AMG8833!");
|
||||
fir_width = AMG8833_WIDTH;
|
||||
fir_height = AMG8833_HEIGHT;
|
||||
fir_ir_fresh_rate = 10;
|
||||
fir_adc_resolution = 12;
|
||||
return mp_const_none;
|
||||
}
|
||||
default: {
|
||||
@ -342,6 +399,13 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_init_obj, 0, py_fir_init);
|
||||
|
||||
static mp_obj_t py_fir_type()
|
||||
{
|
||||
if (fir_sensor == FIR_NONE) return mp_const_none;
|
||||
return mp_obj_new_int(fir_sensor);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_type_obj, py_fir_type);
|
||||
|
||||
static mp_obj_t py_fir_width()
|
||||
{
|
||||
if (fir_sensor == FIR_NONE) return mp_const_none;
|
||||
@ -356,13 +420,6 @@ static mp_obj_t py_fir_height()
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_height_obj, py_fir_height);
|
||||
|
||||
static mp_obj_t py_fir_type()
|
||||
{
|
||||
if (fir_sensor == FIR_NONE) return mp_const_none;
|
||||
return mp_obj_new_int(fir_sensor);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_type_obj, py_fir_type);
|
||||
|
||||
static mp_obj_t py_fir_refresh()
|
||||
{
|
||||
const int mlx_90621_refresh_rates[16] = {512, 512, 512, 512, 512, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 0};
|
||||
@ -393,7 +450,7 @@ mp_obj_t py_fir_read_ta()
|
||||
}
|
||||
case FIR_MLX90621: {
|
||||
fb_alloc_mark();
|
||||
uint16_t *data = fb_alloc0(MLX90621_FRAME_DATA_SIZE * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||
uint16_t *data = fb_alloc(MLX90621_FRAME_DATA_SIZE * sizeof(uint16_t), FB_ALLOC_NO_HINT);
|
||||
PY_ASSERT_TRUE_MSG(MLX90621_GetFrameData(data) >= 0,
|
||||
"Failed to read the MLX90640 sensor data!");
|
||||
mp_obj_t result = mp_obj_new_float(MLX90621_GetTa(data, fir_mlx_data));
|
||||
@ -446,7 +503,7 @@ mp_obj_t py_fir_read_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
}
|
||||
case FIR_MLX90640: {
|
||||
fb_alloc_mark();
|
||||
float Ta, *To = fb_alloc0(MLX90640_WIDTH * MLX90640_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
float Ta, *To = fb_alloc(MLX90640_WIDTH * MLX90640_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
fir_MLX90640_get_frame(&Ta, To);
|
||||
mp_obj_t result = fir_get_ir(MLX90640_WIDTH, MLX90640_HEIGHT, Ta, To,
|
||||
arg_hmirror ^ true, arg_vflip, fir_transposed, false);
|
||||
@ -455,7 +512,7 @@ mp_obj_t py_fir_read_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
}
|
||||
case FIR_AMG8833: {
|
||||
fb_alloc_mark();
|
||||
float Ta, *To = fb_alloc0(AMG8833_WIDTH * AMG8833_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
float Ta, *To = fb_alloc(AMG8833_WIDTH * AMG8833_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
fir_AMG8833_get_frame(&Ta, To);
|
||||
mp_obj_t result = fir_get_ir(AMG8833_WIDTH, AMG8833_HEIGHT, Ta, To,
|
||||
arg_hmirror ^ true, arg_vflip, fir_transposed, true);
|
||||
@ -626,15 +683,102 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_draw_ir_obj, 2, py_fir_draw_ir);
|
||||
mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
if (fir_sensor == FIR_NONE) return mp_const_none;
|
||||
mp_obj_t ir = py_fir_read_ir(0, NULL, NULL);
|
||||
size_t len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_tuple_get(ir, &len, &items);
|
||||
|
||||
int pixformat = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixformat), PIXFORMAT_RGB565);
|
||||
PY_ASSERT_TRUE_MSG((pixformat == PIXFORMAT_GRAYSCALE) || (pixformat == PIXFORMAT_RGB565), "Invalid Pixformat!");
|
||||
bool arg_hmirror =
|
||||
py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false);
|
||||
bool arg_vflip =
|
||||
py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false);
|
||||
bool arg_transpose =
|
||||
py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_transpose), false);
|
||||
|
||||
mp_obj_t copy_to_fb_obj = py_helper_keyword_object(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), NULL);
|
||||
image_t src_img;
|
||||
src_img.bpp = IMAGE_BPP_GRAYSCALE;
|
||||
src_img.w = arg_transpose ? fir_height : fir_width;
|
||||
src_img.h = arg_transpose ? fir_width : fir_height;
|
||||
|
||||
float arg_x_scale = 1.f;
|
||||
bool got_x_scale = py_helper_keyword_float_maybe(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_scale), &arg_x_scale);
|
||||
|
||||
float arg_y_scale = 1.f;
|
||||
bool got_y_scale = py_helper_keyword_float_maybe(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_scale), &arg_y_scale);
|
||||
|
||||
rectangle_t arg_roi;
|
||||
py_helper_keyword_rectangle_roi(&src_img, n_args, args, 5, kw_args, &arg_roi);
|
||||
|
||||
int arg_rgb_channel = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_channel), -1);
|
||||
if ((arg_rgb_channel < -1) || (2 < arg_rgb_channel)) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "-1 <= rgb_channel <= 2!"));
|
||||
|
||||
int arg_alpha = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128);
|
||||
if ((arg_alpha < 0) || (256 < arg_alpha)) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "0 <= alpha <= 256!"));
|
||||
|
||||
const uint16_t *color_palette = rainbow_table;
|
||||
{
|
||||
int palette;
|
||||
|
||||
uint arg_index = 8;
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), MP_MAP_LOOKUP);
|
||||
|
||||
if (kw_arg && MP_OBJ_IS_TYPE(kw_arg->value, mp_const_none)) {
|
||||
color_palette = NULL;
|
||||
} else if ((n_args > arg_index) && MP_OBJ_IS_TYPE(args[arg_index], mp_const_none)) {
|
||||
color_palette = NULL;
|
||||
} else if (py_helper_keyword_int_maybe(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), &palette)) {
|
||||
if (palette == COLOR_PALETTE_RAINBOW) color_palette = rainbow_table;
|
||||
else if (palette == COLOR_PALETTE_IRONBOW) color_palette = ironbow_table;
|
||||
else nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid pre-defined color palette!"));
|
||||
} else {
|
||||
image_t *arg_color_palette = py_helper_keyword_to_image_mutable_color_palette(n_args, args, arg_index, kw_args);
|
||||
|
||||
if (arg_color_palette) {
|
||||
if (arg_color_palette->bpp != IMAGE_BPP_RGB565) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Color palette must be RGB565!"));
|
||||
if ((arg_color_palette->w * arg_color_palette->h) != 256) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Color palette must be 256 pixels!"));
|
||||
color_palette = (uint16_t *) arg_color_palette->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t *alpha_palette = NULL;
|
||||
{
|
||||
image_t *arg_alpha_palette = py_helper_keyword_to_image_mutable_alpha_palette(n_args, args, 9, kw_args);
|
||||
|
||||
if (arg_alpha_palette) {
|
||||
if (arg_alpha_palette->bpp != IMAGE_BPP_GRAYSCALE) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Alpha palette must be GRAYSCALE!"));
|
||||
if ((arg_alpha_palette->w * arg_alpha_palette->h) != 256) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Alpha palette must be 256 pixels!"));
|
||||
alpha_palette = (uint8_t *) arg_alpha_palette->data;
|
||||
}
|
||||
}
|
||||
|
||||
image_hint_t hint = py_helper_keyword_int(n_args, args, 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hint), 0);
|
||||
|
||||
int arg_x_size;
|
||||
bool got_x_size = py_helper_keyword_int_maybe(n_args, args, 11, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_size), &arg_x_size);
|
||||
|
||||
int arg_y_size;
|
||||
bool got_y_size = py_helper_keyword_int_maybe(n_args, args, 12, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_size), &arg_y_size);
|
||||
|
||||
if (got_x_scale && got_x_size) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Choose either x_scale or x_size not both!"));
|
||||
if (got_y_scale && got_y_size) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Choose either y_scale or y_size not both!"));
|
||||
|
||||
if (got_x_size) arg_x_scale = arg_x_size / ((float) arg_roi.w);
|
||||
if (got_y_size) arg_y_scale = arg_y_size / ((float) arg_roi.h);
|
||||
|
||||
if ((!got_x_scale) && (!got_x_size) && got_y_size) arg_x_scale = arg_y_scale;
|
||||
if ((!got_y_scale) && (!got_y_size) && got_x_size) arg_y_scale = arg_x_scale;
|
||||
|
||||
mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 13, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale), NULL);
|
||||
float min, max;
|
||||
|
||||
if (scale_obj) {
|
||||
mp_obj_t *arg_scale;
|
||||
mp_obj_get_array_fixed_n(scale_obj, 2, &arg_scale);
|
||||
min = mp_obj_get_float(arg_scale[0]);
|
||||
max = mp_obj_get_float(arg_scale[1]);
|
||||
}
|
||||
|
||||
int arg_pixformat = py_helper_keyword_int(n_args, args, 14, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixformat), PIXFORMAT_RGB565);
|
||||
if ((arg_pixformat != PIXFORMAT_GRAYSCALE) && (arg_pixformat != PIXFORMAT_RGB565)) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid pixformat!"));
|
||||
|
||||
mp_obj_t copy_to_fb_obj = py_helper_keyword_object(n_args, args, 15, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), NULL);
|
||||
bool copy_to_fb = false;
|
||||
image_t *arg_other = NULL;
|
||||
|
||||
@ -650,46 +794,68 @@ mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
fb_update_jpeg_buffer();
|
||||
}
|
||||
|
||||
image_t image;
|
||||
image.w = fir_width;
|
||||
image.h = fir_height;
|
||||
image.bpp = (pixformat == PIXFORMAT_RGB565) ? IMAGE_BPP_RGB565 : IMAGE_BPP_GRAYSCALE;
|
||||
image.data = NULL;
|
||||
image_t dst_img;
|
||||
dst_img.w = fast_floorf(arg_roi.w * arg_x_scale);
|
||||
dst_img.h = fast_floorf(arg_roi.h * arg_y_scale);
|
||||
dst_img.bpp = (arg_pixformat == PIXFORMAT_RGB565) ? IMAGE_BPP_RGB565 : IMAGE_BPP_GRAYSCALE;
|
||||
|
||||
if (copy_to_fb) {
|
||||
py_helper_set_to_framebuffer(&image);
|
||||
py_helper_set_to_framebuffer(&dst_img);
|
||||
} else if (arg_other) {
|
||||
PY_ASSERT_TRUE_MSG((image_size(&image) <= image_size(arg_other)), "The new image won't fit in the target frame buffer!");
|
||||
image.data = arg_other->data;
|
||||
PY_ASSERT_TRUE_MSG((image_size(&dst_img) <= image_size(arg_other)),
|
||||
"The new image won't fit in the target frame buffer!");
|
||||
arg_other->w = dst_img.w;
|
||||
arg_other->h = dst_img.h;
|
||||
arg_other->bpp = dst_img.bpp;
|
||||
dst_img.data = arg_other->data;
|
||||
py_helper_update_framebuffer(&dst_img);
|
||||
} else {
|
||||
image.data = xalloc(image_size(&image));
|
||||
dst_img.data = xalloc(image_size(&dst_img));
|
||||
}
|
||||
|
||||
// Zero the image we are about to draw on.
|
||||
memset(image.data, 0, image_size(&image));
|
||||
fb_alloc_mark();
|
||||
|
||||
py_helper_update_framebuffer(&image);
|
||||
src_img.data = fb_alloc(src_img.w * src_img.h * sizeof(uint8_t), FB_ALLOC_NO_HINT);
|
||||
|
||||
if (arg_other) {
|
||||
arg_other->w = image.w;
|
||||
arg_other->h = image.h;
|
||||
arg_other->bpp = image.bpp;
|
||||
switch(fir_sensor) {
|
||||
case FIR_MLX90621: {
|
||||
float Ta, *To = fb_alloc(MLX90621_WIDTH * MLX90621_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
fir_MLX90621_get_frame(&Ta, To);
|
||||
if (!scale_obj) fir_get_minmax(To, MLX90621_WIDTH * MLX90621_HEIGHT, &min, &max);
|
||||
fir_fill_image_float(&src_img, MLX90621_WIDTH, MLX90621_HEIGHT, To, min, max,
|
||||
arg_hmirror ^ true, arg_vflip, arg_transpose, true);
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
case FIR_MLX90640: {
|
||||
float Ta, *To = fb_alloc(MLX90640_WIDTH * MLX90640_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
fir_MLX90640_get_frame(&Ta, To);
|
||||
if (!scale_obj) fir_get_minmax(To, MLX90640_WIDTH * MLX90640_HEIGHT, &min, &max);
|
||||
fir_fill_image_float(&src_img, MLX90640_WIDTH, MLX90640_HEIGHT, To, min, max,
|
||||
arg_hmirror ^ true, arg_vflip, arg_transpose, false);
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
case FIR_AMG8833: {
|
||||
float Ta, *To = fb_alloc(AMG8833_WIDTH * AMG8833_HEIGHT * sizeof(float), FB_ALLOC_NO_HINT);
|
||||
fir_AMG8833_get_frame(&Ta, To);
|
||||
if (!scale_obj) fir_get_minmax(To, AMG8833_WIDTH * AMG8833_HEIGHT, &min, &max);
|
||||
fir_fill_image_float(&src_img, AMG8833_WIDTH, AMG8833_HEIGHT, To, min, max,
|
||||
arg_hmirror ^ true, arg_vflip, arg_transpose, true);
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t snapshot = py_image_from_struct(&image);
|
||||
imlib_draw_image(&dst_img, &src_img, 0, 0, arg_x_scale, arg_y_scale, &arg_roi,
|
||||
arg_rgb_channel, arg_alpha, color_palette, alpha_palette, (hint & (~IMAGE_HINT_CENTER)) | IMAGE_HINT_BLACK_BACKGROUND, NULL, NULL);
|
||||
|
||||
mp_obj_t *new_args = xalloc((2 + n_args) * sizeof(mp_obj_t));
|
||||
new_args[0] = snapshot;
|
||||
new_args[1] = items[1]; // ir array
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
for (uint i = 0; i < n_args; i++) {
|
||||
new_args[2+i] = args[i];
|
||||
}
|
||||
|
||||
py_fir_draw_ir(2 + n_args, new_args, kw_args);
|
||||
gc_collect();
|
||||
|
||||
return snapshot;
|
||||
return py_image_from_struct(&dst_img);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_fir_snapshot_obj, 0, py_fir_snapshot);
|
||||
|
||||
@ -702,9 +868,9 @@ STATIC const mp_rom_map_elem_t globals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_FIR_AMG8833), MP_ROM_INT(FIR_AMG8833) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&py_fir_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&py_fir_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_fir_type_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&py_fir_width_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&py_fir_height_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_fir_type_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&py_fir_refresh_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_resolution), MP_ROM_PTR(&py_fir_resolution_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_ta), MP_ROM_PTR(&py_fir_read_ta_obj) },
|
||||
|
Loading…
Reference in New Issue
Block a user