diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index e70443978..48d2144d5 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -67,6 +67,9 @@ #define UINT64_T_MASK (UINT64_T_BITS - 1) #define UINT64_T_SHIFT IM_LOG2(UINT64_T_MASK) +#define IM_DEG2RAD(x) (((x)*M_PI)/180) +#define IM_RAD2DEG(x) (((x)*180)/M_PI) + ///////////////// // Point Stuff // ///////////////// @@ -359,6 +362,23 @@ void image_copy(image_t *dst, image_t *src); size_t image_size(image_t *ptr); bool image_get_mask_pixel(image_t *ptr, int x, int y); +#define IMAGE_IS_MUTABLE(image) \ +({ \ + __typeof__ (image) _image = (image); \ + (_image->bpp == IMAGE_BPP_BINARY) || \ + (_image->bpp == IMAGE_BPP_GRAYSCALE) || \ + (_image->bpp == IMAGE_BPP_RGB565); \ +}) + +#define IMAGE_IS_MUTABLE_BAYER(image) \ +({ \ + __typeof__ (image) _image = (image); \ + (_image->bpp == IMAGE_BPP_BINARY) || \ + (_image->bpp == IMAGE_BPP_GRAYSCALE) || \ + (_image->bpp == IMAGE_BPP_RGB565) || \ + (_image->bpp == IMAGE_BPP_BAYER); \ +}) + #define IMAGE_BINARY_LINE_LEN(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT) #define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t)) diff --git a/src/omv/py/py_assert.h b/src/omv/py/py_assert.h index 18b8b571d..eae85e0f9 100644 --- a/src/omv/py/py_assert.h +++ b/src/omv/py/py_assert.h @@ -8,6 +8,7 @@ */ #ifndef __PY_ASSERT_H__ #define __PY_ASSERT_H__ +#include "mp.h" #define PY_ASSERT_TRUE(cond) \ do { \ if ((cond) == 0) { \ diff --git a/src/omv/py/py_fir.c b/src/omv/py/py_fir.c index 8646400be..420e29393 100644 --- a/src/omv/py/py_fir.c +++ b/src/omv/py/py_fir.c @@ -223,7 +223,7 @@ calling: mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { py_fir_deinit(); - switch (py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) { + switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), FIR_SHIELD)) { case FIR_NONE: return mp_const_none; case FIR_SHIELD: @@ -234,8 +234,8 @@ mp_obj_t py_fir_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) soft_i2c_init(); // pasre refresh rate and ADC resolution - uint32_t IR_refresh_rate = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64); // 64Hz - uint32_t ADC_resolution = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits + uint32_t IR_refresh_rate = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_refresh), 64); // 64Hz + uint32_t ADC_resolution = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_resolution), 18); // 18-bits // sanitize values ADC_resolution = ((ADC_resolution > 18)? 18:(ADC_resolution < 15)? 15:ADC_resolution) - 15; @@ -394,14 +394,14 @@ mp_obj_t py_fir_draw_ta(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) float Ta = mp_obj_get_float(args[1]); float min = -17.7778, max = 37.7778; // 0F to 100F - int alpha = IM_MIN(IM_MAX(py_helper_lookup_int(kw_args, + int alpha = IM_MIN(IM_MAX(py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256); - mp_map_elem_t *kw_scale = mp_map_lookup(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_scale), MP_MAP_LOOKUP); - if (kw_scale != NULL) { + mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_scale)); + if (scale_obj) { mp_obj_t *arg_scale; - mp_obj_get_array_fixed_n(kw_scale->value, 2, &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]); } @@ -449,14 +449,14 @@ mp_obj_t py_fir_draw_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) max = IM_MAX(max, temp); } - int alpha = IM_MIN(IM_MAX(py_helper_lookup_int(kw_args, + int alpha = IM_MIN(IM_MAX(py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), 128), 0), 256); - mp_map_elem_t *kw_scale = mp_map_lookup(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_scale), MP_MAP_LOOKUP); - if (kw_scale != NULL) { + mp_obj_t scale_obj = py_helper_keyword_object(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_scale)); + if (scale_obj) { mp_obj_t *arg_scale; - mp_obj_get_array_fixed_n(kw_scale->value, 2, &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]); } diff --git a/src/omv/py/py_gif.c b/src/omv/py/py_gif.c index e42aa3f93..61ee5d021 100644 --- a/src/omv/py/py_gif.c +++ b/src/omv/py/py_gif.c @@ -28,10 +28,10 @@ typedef struct py_gif_obj { static mp_obj_t py_gif_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { py_gif_obj_t *gif = m_new_obj(py_gif_obj_t); - gif->width = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); - gif->height = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); - gif->color = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MAIN_FB()->bpp>=2); - gif->loop = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true); + gif->width = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); + gif->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); + gif->color = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MAIN_FB()->bpp>=2); + gif->loop = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true); gif->base.type = &py_gif_type; file_write_open(&gif->fp, mp_obj_str_get_str(args[0])); @@ -78,7 +78,7 @@ static mp_obj_t py_gif_add_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw PY_ASSERT_FALSE_MSG((arg_gif->width != arg_img->w) || (arg_gif->height != arg_img->h), "Unexpected image geometry!"); - int delay = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_delay), 10); + int delay = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_delay), 10); gif_add_frame(&arg_gif->fp, arg_img, delay); return mp_const_none; diff --git a/src/omv/py/py_helper.c b/src/omv/py/py_helper.c index 69b774558..ecf421624 100644 --- a/src/omv/py/py_helper.c +++ b/src/omv/py/py_helper.c @@ -1,136 +1,229 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman * This work is licensed under the MIT license, see the file LICENSE for details. - * - * MicroPython helper functions. - * */ + #include "py_helper.h" -int py_helper_lookup_int(mp_map_t *kw_args, mp_obj_t kw, int default_val) +extern void *py_image_cobj(mp_obj_t img_obj); + +image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE(arg_img), "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(IMAGE_IS_MUTABLE_BAYER(arg_img), "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(arg_img->bpp == IMAGE_BPP_GRAYSCALE, "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_arg_to_image_color(const mp_obj_t arg) +{ + image_t *arg_img = py_image_cobj(arg); + PY_ASSERT_TRUE_MSG(arg_img->bpp == IMAGE_BPP_RGB565, "Image format is not supported!"); + return arg_img; +} + +image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, image_t *default_val) { mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); - if (kw_arg != NULL) { - default_val = mp_obj_get_int(kw_arg->value); + if (kw_arg) { + default_val = py_helper_arg_to_image_mutable(kw_arg->value); + } else if (n_args > arg_index) { + default_val = py_helper_arg_to_image_mutable(args[arg_index]); } + return default_val; } -float py_helper_lookup_float(mp_map_t *kw_args, mp_obj_t kw, float default_val) +image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args) +{ + return py_helper_keyword_to_image_mutable(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL); +} + +void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r) { mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); - if (kw_arg != NULL) { - default_val = mp_obj_get_float(kw_arg->value); - } - return default_val; -} - -void py_helper_lookup_int_array(mp_map_t *kw_args, mp_obj_t kw, int *x, int size) -{ - mp_map_elem_t *kw_array = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); - - if (kw_array != NULL) { - mp_obj_t *arg_array; - mp_obj_get_array_fixed_n(kw_array->value, size, &arg_array); - for (int i=0; ivalue, size, &arg_array); - for (int i=0; ivalue)) { - default_color = mp_obj_get_int(kw_color->value); - } else { - mp_obj_t *arg_color; - mp_obj_get_array_fixed_n(kw_color->value, 3, &arg_color); - default_color = IM_RGB565(IM_R825(mp_obj_get_int(arg_color[0])), - IM_G826(mp_obj_get_int(arg_color[1])), - IM_B825(mp_obj_get_int(arg_color[2]))); - } - } - return default_color; -} - -void py_helper_lookup_offset(mp_map_t *kw_args, image_t *img, point_t *p) -{ - mp_map_elem_t *kw_offset = mp_map_lookup(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_offset), MP_MAP_LOOKUP); - - if (kw_offset == NULL) { - p->x = 0; - p->y = 0; - } else { - mp_obj_t *arg_offset; - mp_obj_get_array_fixed_n(kw_offset->value, 2, &arg_offset); - p->x = mp_obj_get_int(arg_offset[0]); - p->y = mp_obj_get_int(arg_offset[1]); - } -} - -void py_helper_lookup_rectangle(mp_map_t *kw_args, image_t *img, rectangle_t *r) -{ - py_helper_lookup_rectangle_2(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_roi), img, r); -} - -void py_helper_lookup_rectangle_2(mp_map_t *kw_args, mp_obj_t kw, image_t *img, rectangle_t *r) -{ - mp_map_elem_t *kw_rectangle = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); - - if (kw_rectangle == NULL) { - r->x = 0; - r->y = 0; - r->w = img->w; - r->h = img->h; - } else { + if (kw_arg) { mp_obj_t *arg_rectangle; - mp_obj_get_array_fixed_n(kw_rectangle->value, 4, &arg_rectangle); + mp_obj_get_array_fixed_n(kw_arg->value, 4, &arg_rectangle); r->x = mp_obj_get_int(arg_rectangle[0]); r->y = mp_obj_get_int(arg_rectangle[1]); r->w = mp_obj_get_int(arg_rectangle[2]); r->h = mp_obj_get_int(arg_rectangle[3]); - - if ((r->w <= 0) || (r->h <= 0)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError, "Invalid ROI dimensions!")); - } - - rectangle_t tmp; - tmp.x = 0; - tmp.y = 0; - tmp.w = img->w; - tmp.h = img->h; - - if (!rectangle_overlap(r, &tmp)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError, "ROI does not overlap the image!")); - } - - rectangle_intersected(r, &tmp); + } else if (n_args > arg_index) { + mp_obj_t *arg_rectangle; + mp_obj_get_array_fixed_n(args[arg_index], 4, &arg_rectangle); + r->x = mp_obj_get_int(arg_rectangle[0]); + r->y = mp_obj_get_int(arg_rectangle[1]); + r->w = mp_obj_get_int(arg_rectangle[2]); + r->h = mp_obj_get_int(arg_rectangle[3]); + } else { + r->x = 0; + r->y = 0; + r->w = img->w; + r->h = img->h; } - if ((r->w <= 0) || (r->h <= 0)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError, "Invalid ROI dimensions!")); + PY_ASSERT_TRUE_MSG((r->w >= 1) && (r->h >= 1), "Invalid ROI dimensions!"); + rectangle_t temp; + temp.x = 0; + temp.y = 0; + temp.w = img->w; + temp.h = img->h; + + PY_ASSERT_TRUE_MSG(rectangle_overlap(r, &temp), "ROI does not overlap on the image!"); + rectangle_intersected(r, &temp); +} + +void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, rectangle_t *r) +{ + py_helper_keyword_rectangle(img, n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_roi), r); +} + +int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + default_val = mp_obj_get_int(kw_arg->value); + } else if (n_args > arg_index) { + default_val = mp_obj_get_int(args[arg_index]); } + + return default_val; +} + +float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + default_val = mp_obj_get_float(kw_arg->value); + } else if (n_args > arg_index) { + default_val = mp_obj_get_float(args[arg_index]); + } + + return default_val; +} + +void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int *x, int size) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]); + } else if (n_args > arg_index) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]); + } +} + +void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float *x, int size) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); + + if (kw_arg) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]); + } else if (n_args > arg_index) { + mp_obj_t *arg_array; + mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array); + for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]); + } +} + +uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items) +{ + if (MP_OBJ_IS_TYPE(args[arg_index], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[arg_index], &mp_type_list)) { + mp_obj_get_array_fixed_n(args[arg_index], len, (mp_obj_t **) items); + return arg_index + 1; + } else { + PY_ASSERT_TRUE_MSG((n_args - arg_index) >= len, "Not enough positional arguments!"); + *items = args + arg_index; + return arg_index + len; + } +} + +int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, int default_val) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP); + + if (kw_arg) { + if (mp_obj_is_integer(kw_arg->value)) { + default_val = mp_obj_get_int(kw_arg->value); + } else { + mp_obj_t *arg_color; + mp_obj_get_array_fixed_n(kw_arg->value, 3, &arg_color); + default_val = COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(mp_obj_get_int(arg_color[0])), + COLOR_G8_TO_G6(mp_obj_get_int(arg_color[1])), + COLOR_B8_TO_B5(mp_obj_get_int(arg_color[2]))); + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + default_val = COLOR_RGB565_TO_BINARY(default_val); + break; + } + case IMAGE_BPP_GRAYSCALE: { + default_val = COLOR_RGB565_TO_GRAYSCALE(default_val); + break; + } + default: { + break; + } + } + } + } else if (n_args > arg_index) { + if (mp_obj_is_integer(args[arg_index])) { + default_val = mp_obj_get_int(args[arg_index]); + } else { + mp_obj_t *arg_color; + mp_obj_get_array_fixed_n(args[arg_index], 3, &arg_color); + default_val = COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(mp_obj_get_int(arg_color[0])), + COLOR_G8_TO_G6(mp_obj_get_int(arg_color[1])), + COLOR_B8_TO_B5(mp_obj_get_int(arg_color[2]))); + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + default_val = COLOR_RGB565_TO_BINARY(default_val); + break; + } + case IMAGE_BPP_GRAYSCALE: { + default_val = COLOR_RGB565_TO_GRAYSCALE(default_val); + break; + } + default: { + break; + } + } + } + } + + return default_val; } void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds) @@ -139,7 +232,6 @@ void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds) mp_obj_t *arg_thresholds; mp_obj_get_array(arg, &arg_thresholds_len, &arg_thresholds); if (!arg_thresholds_len) return; - for(mp_uint_t i = 0; i < arg_thresholds_len; i++) { mp_uint_t arg_threshold_len; mp_obj_t *arg_threshold; @@ -147,9 +239,11 @@ void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds) if (arg_threshold_len) { color_thresholds_list_lnk_data_t lnk_data; lnk_data.LMin = (arg_threshold_len > 0) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[0]), - IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN); + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : + IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN); lnk_data.LMax = (arg_threshold_len > 1) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[1]), - IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX); + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) : + IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX); lnk_data.AMin = (arg_threshold_len > 2) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[2]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MIN; lnk_data.AMax = (arg_threshold_len > 3) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[3]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MAX; lnk_data.BMin = (arg_threshold_len > 4) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[4]), COLOR_B_MAX), COLOR_B_MIN) : COLOR_B_MIN; @@ -167,11 +261,39 @@ void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds) } } -void py_helper_keyword_thresholds(mp_map_t *kw_args, mp_obj_t kw, list_t *thresholds) +void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, list_t *thresholds) +{ + mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thresholds), MP_MAP_LOOKUP); + + if (kw_arg) { + py_helper_arg_to_thresholds(kw_arg->value, thresholds); + } else if (n_args > arg_index) { + py_helper_arg_to_thresholds(args[arg_index], thresholds); + } +} + +int py_helper_arg_to_ksize(const mp_obj_t arg) +{ + int ksize = mp_obj_get_int(arg); + PY_ASSERT_TRUE_MSG(ksize >= 0, "KernelSize must be >= 0!"); + return ksize; +} + +int py_helper_ksize_to_n(int ksize) +{ + return ((ksize * 2) + 1) * ((ksize * 2) + 1); +} + +mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args, uint arg_index, mp_map_t *kw_args, mp_obj_t kw) { mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP); - if (kw_arg != NULL) { - py_helper_arg_to_thresholds(kw_arg->value, thresholds); + if (kw_arg) { + return kw_arg->value; + } else if (n_args > arg_index) { + return args[arg_index]; + } else { + return NULL; } } diff --git a/src/omv/py/py_helper.h b/src/omv/py/py_helper.h index 1cf7e57d1..0963c032b 100644 --- a/src/omv/py/py_helper.h +++ b/src/omv/py/py_helper.h @@ -1,23 +1,39 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman * This work is licensed under the MIT license, see the file LICENSE for details. - * - * MicroPython helper functions. - * */ + #ifndef __PY_HELPER_H__ #define __PY_HELPER_H__ -#include +#include "py_assert.h" #include "imlib.h" -int py_helper_lookup_int(mp_map_t *kw_args, mp_obj_t kw, int default_val); -float py_helper_lookup_float(mp_map_t *kw_args, mp_obj_t kw, float default_val); -void py_helper_lookup_int_array(mp_map_t *kw_args, mp_obj_t kw, int *x, int size); -void py_helper_lookup_float_array(mp_map_t *kw_args, mp_obj_t kw, float *x, int size); -int py_helper_lookup_color(mp_map_t *kw_args, int default_color); -void py_helper_lookup_offset(mp_map_t *kw_args, image_t *img, point_t *p); -void py_helper_lookup_rectangle(mp_map_t *kw_args, image_t *img, rectangle_t *r); -void py_helper_lookup_rectangle_2(mp_map_t *kw_args, mp_obj_t kw, image_t *img, rectangle_t *r); +image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg); +image_t *py_helper_arg_to_image_mutable_bayer(const mp_obj_t arg); +image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg); +image_t *py_helper_arg_to_image_color(const mp_obj_t arg); +image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, image_t *default_val); +image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args); +void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r); +void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, rectangle_t *r); +int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int default_val); +float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float default_val); +void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, int *x, int size); +void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, mp_obj_t kw, float *x, int size); +uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items); +int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, int default_val); void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds); -void py_helper_keyword_thresholds(mp_map_t *kw_args, mp_obj_t kw, list_t *thresholds); +void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index, + mp_map_t *kw_args, list_t *thresholds); +int py_helper_arg_to_ksize(const mp_obj_t arg); +int py_helper_ksize_to_n(int ksize); +mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args, uint arg_index, mp_map_t *kw_args, mp_obj_t kw); #endif // __PY_HELPER__ diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index b5c426d6f..ca7c72d43 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -6,6 +6,7 @@ * Image Python module. * */ + #include #include #include "imlib.h" @@ -43,7 +44,7 @@ void *py_cascade_cobj(mp_obj_t cascade) static void py_cascade_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_cascade_obj_t *self = self_in; - mp_printf(print, "width:%d height:%d n_stages:%d n_features:%d n_rectangles:%d\n", + mp_printf(print, "{\"width\":%d, \"height\":%d, \"n_stages\":%d, \"n_features\":%d, \"n_rectangles\":%d}", self->_cobj.window.w, self->_cobj.window.h, self->_cobj.n_stages, self->_cobj.n_features, self->_cobj.n_rectangles); } @@ -66,7 +67,7 @@ typedef struct _py_kp_obj_t { static void py_kp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_kp_obj_t *self = self_in; - mp_printf(print, "size:%d threshold:%d normalized:%d", array_length(self->kpts), self->threshold, self->normalized); + mp_printf(print, "{\"size\":%d, \"threshold\":%d, \"normalized\":%d}", array_length(self->kpts), self->threshold, self->normalized); } mp_obj_t py_kp_unary_op(mp_uint_t op, mp_obj_t self_in) { @@ -114,7 +115,7 @@ typedef struct _py_lbp_obj_t { static void py_lbp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - mp_printf(print, ""); + mp_printf(print, "{}"); } static const mp_obj_type_t py_lbp_type = { @@ -137,7 +138,7 @@ typedef struct _py_kptmatch_obj_t { static void py_kptmatch_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_kptmatch_obj_t *self = self_in; - mp_printf(print, " {cx:%d, cy:%d, x:%d, y:%d, w:%d, h:%d, count:%d, theta:%d}", + mp_printf(print, "{\"cx\":%d, \"cy\":%d, \"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"count\":%d, \"theta\":%d}", mp_obj_get_int(self->cx), mp_obj_get_int(self->cy), mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), mp_obj_get_int(self->h), mp_obj_get_int(self->count), mp_obj_get_int(self->theta)); } @@ -207,7 +208,7 @@ STATIC const mp_rom_map_elem_t py_kptmatch_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&py_kptmatch_count_obj) }, { MP_ROM_QSTR(MP_QSTR_theta), MP_ROM_PTR(&py_kptmatch_theta_obj) }, { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&py_kptmatch_match_obj) }, - { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_kptmatch_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&py_kptmatch_rect_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_kptmatch_locals_dict, py_kptmatch_locals_dict_table); @@ -217,7 +218,7 @@ static const mp_obj_type_t py_kptmatch_type = { .name = MP_QSTR_kptmatch, .print = py_kptmatch_print, .subscr = py_kptmatch_subscr, - .locals_dict = (mp_obj_t) &py_kptmatch_locals_dict, + .locals_dict = (mp_obj_t) &py_kptmatch_locals_dict }; // Image ////////////////////////////////////////////////////////////////////// @@ -238,19 +239,19 @@ static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k py_image_obj_t *self = self_in; switch(self->_cobj.bpp) { case IMAGE_BPP_BINARY: { - mp_printf(print, "{w:%d, h:%d, type=\"binary\", size:%d}", + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"binary\", \"size\":%d}", self->_cobj.w, self->_cobj.h, ((self->_cobj.w + UINT32_T_MASK) >> UINT32_T_SHIFT) * self->_cobj.h); break; } case IMAGE_BPP_GRAYSCALE: { - mp_printf(print, "{w:%d, h:%d, type=\"grayscale\", size:%d}", + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"grayscale\", \"size\":%d}", self->_cobj.w, self->_cobj.h, (self->_cobj.w * self->_cobj.h) * sizeof(uint8_t)); break; } case IMAGE_BPP_RGB565: { - mp_printf(print, "{w:%d, h:%d, type=\"rgb565\", size:%d}", + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"rgb565\", \"size\":%d}", self->_cobj.w, self->_cobj.h, (self->_cobj.w * self->_cobj.h) * sizeof(uint16_t)); break; @@ -259,7 +260,7 @@ static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k if((self->_cobj.data[0] == 0xFE) && (self->_cobj.data[self->_cobj.bpp-1] == 0xFE)) { // for ide print->print_strn(print->data, (const char *) self->_cobj.data, self->_cobj.bpp); } else { // not for ide - mp_printf(print, "{w:%d, h:%d, type=\"jpeg\", size:%d}", + mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\"=\"jpeg\", \"size\":%d}", self->_cobj.w, self->_cobj.h, self->_cobj.bpp); } @@ -471,32 +472,10 @@ static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, py_image_obj_t *self = self_in; if (flags == MP_BUFFER_READ) { bufinfo->buf = self->_cobj.data; - switch (self->_cobj.bpp) { - case IMAGE_BPP_BINARY: { - bufinfo->len = ((self->_cobj.w + UINT32_T_MASK) >> UINT32_T_SHIFT) * self->_cobj.h; - break; - } - case IMAGE_BPP_GRAYSCALE: { - bufinfo->len = (self->_cobj.w * self->_cobj.h) * sizeof(uint8_t); - break; - } - case IMAGE_BPP_RGB565: { - bufinfo->len = (self->_cobj.w * self->_cobj.h) * sizeof(uint16_t); - break; - } - case IMAGE_BPP_BAYER: { - bufinfo->len = self->_cobj.w * self->_cobj.h; - break; - } - default: { // JPEG - bufinfo->len = self->_cobj.bpp; - break; - } - } + bufinfo->len = image_size(&self->_cobj); bufinfo->typecode = 'b'; return 0; - } else { - // can't write to an image + } else { // Can't write to an image! bufinfo->buf = NULL; bufinfo->len = 0; bufinfo->typecode = -1; @@ -504,88 +483,269 @@ static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, } } -static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +//////////////// +// Basic Methods +//////////////// + +static mp_obj_t py_image_width(mp_obj_t img_obj) { - image_t *arg_img = py_image_cobj(args[0]); + return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->w); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width); - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); +static mp_obj_t py_image_height(mp_obj_t img_obj) +{ + return mp_obj_new_int(((image_t *) py_image_cobj(img_obj))->h); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height); - mp_obj_t img_obj = py_image(0, 0, 0, 0); - image_t *img = py_image_cobj(img_obj); +static mp_obj_t py_image_format(mp_obj_t img_obj) +{ + switch (((image_t *) py_image_cobj(img_obj))->bpp) { + case IMAGE_BPP_BINARY: return mp_const_none; // TODO: FIXME! + case IMAGE_BPP_GRAYSCALE: return mp_obj_new_int(PIXFORMAT_GRAYSCALE); + case IMAGE_BPP_RGB565: return mp_obj_new_int(PIXFORMAT_RGB565); + case IMAGE_BPP_BAYER: return mp_obj_new_int(PIXFORMAT_BAYER); + default: return mp_obj_new_int(PIXFORMAT_JPEG); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format); + +static mp_obj_t py_image_size(mp_obj_t img_obj) +{ + return mp_obj_new_int(image_size((image_t *) py_image_cobj(img_obj))); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size); + +STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + bool arg_rgbtuple = + py_helper_keyword_int(n_args, args, offset, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgbtuple), arg_img->bpp == IMAGE_BPP_RGB565); + + if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { + return mp_const_none; + } + + switch (arg_img->bpp) { + case IMAGE_BPP_BINARY: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_BINARY_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_BINARY_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_BINARY_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_GRAYSCALE: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_RGB565: { + if (arg_rgbtuple) { + int pixel = IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y); + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_R5_TO_R8(COLOR_RGB565_TO_R5(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_G6_TO_G8(COLOR_RGB565_TO_G6(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_B5_TO_B8(COLOR_RGB565_TO_B5(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y)); + } + } + case IMAGE_BPP_BAYER: + if (arg_rgbtuple) { + int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y); // Correct! + mp_obj_t pixel_tuple[3]; + pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel))); + return mp_obj_new_tuple(3, pixel_tuple); + } else { + return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y)); // Correct! + } + default: return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_pixel_obj, 2, py_image_get_pixel); + +STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. + + if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { + return args[0]; + } + + switch (arg_img->bpp) { + case IMAGE_BPP_BINARY: { + IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_GRAYSCALE: { + IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_RGB565: { + IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c); + return args[0]; + } + case IMAGE_BPP_BAYER: { + IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c); // Correct! + return args[0]; + } + default: return args[0]; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_set_pixel_obj, 2, py_image_set_pixel); + +static mp_obj_t py_image_mean_pool(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); + + int x_div = mp_obj_get_int(x_div_obj); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(y_div_obj); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = arg_img->pixels; + + imlib_mean_pool(arg_img, &out_img, x_div, y_div); + arg_img->w = out_img.w; + arg_img->h = out_img.h; + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->w = out_img.w; + MAIN_FB()->h = out_img.h; + } - imlib_copy_image(img, arg_img, &roi); return img_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pool_obj, py_image_mean_pool); -static mp_obj_t py_image_copy_to_fb(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +static mp_obj_t py_image_mean_pooled(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) { - point_t arg_offs; - image_t *arg_img = py_image_cobj(args[0]); - py_helper_lookup_offset(kw_args, arg_img, &arg_offs); + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); - MAIN_FB()->w = arg_img->w; - MAIN_FB()->h = arg_img->h; - MAIN_FB()->bpp = arg_img->bpp; + int x_div = mp_obj_get_int(x_div_obj); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(y_div_obj); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - int yoffs = arg_offs.y; - int xoffs = arg_offs.x * arg_img->bpp; - int stride = arg_img->w * arg_img->bpp; + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = xalloc(image_size(&out_img)); - for (int y=yoffs; yh; y++) { - for (int x=xoffs; xpixels[y*stride+x] = arg_img->pixels[y*stride+x]; - } + imlib_mean_pool(arg_img, &out_img, x_div, y_div); + return py_image_from_struct(&out_img); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pooled_obj, py_image_mean_pooled); + +static mp_obj_t py_image_midpoint_pool(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + + int x_div = mp_obj_get_int(args[1]); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(args[2]); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); + + int bias = IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256, 256), 0); + + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = arg_img->pixels; + + imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, bias); + arg_img->w = out_img.w; + arg_img->h = out_img.h; + + if (MAIN_FB()->pixels == arg_img->data) { + MAIN_FB()->w = out_img.w; + MAIN_FB()->h = out_img.h; } - return mp_const_true; -} -static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pool_obj, 3, py_image_midpoint_pool); + +static mp_obj_t py_image_midpoint_pooled(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - const char *path = mp_obj_str_get_str(args[1]); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + int x_div = mp_obj_get_int(args[1]); + PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); + int y_div = mp_obj_get_int(args[2]); + PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); + PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); - arg_q = IM_MIN(IM_MAX(arg_q, 1), 100); + int bias = IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 3, kw_args, + MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256, 256), 0); - imlib_save_image(arg_img, path, &roi, arg_q); - return mp_const_none; + image_t out_img; + out_img.w = arg_img->w / x_div; + out_img.h = arg_img->h / y_div; + out_img.bpp = arg_img->bpp; + out_img.pixels = xalloc(image_size(&out_img)); + + imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, bias); + return py_image_from_struct(&out_img); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midpoint_pooled); static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); - PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100"); + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); uint32_t size; fb_alloc_mark(); uint8_t *buffer = fb_alloc_all(&size); image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); - - switch(arg_img->bpp) { - case IMAGE_BPP_BINARY: { - PY_ASSERT_TRUE_MSG(out.bpp <= (((arg_img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * arg_img->h), "Can't compress in place!"); - break; - } - case IMAGE_BPP_GRAYSCALE: { - PY_ASSERT_TRUE_MSG(out.bpp <= ((arg_img->w * arg_img->h) * sizeof(uint8_t)), "Can't compress in place!"); - break; - } - case IMAGE_BPP_RGB565: { - PY_ASSERT_TRUE_MSG(out.bpp <= ((arg_img->w * arg_img->h) * sizeof(uint16_t)), "Can't compress in place!"); - break; - } - default: { - break; - } - } - + PY_ASSERT_TRUE_MSG(out.bpp <= image_size(arg_img), "Can't compress in place!"); memcpy(arg_img->data, out.data, out.bpp); arg_img->bpp = out.bpp; fb_free(); @@ -597,44 +757,20 @@ static mp_obj_t py_image_compress(uint n_args, const mp_obj_t *args, mp_map_t *k return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_obj, 1, py_image_compress); static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); - PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100"); + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); uint32_t size; fb_alloc_mark(); uint8_t *buffer = fb_alloc_all(&size); image_t out = { .w=arg_img->w, .h=arg_img->h, .bpp=size, .data=buffer }; PY_ASSERT_FALSE_MSG(jpeg_compress(arg_img, &out, arg_q, false), "Out of Memory!"); - - switch(arg_img->bpp) { - case IMAGE_BPP_BINARY: { - PY_ASSERT_TRUE_MSG(((((out.bpp * 8) + 5) / 6) + 2) <= - (((arg_img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * arg_img->h), - "Can't compress in place!"); - break; - } - case IMAGE_BPP_GRAYSCALE: { - PY_ASSERT_TRUE_MSG(((((out.bpp * 8) + 5) / 6) + 2) <= - ((arg_img->w * arg_img->h) * sizeof(uint8_t)), - "Can't compress in place!"); - break; - } - case IMAGE_BPP_RGB565: { - PY_ASSERT_TRUE_MSG(((((out.bpp * 8) + 5) / 6) + 2) <= - ((arg_img->w * arg_img->h) * sizeof(uint16_t)), - "Can't compress in place!"); - break; - } - default: { - break; - } - } - + PY_ASSERT_TRUE_MSG(out.bpp <= image_size(arg_img), "Can't compress in place!"); uint8_t *ptr = arg_img->data; *ptr++ = 0xFE; @@ -679,13 +815,13 @@ static mp_obj_t py_image_compress_for_ide(uint n_args, const mp_obj_t *args, mp_ return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_for_ide_obj, 1, py_image_compress_for_ide); static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); - PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100"); + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); uint32_t size; fb_alloc_mark(); @@ -700,13 +836,13 @@ static mp_obj_t py_image_compressed(uint n_args, const mp_obj_t *args, mp_map_t return py_image_from_struct(&out); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_obj, 1, py_image_compressed); static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); - PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), " 1 <= quality <= 100"); + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + int arg_q = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); uint32_t size; fb_alloc_mark(); @@ -754,681 +890,767 @@ static mp_obj_t py_image_compressed_for_ide(uint n_args, const mp_obj_t *args, m return py_image_from_struct(&out); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide); -static mp_obj_t py_image_width(mp_obj_t img_obj) +static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - return mp_obj_new_int(arg_img->w); -} + image_t *arg_img = py_image_cobj(args[0]); -static mp_obj_t py_image_height(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - return mp_obj_new_int(arg_img->h); -} + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); -static mp_obj_t py_image_format(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - if (IM_IS_GS(arg_img)) { - return mp_obj_new_int(PIXFORMAT_GRAYSCALE); - } else if (IM_IS_RGB565(arg_img)) { - return mp_obj_new_int(PIXFORMAT_RGB565); + bool copy_to_fb = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false); + if (copy_to_fb) fb_update_jpeg_buffer(); + + image_t image; + image.w = roi.w; + image.h = roi.h; + image.bpp = arg_img->bpp; + image.data = NULL; + + if (copy_to_fb) { + PY_ASSERT_TRUE_MSG(arg_img->data != MAIN_FB()->pixels, "Cannot copy to fb!"); + PY_ASSERT_TRUE_MSG((image_size(&image) <= OMV_RAW_BUF_SIZE), "FB Overflow!"); + MAIN_FB()->w = image.w; + MAIN_FB()->h = image.h; + MAIN_FB()->bpp = image.bpp; + image.data = MAIN_FB()->pixels; } else { - return mp_obj_new_int(PIXFORMAT_JPEG); + image.data = xalloc(image_size(&image)); } -} -static mp_obj_t py_image_size(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - if (IM_IS_JPEG(arg_img)) { - return mp_obj_new_int(arg_img->bpp); - } else { - return mp_obj_new_int(arg_img->w * arg_img->h * arg_img->bpp); + switch(arg_img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, y); + uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, y); + uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + case IMAGE_BPP_BAYER: { // Correct! + for (int y = roi.y, yy = roi.y + roi.h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, y); + uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y - roi.y); + for (int x = roi.x, xx = roi.x + roi.w; x < xx; x++) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x - roi.x, IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)); + } + } + break; + } + default: { // JPEG + memcpy(image.data, arg_img->data, image_size(&image)); + break; + } } -} -static mp_obj_t py_image_clear(mp_obj_t img_obj) + return py_image_from_struct(&image); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy); + +static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - memset(arg_img->pixels, 0, arg_img->w * arg_img->h * arg_img->bpp); + image_t *arg_img = py_image_cobj(args[0]); + const char *path = mp_obj_str_get_str(args[1]); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); + + int arg_q = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + PY_ASSERT_TRUE_MSG((1 <= arg_q) && (arg_q <= 100), "Error: 1 <= quality <= 100!"); + + fb_alloc_mark(); + imlib_save_image(arg_img, path, &roi, arg_q); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save); + +////////////////// +// Drawing Methods +////////////////// + +STATIC mp_obj_t py_image_clear(mp_obj_t img_obj) +{ + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(img_obj); + memset(arg_img->data, 0, image_size(arg_img)); return img_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_clear_obj, py_image_clear); -static mp_obj_t py_image_get_pixel(mp_obj_t img_obj, mp_obj_t x_obj, mp_obj_t y_obj) +STATIC mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(!IM_IS_JPEG(arg_img), "Image format is not supported."); - - int arg_x = mp_obj_get_int(x_obj); - int arg_y = mp_obj_get_int(y_obj); - if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { - return mp_const_none; - } - - switch (arg_img->bpp) { - case 1: // GS - case 3: // BAYER - return mp_obj_new_int(IM_GET_GS_PIXEL(arg_img, arg_x, arg_y)); - case 2: { // RGB565 - uint16_t pixel = IM_GET_RGB565_PIXEL(arg_img, arg_x, arg_y); - mp_obj_t pixel_tuple[3]; - pixel_tuple[0] = mp_obj_new_int(IM_R528(IM_R565(pixel))); - pixel_tuple[1] = mp_obj_new_int(IM_G628(IM_G565(pixel))); - pixel_tuple[2] = mp_obj_new_int(IM_B528(IM_B565(pixel))); - return mp_obj_new_tuple(3, pixel_tuple); - } - default: - return mp_const_none; - } -} - -static mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_x = mp_obj_get_int(args[1]); - int arg_y = mp_obj_get_int(args[2]); - if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) { - return mp_const_none; - } - - if (IM_IS_GS(arg_img)) { - IM_SET_GS_PIXEL(arg_img, arg_x, arg_y, mp_obj_get_int(args[3])); - } else { - mp_obj_t *arg_color; - mp_obj_get_array_fixed_n(args[3], 3, &arg_color); - int red = IM_R825(mp_obj_get_int(arg_color[0])); - int green = IM_G826(mp_obj_get_int(arg_color[1])); - int blue = IM_B825(mp_obj_get_int(arg_color[2])); - IM_SET_RGB565_PIXEL(arg_img, arg_x, arg_y, IM_RGB565(red, green, blue)); - } - return mp_const_none; -} - -static mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_obj_t *arg_vec; - mp_obj_get_array_fixed_n(args[1], 4, &arg_vec); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec); int arg_x0 = mp_obj_get_int(arg_vec[0]); int arg_y0 = mp_obj_get_int(arg_vec[1]); int arg_x1 = mp_obj_get_int(arg_vec[2]); int arg_y1 = mp_obj_get_int(arg_vec[3]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c); - return mp_const_none; + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line); -static mp_obj_t py_image_draw_rectangle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_draw_rectangle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_obj_t *arg_vec; - mp_obj_get_array_fixed_n(args[1], 4, &arg_vec); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 4, &arg_vec); int arg_rx = mp_obj_get_int(arg_vec[0]); int arg_ry = mp_obj_get_int(arg_vec[1]); int arg_rw = mp_obj_get_int(arg_vec[2]); int arg_rh = mp_obj_get_int(arg_vec[3]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c); - return mp_const_none; + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle); -static mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); - int arg_cx = mp_obj_get_int(args[1]); - int arg_cy = mp_obj_get_int(args[2]); - int arg_r = mp_obj_get_int(args[3]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec); + int arg_cx = mp_obj_get_int(arg_vec[0]); + int arg_cy = mp_obj_get_int(arg_vec[1]); + int arg_cr = mp_obj_get_int(arg_vec[2]); - imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_r, arg_c); - return mp_const_none; + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. + + imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c); + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_circle); -static mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); - int arg_x_off = mp_obj_get_int(args[1]); - int arg_y_off = mp_obj_get_int(args[2]); - const char *arg_str = mp_obj_str_get_str(args[3]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 3, &arg_vec); + int arg_x_off = mp_obj_get_int(arg_vec[0]); + int arg_y_off = mp_obj_get_int(arg_vec[1]); + const char *arg_str = mp_obj_str_get_str(arg_vec[2]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, arg_c); - return mp_const_none; + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string); -static mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); - int arg_x = mp_obj_get_int(args[1]); - int arg_y = mp_obj_get_int(args[2]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white - int arg_s = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 5); + const mp_obj_t *arg_vec; + uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec); + int arg_x = mp_obj_get_int(arg_vec[0]); + int arg_y = mp_obj_get_int(arg_vec[1]); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White. + int arg_s = + py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 5); imlib_draw_line(arg_img, arg_x-arg_s, arg_y , arg_x+arg_s, arg_y , arg_c); imlib_draw_line(arg_img, arg_x , arg_y-arg_s, arg_x , arg_y+arg_s, arg_c); - return mp_const_none; + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 2, py_image_draw_cross); -static mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - py_kp_obj_t *kpts_obj = ((py_kp_obj_t*)args[1]); - int arg_c = py_helper_lookup_color(kw_args, -1); // white - int arg_s = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), arg_img->w*10/100); - + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + py_kp_obj_t *kpts_obj = (py_kp_obj_t*) args[1]; PY_ASSERT_TYPE(kpts_obj, &py_kp_type); + + int arg_c = + py_helper_keyword_color(arg_img, n_args, args, 2, kw_args, -1); // White. + int arg_s = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), arg_img->w * 0.1f); + for (int i=0; ikpts); i++) { kp_t *kp = array_at(kpts_obj->kpts, i); int cx = kp->x; int cy = kp->y; int size = arg_s/2; - int si = (int) (sin_table[kp->angle] * size); - int co = (int) (cos_table[kp->angle] * size); + int si = sin_table[kp->angle] * size; + int co = cos_table[kp->angle] * size; imlib_draw_line(arg_img, cx, cy, cx+co, cy+si, arg_c); imlib_draw_circle(arg_img, cx, cy, size, arg_c); } - return mp_const_none; -} - -static mp_obj_t py_image_binary(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - list_t thresholds; - list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); - py_helper_arg_to_thresholds(args[1], &thresholds); - - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), - (n_args > 2) ? mp_obj_get_int(args[2]) : false); - - bool zero = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zero), - (n_args > 3) ? mp_obj_get_int(args[3]) : false); - - imlib_binary(arg_img, &thresholds, invert, zero); - list_free(&thresholds); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints); -static mp_obj_t py_image_invert(mp_obj_t img_obj) +///////////////// +// Binary Methods +///////////////// + +STATIC mp_obj_t py_image_binary(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + list_t arg_thresholds; + list_init(&arg_thresholds, sizeof(color_thresholds_list_lnk_data_t)); + py_helper_arg_to_thresholds(args[1], &arg_thresholds); - imlib_invert(arg_img); - return img_obj; -} - -static mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_and(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_nand(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_or(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_nor(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_xor(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - if (MP_OBJ_IS_STR(args[1])) { - fb_alloc_mark(); - imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); - } else { - image_t *arg_other = py_image_cobj(args[1]); - fb_alloc_mark(); - imlib_b_xnor(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_free_till_mark(); - } - - return args[0]; -} - -static mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - - int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), - (n_args > 2) ? mp_obj_get_int(args[2]) : ((((arg_ksize*2)+1)*((arg_ksize*2)+1))-1)); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + bool arg_zero = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zero), false); fb_alloc_mark(); - imlib_erode(arg_img, arg_ksize, threshold, (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_binary(py_helper_arg_to_image_mutable(args[0]), &arg_thresholds, arg_invert, arg_zero); fb_alloc_free_till_mark(); - + list_free(&arg_thresholds); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_binary_obj, 2, py_image_binary); -static mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_invert(mp_obj_t img_obj) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - - int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), - (n_args > 2) ? mp_obj_get_int(args[2]) : 0); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - fb_alloc_mark(); - imlib_dilate(arg_img, arg_ksize, threshold, (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_invert(py_helper_arg_to_image_mutable(img_obj)); fb_alloc_free_till_mark(); - - return args[0]; -} - -static mp_obj_t py_image_negate(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - imlib_negate(arg_img); return img_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert); -static mp_obj_t py_image_replace(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - bool hmirror = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), - (n_args > 2) ? mp_obj_get_int(args[2]) : false); - bool vflip = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), - (n_args > 3) ? mp_obj_get_int(args[3]) : false); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_replace(arg_img, mp_obj_str_get_str(args[1]), NULL, hmirror, vflip); - fb_alloc_mark(); + imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_replace(arg_img, NULL, arg_other, hmirror, vflip); + imlib_b_and(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and); -static mp_obj_t py_image_add(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_add(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); + imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_add(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); + imlib_b_nand(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand); -static mp_obj_t py_image_sub(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - bool reverse = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), - (n_args > 2) ? mp_obj_get_int(args[2]) : false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_sub(arg_img, mp_obj_str_get_str(args[1]), NULL, reverse, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); - fb_alloc_mark(); + imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_sub(arg_img, NULL, arg_other, reverse, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_b_or(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or); -static mp_obj_t py_image_mul(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), - (n_args > 2) ? mp_obj_get_int(args[2]) : false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_mul(arg_img, mp_obj_str_get_str(args[1]), NULL, invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); - fb_alloc_mark(); + imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_mul(arg_img, NULL, arg_other, invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_b_nor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor); -static mp_obj_t py_image_div(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), - (n_args > 2) ? mp_obj_get_int(args[2]) : false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_div(arg_img, mp_obj_str_get_str(args[1]), NULL, invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); - fb_alloc_mark(); + imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_div(arg_img, NULL, arg_other, invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_b_xor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor); -static mp_obj_t py_image_min(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_min(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); + imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_min(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); + imlib_b_xnor(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor); -static mp_obj_t py_image_max(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), + py_helper_ksize_to_n(arg_ksize) - 1); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + fb_alloc_mark(); + imlib_erode(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_erode_obj, 2, py_image_erode); + +STATIC mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), + 0); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + fb_alloc_mark(); + imlib_dilate(py_helper_arg_to_image_mutable(args[0]), arg_ksize, arg_threshold, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate); + +/////////////// +// Math Methods +/////////////// + +STATIC mp_obj_t py_image_negate(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_negate(py_helper_arg_to_image_mutable(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate); + +STATIC mp_obj_t py_image_replace(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_hmirror = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false); + bool arg_vflip = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_max(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); + imlib_replace(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_hmirror, arg_vflip); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_max(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); + imlib_replace(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_hmirror, arg_vflip); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_replace_obj, 2, py_image_replace); -static mp_obj_t py_image_difference(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_add(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_difference(arg_img, mp_obj_str_get_str(args[1]), NULL, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); - fb_alloc_mark(); + imlib_add(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_difference(arg_img, NULL, arg_other, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 2) ? py_image_cobj(args[2]) : NULL)); + imlib_add(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 2, py_image_add); -static mp_obj_t py_image_blend(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_sub(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int alpha = IM_MIN(IM_MAX(py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), - (n_args > 2) ? mp_obj_get_int(args[2]) : 128), 0), 256); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); if (MP_OBJ_IS_STR(args[1])) { fb_alloc_mark(); - imlib_blend(arg_img, mp_obj_str_get_str(args[1]), NULL, alpha / 256.0, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); - fb_alloc_mark(); + imlib_sub(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_reverse, arg_msk); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_blend(arg_img, NULL, arg_other, alpha / 256.0, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : - ((n_args > 3) ? py_image_cobj(args[3]) : NULL)); + imlib_sub(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_reverse, arg_msk); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 2, py_image_sub); -static mp_obj_t py_image_morph(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_mul(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_mul(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_mul(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_invert, arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mul_obj, 2, py_image_mul); + +STATIC mp_obj_t py_image_div(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_invert = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_div(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_div(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_invert, arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_div_obj, 2, py_image_div); + +STATIC mp_obj_t py_image_min(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_min(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_min(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 2, py_image_min); + +STATIC mp_obj_t py_image_max(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_max(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_max(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 2, py_image_max); + +STATIC mp_obj_t py_image_difference(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 2, kw_args); + + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_difference(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_difference(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 2, py_image_difference); + +STATIC mp_obj_t py_image_blend(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_alpha = + IM_MAX(IM_MIN(py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha), + 128), 256), 0) / 256.0f; + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 3, kw_args); + + if (MP_OBJ_IS_STR(args[1])) { + fb_alloc_mark(); + imlib_blend(arg_img, mp_obj_str_get_str(args[1]), NULL, arg_alpha, arg_msk); + fb_alloc_free_till_mark(); + } else { + fb_alloc_mark(); + imlib_blend(arg_img, NULL, py_helper_arg_to_image_mutable(args[1]), arg_alpha, arg_msk); + fb_alloc_free_till_mark(); + } + + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend); + +//////////////////// +// Filtering Methods +//////////////////// + +static mp_obj_t py_image_histeq(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_histeq(py_helper_arg_to_image_mutable(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq); + +STATIC mp_obj_t py_image_mean(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args); + + fb_alloc_mark(); + imlib_mean_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mean_obj, 2, py_image_mean); + +STATIC mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + PY_ASSERT_TRUE_MSG(arg_ksize <= 2, "KernelSize must be <= 2!"); + int n = py_helper_ksize_to_n(arg_ksize); + int arg_percentile = + IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_percentile), + 0.5) * n, n - 1), 0); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args); + + fb_alloc_mark(); + imlib_median_filter(arg_img, arg_ksize, arg_percentile, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 2, py_image_median); + +STATIC mp_obj_t py_image_mode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 5, kw_args); + + fb_alloc_mark(); + imlib_mode_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mode_obj, 2, py_image_mode); + +STATIC mp_obj_t py_image_midpoint(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int arg_bias = + IM_MAX(IM_MIN(py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), + 0.5) * 256, 256), 0); + bool arg_threshold = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); + int arg_offset = + py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); + bool arg_invert = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 6, kw_args); + + fb_alloc_mark(); + imlib_midpoint_filter(arg_img, arg_ksize, arg_bias, arg_threshold, arg_offset, arg_invert, arg_msk); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint); + +STATIC mp_obj_t py_image_morph(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + py_helper_arg_to_ksize(args[1]); + int n = py_helper_ksize_to_n(arg_ksize); - int array_size = ((arg_ksize*2)+1)*((arg_ksize*2)+1); mp_obj_t *krn; - mp_obj_get_array_fixed_n(args[2], array_size, &krn); - - int8_t arg_krn[array_size]; + mp_obj_get_array_fixed_n(args[2], n, &krn); + int8_t arg_krn[n]; int arg_m = 0; - for (int i = 0; i < array_size; i++) { + + for (int i = 0; i < n; i++) { int value = mp_obj_get_int(krn[i]); PY_ASSERT_FALSE_MSG((value < -128) || (127 < value), - "Kernel Values must be between [-128:127] inclusive"); + "Kernel Values must be between [-128:127] inclusive!"); arg_krn[i] = value; arg_m += arg_krn[i]; } @@ -1437,112 +1659,49 @@ static mp_obj_t py_image_morph(uint n_args, const mp_obj_t *args, mp_map_t *kw_a arg_m = 1; } - imlib_morph(arg_img, arg_ksize, arg_krn, - py_helper_lookup_float(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0 / ((float) arg_m)), - py_helper_lookup_int(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_add), 0)); + float arg_mul = + py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mul), 1.0f / arg_m); + float arg_add = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_add), 0.0f); + + fb_alloc_mark(); + imlib_morph(arg_img, arg_ksize, arg_krn, arg_mul, arg_add); + fb_alloc_free_till_mark(); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph); -static mp_obj_t py_image_midpoint(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_gaussian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - - int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); - int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); - int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - int bias = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256; - imlib_midpoint_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(bias, 0), 256), arg_threshold, arg_offset, arg_invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : NULL); - return args[0]; -} - -static mp_obj_t py_image_mean(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - - int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); - int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); - int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - imlib_mean_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : NULL); - return args[0]; -} - -static mp_obj_t py_image_mode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - - int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); - int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); - int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - imlib_mode_filter(arg_img, arg_ksize, arg_threshold, arg_offset, arg_invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : NULL); - return args[0]; -} - -static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0"); - PY_ASSERT_TRUE_MSG(arg_ksize <= 2, "Kernel Size must be <= 2"); - - int arg_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), false); - int arg_offset = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_offset), 0); - int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP); - - int n = ((arg_ksize*2)+1)*((arg_ksize*2)+1); - int percentile = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_percentile), 0.5) * n; - imlib_median_filter(arg_img, arg_ksize, IM_MIN(IM_MAX(percentile, 0), n-1), arg_threshold, arg_offset, arg_invert, - (kw_arg != NULL) ? py_image_cobj(kw_arg->value) : NULL); - return args[0]; -} - -static mp_obj_t py_image_gaussian(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int arg_ksize = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG((arg_ksize == 3 || arg_ksize == 5), "Kernel Size must be 3 or 5"); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + int arg_ksize = + mp_obj_get_int(args[1]); + PY_ASSERT_TRUE_MSG((arg_ksize == 3 || arg_ksize == 5), "KernelSize must be 3 or 5!"); if (arg_ksize == 3) { + fb_alloc_mark(); imlib_morph(arg_img, 1, kernel_gauss_3, 1.0f/16.0f, 0.0f); + fb_alloc_free_till_mark(); } else if (arg_ksize == 5) { + fb_alloc_mark(); imlib_morph(arg_img, 2, kernel_gauss_5, 1.0f/256.0f, 0.0f); + fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 2, py_image_gaussian); + +///////////////////////// +// Shadow Removal Methods +///////////////////////// #ifdef IMLIB_ENABLE_REMOVE_SHADOWS -static mp_obj_t py_image_remove_shadows(uint n_args, const mp_obj_t *args) +STATIC mp_obj_t py_image_remove_shadows(uint n_args, const mp_obj_t *args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_RGB565(arg_img), "Image format is not supported."); + image_t *arg_img = + py_helper_arg_to_image_color(args[0]); if (n_args < 2) { fb_alloc_mark(); @@ -1553,139 +1712,132 @@ static mp_obj_t py_image_remove_shadows(uint n_args, const mp_obj_t *args) imlib_remove_shadows(arg_img, mp_obj_str_get_str(args[1]), NULL); fb_alloc_mark(); } else { - image_t *arg_other = py_image_cobj(args[1]); fb_alloc_mark(); - imlib_remove_shadows(arg_img, NULL, arg_other); + imlib_remove_shadows(arg_img, NULL, py_helper_arg_to_image_color(args[1])); fb_alloc_free_till_mark(); } return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_remove_shadows_obj, 1, 2, py_image_remove_shadows); #endif // IMLIB_ENABLE_REMOVE_SHADOWS +#ifdef IMLIB_ENABLE_CHROMINVAR +STATIC mp_obj_t py_image_chrominvar(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_chrominvar(py_helper_arg_to_image_color(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_chrominvar_obj, py_image_chrominvar); +#endif // IMLIB_ENABLE_CHROMINVAR + +#ifdef IMLIB_ENABLE_ILLUMINVAR +STATIC mp_obj_t py_image_illuminvar(mp_obj_t img_obj) +{ + fb_alloc_mark(); + imlib_illuminvar(py_helper_arg_to_image_color(img_obj)); + fb_alloc_free_till_mark(); + return img_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_illuminvar_obj, py_image_illuminvar); +#endif // IMLIB_ENABLE_ILLUMINVAR + +//////////////////// +// Geometric Methods +//////////////////// + #ifdef IMLIB_ENABLE_LINPOLAR static mp_obj_t py_image_linpolar(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_RGB565(arg_img), "Image format is not supported."); - bool reverse = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), - (n_args > 1) ? mp_obj_get_int(args[1]) : false); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); fb_alloc_mark(); - imlib_logpolar(arg_img, true, reverse); + imlib_logpolar(arg_img, true, arg_reverse); fb_alloc_free_till_mark(); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_linpolar_obj, 1, py_image_linpolar); #endif // IMLIB_ENABLE_LINPOLAR #ifdef IMLIB_ENABLE_LOGPOLAR static mp_obj_t py_image_logpolar(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_RGB565(arg_img), "Image format is not supported."); - bool reverse = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), - (n_args > 1) ? mp_obj_get_int(args[1]) : false); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + bool arg_reverse = + py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_reverse), false); fb_alloc_mark(); - imlib_logpolar(arg_img, false, reverse); + imlib_logpolar(arg_img, false, arg_reverse); fb_alloc_free_till_mark(); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_logpolar_obj, 1, py_image_logpolar); #endif // IMLIB_ENABLE_LOGPOLAR -#ifdef IMLIB_ENABLE_CHROMINVAR -static mp_obj_t py_image_chrominvar(mp_obj_t img_obj) +STATIC mp_obj_t py_image_lens_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_RGB565(arg_img), "Image format is not supported."); - - imlib_chrominvar(arg_img); - return img_obj; -} -#endif // IMLIB_ENABLE_CHROMINVAR - -#ifdef IMLIB_ENABLE_ILLUMINVAR -static mp_obj_t py_image_illuminvar(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_RGB565(arg_img), "Image format is not supported."); - - imlib_illuminvar(arg_img); - return img_obj; -} -#endif // IMLIB_ENABLE_ILLUMINVAR - -static mp_obj_t py_image_histeq(mp_obj_t img_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - imlib_histeq(arg_img); - return img_obj; -} - -static mp_obj_t py_image_lens_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - float strength = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_strength), - (n_args > 1) ? mp_obj_get_float(args[1]) : 1.8); - PY_ASSERT_TRUE_MSG(strength > 0.0, "strength must be > 0"); - - float zoom = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), - (n_args > 2) ? mp_obj_get_float(args[2]) : 1.0); - PY_ASSERT_TRUE_MSG(zoom > 0.0, "zoom must be > 0"); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_strength = + py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_strength), 1.8); + PY_ASSERT_TRUE_MSG(arg_strength > 0.0, "Strength must be > 0!"); + float arg_zoom = + py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0); + PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!"); fb_alloc_mark(); - imlib_lens_corr(arg_img, strength, zoom); + imlib_lens_corr(arg_img, arg_strength, arg_zoom); fb_alloc_free_till_mark(); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_lens_corr_obj, 1, py_image_lens_corr); #ifdef IMLIB_ENABLE_ROTATION_CORR -static mp_obj_t py_image_rotation_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +STATIC mp_obj_t py_image_rotation_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - float x_rotation = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_rotation), - (n_args > 1) ? mp_obj_get_float(args[1]) : 0.0); - x_rotation = x_rotation * M_PI / 180; - - float y_rotation = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_rotation), - (n_args > 2) ? mp_obj_get_float(args[2]) : 0.0); - y_rotation = y_rotation * M_PI / 180; - - float z_rotation = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_z_rotation), - (n_args > 3) ? mp_obj_get_float(args[3]) : 0.0); - z_rotation = z_rotation * M_PI / 180; - - float x_translation = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_translation), - (n_args > 4) ? mp_obj_get_float(args[4]) : 0.0); - - float y_translation = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_translation), - (n_args > 5) ? mp_obj_get_float(args[5]) : 0.0); - - float zoom = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), - (n_args > 6) ? mp_obj_get_float(args[6]) : 1.0); - PY_ASSERT_TRUE_MSG(zoom > 0.0, "zoom must be > 0"); + image_t *arg_img = + py_helper_arg_to_image_mutable(args[0]); + float arg_x_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_rotation), 0.0)); + float arg_y_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_rotation), 0.0)); + float arg_z_rotation = + IM_DEG2RAD(py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_z_rotation), 0.0)); + float arg_x_translation = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_translation), 0.0); + float arg_y_translation = + py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_translation), 0.0); + float arg_zoom = + py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zoom), 1.0); + PY_ASSERT_TRUE_MSG(arg_zoom > 0.0, "Zoom must be > 0!"); fb_alloc_mark(); - imlib_rotation_corr(arg_img, x_rotation, y_rotation, z_rotation, x_translation, y_translation, zoom); + imlib_rotation_corr(arg_img, + arg_x_rotation, arg_y_rotation, arg_z_rotation, + arg_x_translation, arg_y_translation, + arg_zoom); fb_alloc_free_till_mark(); return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_rotation_corr_obj, 1, py_image_rotation_corr); #endif // IMLIB_ENABLE_ROTATION_CORR -static mp_obj_t py_image_mask_ellipse(mp_obj_t img_obj) +STATIC mp_obj_t py_image_mask_ellipse(mp_obj_t img_obj) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - imlib_mask_ellipse(arg_img); + imlib_mask_ellipse(py_helper_arg_to_image_grayscale(img_obj)); return img_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_mask_ellipse_obj, py_image_mask_ellipse); + +////////////// +// Get Methods +////////////// #ifdef IMLIB_ENABLE_GET_SIMILARITY // Similarity Object // @@ -1699,7 +1851,7 @@ static void py_similarity_print(const mp_print_t *print, mp_obj_t self_in, mp_pr { py_similarity_obj_t *self = self_in; mp_printf(print, - "{mean:%f, stdev:%f, min:%f, max:%f}", + "{\"mean\":%f, \"stdev\":%f, \"min\":%f, \"max\":%f}", (double) mp_obj_get_float(self->avg), (double) mp_obj_get_float(self->std), (double) mp_obj_get_float(self->min), @@ -1753,24 +1905,21 @@ static const mp_obj_type_t py_similarity_type = { .name = MP_QSTR_similarity, .print = py_similarity_print, .subscr = py_similarity_subscr, - .locals_dict = (mp_obj_t) &py_similarity_locals_dict, + .locals_dict = (mp_obj_t) &py_similarity_locals_dict }; static mp_obj_t py_image_get_similarity(mp_obj_t img_obj, mp_obj_t other_obj) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - + image_t *arg_img = py_helper_arg_to_image_mutable(img_obj); float avg, std, min, max; if (MP_OBJ_IS_STR(other_obj)) { fb_alloc_mark(); imlib_get_similarity(arg_img, mp_obj_str_get_str(other_obj), NULL, &avg, &std, &min, &max); - fb_alloc_mark(); + fb_alloc_free_till_mark(); } else { - image_t *arg_other = py_image_cobj(other_obj); fb_alloc_mark(); - imlib_get_similarity(arg_img, NULL, arg_other, &avg, &std, &min, &max); + imlib_get_similarity(arg_img, NULL, py_helper_arg_to_image_mutable(other_obj), &avg, &std, &min, &max); fb_alloc_free_till_mark(); } @@ -1782,6 +1931,7 @@ static mp_obj_t py_image_get_similarity(mp_obj_t img_obj, mp_obj_t other_obj) o->max = mp_obj_new_float(max); return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_get_similarity_obj, py_image_get_similarity); #endif // IMLIB_ENABLE_GET_SIMILARITY // Statistics Object // @@ -1789,7 +1939,9 @@ static mp_obj_t py_image_get_similarity(mp_obj_t img_obj, mp_obj_t other_obj) typedef struct py_statistics_obj { mp_obj_base_t base; image_bpp_t bpp; - mp_obj_t LMean, LMedian, LMode, LSTDev, LMin, LMax, LLQ, LUQ, AMean, AMedian, AMode, ASTDev, AMin, AMax, ALQ, AUQ, BMean, BMedian, BMode, BSTDev, BMin, BMax, BLQ, BUQ; + mp_obj_t LMean, LMedian, LMode, LSTDev, LMin, LMax, LLQ, LUQ, + AMean, AMedian, AMode, ASTDev, AMin, AMax, ALQ, AUQ, + BMean, BMedian, BMode, BSTDev, BMin, BMax, BLQ, BUQ; } py_statistics_obj_t; static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) @@ -1797,7 +1949,7 @@ static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_pr py_statistics_obj_t *self = self_in; switch(self->bpp) { case IMAGE_BPP_BINARY: { - mp_printf(print, "{mean:%d, median:%d, mode:%d, stdev:%d, min:%d, max:%d, lq:%d, uq:%d}", + mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}", mp_obj_get_int(self->LMean), mp_obj_get_int(self->LMedian), mp_obj_get_int(self->LMode), @@ -1809,7 +1961,7 @@ static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_pr break; } case IMAGE_BPP_GRAYSCALE: { - mp_printf(print, "{mean:%d, median:%d, mode:%d, stdev:%d, min:%d, max:%d, lq:%d, uq:%d}", + mp_printf(print, "{\"mean\":%d, \"median\":%d, \"mode\":%d, \"stdev\":%d, \"min\":%d, \"max\":%d, \"lq\":%d, \"uq\":%d}", mp_obj_get_int(self->LMean), mp_obj_get_int(self->LMedian), mp_obj_get_int(self->LMode), @@ -1821,9 +1973,9 @@ static void py_statistics_print(const mp_print_t *print, mp_obj_t self_in, mp_pr break; } case IMAGE_BPP_RGB565: { - mp_printf(print, "{l_mean:%d, l_median:%d, l_mode:%d, l_stdev:%d, l_min:%d, l_max:%d, l_lq:%d, l_uq:%d," - " a_mean:%d, a_median:%d, a_mode:%d, a_stdev:%d, a_min:%d, a_max:%d, a_lq:%d, a_uq:%d," - " b_mean:%d, b_median:%d, b_mode:%d, b_stdev:%d, b_min:%d, b_max:%d, b_lq:%d, b_uq:%d}", + mp_printf(print, "{\"l_mean\":%d, \"l_median\":%d, \"l_mode\":%d, \"l_stdev\":%d, \"l_min\":%d, \"l_max\":%d, \"l_lq\":%d, \"l_uq\":%d," + " \"a_mean\":%d, \"a_median\":%d, \"a_mode\":%d, \"a_stdev\":%d, \"a_min\":%d, \"a_max\":%d, \"a_lq\":%d, \"a_uq\":%d," + " \"b_mean\":%d, \"b_median\":%d, \"b_mode\":%d, \"b_stdev\":%d, \"b_min\":%d, \"b_max\":%d, \"b_lq\":%d, \"b_uq\":%d}", mp_obj_get_int(self->LMean), mp_obj_get_int(self->LMedian), mp_obj_get_int(self->LMode), @@ -2008,7 +2160,7 @@ static const mp_obj_type_t py_statistics_type = { .name = MP_QSTR_statistics, .print = py_statistics_print, .subscr = py_statistics_subscr, - .locals_dict = (mp_obj_t) &py_statistics_locals_dict, + .locals_dict = (mp_obj_t) &py_statistics_locals_dict }; // Percentile Object // @@ -2024,15 +2176,20 @@ static void py_percentile_print(const mp_print_t *print, mp_obj_t self_in, mp_pr py_percentile_obj_t *self = self_in; switch(self->bpp) { case IMAGE_BPP_BINARY: { - mp_printf(print, "{value:%d}", mp_obj_get_int(self->LValue)); + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); break; } case IMAGE_BPP_GRAYSCALE: { - mp_printf(print, "{value:%d}", mp_obj_get_int(self->LValue)); + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); break; } case IMAGE_BPP_RGB565: { - mp_printf(print, "{l_value:%d, a_value:%d, b_value:%d}", mp_obj_get_int(self->LValue), mp_obj_get_int(self->AValue), mp_obj_get_int(self->BValue)); + mp_printf(print, "{\"l_value:%d\", \"a_value\":%d, \"b_value\":%d}", + mp_obj_get_int(self->LValue), + mp_obj_get_int(self->AValue), + mp_obj_get_int(self->BValue)); break; } default: { @@ -2088,7 +2245,7 @@ static const mp_obj_type_t py_percentile_type = { .name = MP_QSTR_percentile, .print = py_percentile_print, .subscr = py_percentile_subscr, - .locals_dict = (mp_obj_t) &py_percentile_locals_dict, + .locals_dict = (mp_obj_t) &py_percentile_locals_dict }; // Threshold Object // @@ -2104,15 +2261,20 @@ static void py_threshold_print(const mp_print_t *print, mp_obj_t self_in, mp_pri py_threshold_obj_t *self = self_in; switch(self->bpp) { case IMAGE_BPP_BINARY: { - mp_printf(print, "{value:%d}", mp_obj_get_int(self->LValue)); + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); break; } case IMAGE_BPP_GRAYSCALE: { - mp_printf(print, "{value:%d}", mp_obj_get_int(self->LValue)); + mp_printf(print, "{\"value\":%d}", + mp_obj_get_int(self->LValue)); break; } case IMAGE_BPP_RGB565: { - mp_printf(print, "{l_value:%d, a_value:%d, b_value:%d}", mp_obj_get_int(self->LValue), mp_obj_get_int(self->AValue), mp_obj_get_int(self->BValue)); + mp_printf(print, "{\"l_value\":%d, \"a_value\":%d, \"b_value\":%d}", + mp_obj_get_int(self->LValue), + mp_obj_get_int(self->AValue), + mp_obj_get_int(self->BValue)); break; } default: { @@ -2168,7 +2330,7 @@ static const mp_obj_type_t py_threshold_type = { .name = MP_QSTR_threshold, .print = py_threshold_print, .subscr = py_threshold_subscr, - .locals_dict = (mp_obj_t) &py_threshold_locals_dict, + .locals_dict = (mp_obj_t) &py_threshold_locals_dict }; // Histogram Object // @@ -2184,23 +2346,23 @@ static void py_histogram_print(const mp_print_t *print, mp_obj_t self_in, mp_pri py_histogram_obj_t *self = self_in; switch(self->bpp) { case IMAGE_BPP_BINARY: { - mp_printf(print, "{bins:"); + mp_printf(print, "{\"bins\":"); mp_obj_print_helper(print, self->LBins, kind); mp_printf(print, "}"); break; } case IMAGE_BPP_GRAYSCALE: { - mp_printf(print, "{bins:"); + mp_printf(print, "{\"bins\":"); mp_obj_print_helper(print, self->LBins, kind); mp_printf(print, "}"); break; } case IMAGE_BPP_RGB565: { - mp_printf(print, "{l_bins:"); + mp_printf(print, "{\"l_bins\":"); mp_obj_print_helper(print, self->LBins, kind); - mp_printf(print, ", a_bins:"); + mp_printf(print, ", \"a_bins\":"); mp_obj_print_helper(print, self->ABins, kind); - mp_printf(print, ", b_bins:"); + mp_printf(print, ", \"b_bins\":"); mp_obj_print_helper(print, self->BBins, kind); mp_printf(print, "}"); break; @@ -2410,28 +2572,28 @@ static const mp_obj_type_t py_histogram_type = { .name = MP_QSTR_histogram, .print = py_histogram_print, .subscr = py_histogram_subscr, - .locals_dict = (mp_obj_t) &py_histogram_locals_dict, + .locals_dict = (mp_obj_t) &py_histogram_locals_dict }; static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); - py_helper_keyword_thresholds(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thresholds), &thresholds); - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + py_helper_keyword_thresholds(n_args, args, 1, kw_args, &thresholds); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); histogram_t hist; switch(arg_img->bpp) { case IMAGE_BPP_BINARY: { - int bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); hist.ABinCount = 0; hist.BBinCount = 0; @@ -2444,9 +2606,10 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map break; } case IMAGE_BPP_GRAYSCALE: { - int bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); hist.ABinCount = 0; hist.BBinCount = 0; @@ -2459,17 +2622,20 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map break; } case IMAGE_BPP_RGB565: { - int l_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_L_MAX-COLOR_L_MIN+1)); + int l_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_L_MAX-COLOR_L_MIN+1)); PY_ASSERT_TRUE_MSG(l_bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); - int a_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_A_MAX-COLOR_A_MIN+1)); + int a_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_A_MAX-COLOR_A_MIN+1)); PY_ASSERT_TRUE_MSG(a_bins >= 2, "bins must be >= 2"); - hist.ABinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); + hist.ABinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); PY_ASSERT_TRUE_MSG(hist.ABinCount >= 2, "a_bins must be >= 2"); - int b_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_B_MAX-COLOR_B_MIN+1)); + int b_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_B_MAX-COLOR_B_MIN+1)); PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2"); - hist.BBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); + hist.BBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2"); fb_alloc_mark(); hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); @@ -2511,26 +2677,27 @@ static mp_obj_t py_image_get_histogram(uint n_args, const mp_obj_t *args, mp_map return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_histogram_obj, 1, py_image_get_histogram); static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); - py_helper_keyword_thresholds(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thresholds), &thresholds); - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + py_helper_keyword_thresholds(n_args, args, 1, kw_args, &thresholds); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); + + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); histogram_t hist; switch(arg_img->bpp) { case IMAGE_BPP_BINARY: { - int bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_BINARY_MAX-COLOR_BINARY_MIN+1)); PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); hist.ABinCount = 0; hist.BBinCount = 0; @@ -2543,9 +2710,10 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma break; } case IMAGE_BPP_GRAYSCALE: { - int bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); + int bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_GRAYSCALE_MAX-COLOR_GRAYSCALE_MIN+1)); PY_ASSERT_TRUE_MSG(bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); hist.ABinCount = 0; hist.BBinCount = 0; @@ -2558,17 +2726,20 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma break; } case IMAGE_BPP_RGB565: { - int l_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_L_MAX-COLOR_L_MIN+1)); + int l_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_L_MAX-COLOR_L_MIN+1)); PY_ASSERT_TRUE_MSG(l_bins >= 2, "bins must be >= 2"); - hist.LBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); + hist.LBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_l_bins), l_bins); PY_ASSERT_TRUE_MSG(hist.LBinCount >= 2, "l_bins must be >= 2"); - int a_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_A_MAX-COLOR_A_MIN+1)); + int a_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_A_MAX-COLOR_A_MIN+1)); PY_ASSERT_TRUE_MSG(a_bins >= 2, "bins must be >= 2"); - hist.ABinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); + hist.ABinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_a_bins), a_bins); PY_ASSERT_TRUE_MSG(hist.ABinCount >= 2, "a_bins must be >= 2"); - int b_bins = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), (COLOR_B_MAX-COLOR_B_MIN+1)); + int b_bins = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bins), + (COLOR_B_MAX-COLOR_B_MIN+1)); PY_ASSERT_TRUE_MSG(b_bins >= 2, "bins must be >= 2"); - hist.BBinCount = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); + hist.BBinCount = py_helper_keyword_int(n_args, args, n_args, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_b_bins), b_bins); PY_ASSERT_TRUE_MSG(hist.BBinCount >= 2, "b_bins must be >= 2"); fb_alloc_mark(); hist.LBins = fb_alloc(hist.LBinCount * sizeof(float)); @@ -2621,6 +2792,7 @@ static mp_obj_t py_image_get_statistics(uint n_args, const mp_obj_t *args, mp_ma return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_statistics_obj, 1, py_image_get_statistics); // Line Object // #define py_line_obj_size 8 @@ -2633,7 +2805,7 @@ static void py_line_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki { py_line_obj_t *self = self_in; mp_printf(print, - "{x1:%d, y1:%d, x2:%d, y2:%d, length:%d, magnitude:%d, theta:%d, rho:%d}", + "{\"x1\":%d, \"y1\":%d, \"x2\":%d, \"y2\":%d, \"length\":%d, \"magnitude\":%d, \"theta\":%d, \"rho\":%d}", mp_obj_get_int(self->x1), mp_obj_get_int(self->y1), mp_obj_get_int(self->x2), @@ -2707,7 +2879,7 @@ STATIC const mp_rom_map_elem_t py_line_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&py_line_length_obj) }, { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_line_magnitude_obj) }, { MP_ROM_QSTR(MP_QSTR_theta), MP_ROM_PTR(&py_line_theta_obj) }, - { MP_ROM_QSTR(MP_QSTR_rho), MP_ROM_PTR(&py_line_rho_obj) }, + { MP_ROM_QSTR(MP_QSTR_rho), MP_ROM_PTR(&py_line_rho_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_line_locals_dict, py_line_locals_dict_table); @@ -2717,30 +2889,29 @@ static const mp_obj_type_t py_line_type = { .name = MP_QSTR_line, .print = py_line_print, .subscr = py_line_subscr, - .locals_dict = (mp_obj_t) &py_line_locals_dict, + .locals_dict = (mp_obj_t) &py_line_locals_dict }; static mp_obj_t py_image_get_regression(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); py_helper_arg_to_thresholds(args[1], &thresholds); if (!list_size(&thresholds)) return mp_const_none; + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - unsigned int x_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); - unsigned int y_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - unsigned int area_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); - unsigned int pixels_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); - bool robust = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_robust), false); + unsigned int area_threshold = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); + unsigned int pixels_threshold = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); + bool robust = py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_robust), false); find_lines_list_lnk_data_t out; fb_alloc_mark(); @@ -2766,6 +2937,11 @@ static mp_obj_t py_image_get_regression(uint n_args, const mp_obj_t *args, mp_ma return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_regression_obj, 2, py_image_get_regression); + +/////////////// +// Find Methods +/////////////// // Blob Object // #define py_blob_obj_size 10 @@ -2778,7 +2954,7 @@ static void py_blob_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki { py_blob_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, pixels:%d, cx:%d, cy:%d, rotation:%f, code:%d, count:%d}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"pixels\":%d, \"cx\":%d, \"cy\":%d, \"rotation\":%f, \"code\":%d, \"count\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -2843,7 +3019,7 @@ mp_obj_t py_blob_area(mp_obj_t self_in) { } mp_obj_t py_blob_density(mp_obj_t self_in) { int area = mp_obj_get_int(((py_blob_obj_t *) self_in)->w) * mp_obj_get_int(((py_blob_obj_t *) self_in)->h); - if (area) return mp_obj_new_float(mp_obj_get_int(((py_blob_obj_t *) self_in)->pixels) / (float) area); + if (area) return mp_obj_new_float(mp_obj_get_int(((py_blob_obj_t *) self_in)->pixels) / ((float) area)); return mp_obj_new_float(0.0f); } @@ -2884,7 +3060,7 @@ static const mp_obj_type_t py_blob_type = { .name = MP_QSTR_blob, .print = py_blob_print, .subscr = py_blob_subscr, - .locals_dict = (mp_obj_t) &py_blob_locals_dict, + .locals_dict = (mp_obj_t) &py_blob_locals_dict }; static bool py_image_find_blobs_threshold_cb(void *fun_obj, find_blobs_list_lnk_data_t *blob) @@ -2938,38 +3114,33 @@ static bool py_image_find_blobs_merge_cb(void *fun_obj, find_blobs_list_lnk_data static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); list_t thresholds; list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t)); py_helper_arg_to_thresholds(args[1], &thresholds); if (!list_size(&thresholds)) return mp_obj_new_list(0, NULL); + bool invert = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - unsigned int x_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); + + unsigned int x_stride = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); - unsigned int y_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); - bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), false); - unsigned int area_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); - unsigned int pixels_threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); - bool merge = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge), false); - int margin = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_margin), 0); - - mp_map_elem_t *threshold_cb_kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold_cb), MP_MAP_LOOKUP); - mp_obj_t threshold_cb_kw_val = (threshold_cb_kw_arg != NULL) ? threshold_cb_kw_arg->value : NULL; - - mp_map_elem_t *merge_cb_kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_cb), MP_MAP_LOOKUP); - mp_obj_t merge_cb_kw_val = (merge_cb_kw_arg != NULL) ? merge_cb_kw_arg->value : NULL; + unsigned int area_threshold = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_area_threshold), 10); + unsigned int pixels_threshold = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_pixels_threshold), 10); + bool merge = py_helper_keyword_int(n_args, args, 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge), false); + int margin = py_helper_keyword_int(n_args, args, 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_margin), 0); + mp_obj_t threshold_cb = py_helper_keyword_object(n_args, args, 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold_cb)); + mp_obj_t merge_cb = py_helper_keyword_object(n_args, args, 11, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_cb)); list_t out; fb_alloc_mark(); - imlib_find_blobs(&out, arg_img, &roi, x_stride, y_stride, &thresholds, invert, area_threshold, - pixels_threshold, merge, margin, py_image_find_blobs_threshold_cb, threshold_cb_kw_val, - py_image_find_blobs_merge_cb, merge_cb_kw_val); + imlib_find_blobs(&out, arg_img, &roi, x_stride, y_stride, &thresholds, invert, + area_threshold, pixels_threshold, merge, margin, + py_image_find_blobs_threshold_cb, threshold_cb, py_image_find_blobs_merge_cb, merge_cb); fb_alloc_free_till_mark(); list_free(&thresholds); @@ -2996,26 +3167,27 @@ static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_blobs_obj, 2, py_image_find_blobs); #ifdef IMLIB_ENABLE_FIND_LINES static mp_obj_t py_image_find_lines(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); - unsigned int x_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + unsigned int x_stride = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); - unsigned int y_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + uint32_t threshold = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000); + unsigned int theta_margin = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_theta_margin), 25); + unsigned int rho_margin = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rho_margin), 25); list_t out; fb_alloc_mark(); - imlib_find_lines(&out, arg_img, &roi, x_stride, y_stride, py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_theta_margin), 25), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rho_margin), 25)); + imlib_find_lines(&out, arg_img, &roi, x_stride, y_stride, threshold, theta_margin, rho_margin); fb_alloc_free_till_mark(); mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); @@ -3041,22 +3213,23 @@ static mp_obj_t py_image_find_lines(uint n_args, const mp_obj_t *args, mp_map_t return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lines_obj, 1, py_image_find_lines); #endif // IMLIB_ENABLE_FIND_LINES #ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS static mp_obj_t py_image_find_line_segments(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + unsigned int merge_distance = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_distance), 0); + unsigned int max_theta_diff = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_theta_diff), 15); list_t out; fb_alloc_mark(); - imlib_lsd_find_line_segments(&out, arg_img, &roi, - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_merge_distance), 0), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_theta_diff), 15)); + imlib_lsd_find_line_segments(&out, arg_img, &roi, merge_distance, max_theta_diff); fb_alloc_free_till_mark(); mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); @@ -3082,6 +3255,7 @@ static mp_obj_t py_image_find_line_segments(uint n_args, const mp_obj_t *args, m return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_line_segments_obj, 1, py_image_find_line_segments); #endif // IMLIB_ENABLE_FIND_LINE_SEGMENTS #ifdef IMLIB_ENABLE_FIND_CIRCLES @@ -3096,7 +3270,7 @@ static void py_circle_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ { py_circle_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, r:%d, magnitude:%d}", + "{\"x\":%d, \"y\":%d, \"r\":%d, \"magnitude\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->r), @@ -3149,7 +3323,7 @@ STATIC const mp_rom_map_elem_t py_circle_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&py_circle_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_circle_y_obj) }, { MP_ROM_QSTR(MP_QSTR_r), MP_ROM_PTR(&py_circle_r_obj) }, - { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_circle_magnitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_circle_magnitude_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_circle_locals_dict, py_circle_locals_dict_table); @@ -3159,28 +3333,28 @@ static const mp_obj_type_t py_circle_type = { .name = MP_QSTR_circle, .print = py_circle_print, .subscr = py_circle_subscr, - .locals_dict = (mp_obj_t) &py_circle_locals_dict, + .locals_dict = (mp_obj_t) &py_circle_locals_dict }; static mp_obj_t py_image_find_circles(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); - unsigned int x_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); + unsigned int x_stride = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_stride), 2); PY_ASSERT_TRUE_MSG(x_stride > 0, "x_stride must not be zero."); - unsigned int y_stride = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); + unsigned int y_stride = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_stride), 1); PY_ASSERT_TRUE_MSG(y_stride > 0, "y_stride must not be zero."); + uint32_t threshold = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 2000); + unsigned int x_margin = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_margin), 10); + unsigned int y_margin = py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_margin), 10); + unsigned int r_margin = py_helper_keyword_int(n_args, args, 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_margin), 10); list_t out; fb_alloc_mark(); - imlib_find_circles(&out, arg_img, &roi, x_stride, y_stride, py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 2000), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_x_margin), 10), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_margin), 10), - py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_r_margin), 10)); + imlib_find_circles(&out, arg_img, &roi, x_stride, y_stride, threshold, x_margin, y_margin, r_margin); fb_alloc_free_till_mark(); mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); @@ -3200,6 +3374,7 @@ static mp_obj_t py_image_find_circles(uint n_args, const mp_obj_t *args, mp_map_ return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_circles_obj, 1, py_image_find_circles); #endif // IMLIB_ENABLE_FIND_CIRCLES #ifdef IMLIB_ENABLE_FIND_RECTS @@ -3215,7 +3390,7 @@ static void py_rect_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki { py_rect_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, magnitude:%d}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"magnitude\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -3277,7 +3452,7 @@ STATIC const mp_rom_map_elem_t py_rect_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&py_rect_y_obj) }, { MP_ROM_QSTR(MP_QSTR_w), MP_ROM_PTR(&py_rect_w_obj) }, { MP_ROM_QSTR(MP_QSTR_h), MP_ROM_PTR(&py_rect_h_obj) }, - { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_rect_magnitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_magnitude), MP_ROM_PTR(&py_rect_magnitude_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_rect_locals_dict, py_rect_locals_dict_table); @@ -3287,20 +3462,21 @@ static const mp_obj_type_t py_rect_type = { .name = MP_QSTR_rect, .print = py_rect_print, .subscr = py_rect_subscr, - .locals_dict = (mp_obj_t) &py_rect_locals_dict, + .locals_dict = (mp_obj_t) &py_rect_locals_dict }; static mp_obj_t py_image_find_rects(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + uint32_t threshold = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000); list_t out; fb_alloc_mark(); - imlib_find_rects(&out, arg_img, &roi, py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 1000)); + imlib_find_rects(&out, arg_img, &roi, threshold); fb_alloc_free_till_mark(); mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); @@ -3326,6 +3502,7 @@ static mp_obj_t py_image_find_rects(uint n_args, const mp_obj_t *args, mp_map_t return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_rects_obj, 1, py_image_find_rects); #endif // IMLIB_ENABLE_FIND_RECTS #ifdef IMLIB_ENABLE_QRCODES @@ -3341,7 +3518,8 @@ static void py_qrcode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ { py_qrcode_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, payload:\"%s\", version:%d, ecc_level:%d, mask:%d, data_type:%d, eci:%d}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"version\":%d, \"ecc_level\":%d, \"mask\":%d, \"data_type\":%d, \"eci\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -3440,7 +3618,7 @@ STATIC const mp_rom_map_elem_t py_qrcode_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_is_numeric), MP_ROM_PTR(&py_qrcode_is_numeric_obj) }, { MP_ROM_QSTR(MP_QSTR_is_alphanumeric), MP_ROM_PTR(&py_qrcode_is_alphanumeric_obj) }, { MP_ROM_QSTR(MP_QSTR_is_binary), MP_ROM_PTR(&py_qrcode_is_binary_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_kanji), MP_ROM_PTR(&py_qrcode_is_kanji_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_kanji), MP_ROM_PTR(&py_qrcode_is_kanji_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_qrcode_locals_dict, py_qrcode_locals_dict_table); @@ -3450,16 +3628,15 @@ static const mp_obj_type_t py_qrcode_type = { .name = MP_QSTR_qrcode, .print = py_qrcode_print, .subscr = py_qrcode_subscr, - .locals_dict = (mp_obj_t) &py_qrcode_locals_dict, + .locals_dict = (mp_obj_t) &py_qrcode_locals_dict }; static mp_obj_t py_image_find_qrcodes(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); list_t out; fb_alloc_mark(); @@ -3495,6 +3672,7 @@ static mp_obj_t py_image_find_qrcodes(uint n_args, const mp_obj_t *args, mp_map_ return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_qrcodes_obj, 1, py_image_find_qrcodes); #endif // IMLIB_ENABLE_QRCODES #ifdef IMLIB_ENABLE_APRILTAGS @@ -3512,9 +3690,10 @@ static void py_apriltag_print(const mp_print_t *print, mp_obj_t self_in, mp_prin { py_apriltag_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, id:%d, family:%d, cx:%d, cy:%d, rotation:%f, decision_margin:%f, hamming:%d, goodness:%f," - " x_translation:%f, y_translation:%f, z_translation:%f," - " x_rotation:%f, y_rotation:%f, z_rotation:%f}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"id\":%d," + " \"family\":%d, \"cx\":%d, \"cy\":%d, \"rotation\":%f, \"decision_margin\":%f, \"hamming\":%d, \"goodness\":%f," + " \"x_translation\":%f, \"y_translation\":%f, \"z_translation\":%f," + " \"x_rotation\":%f, \"y_rotation\":%f, \"z_rotation\":%f}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -3641,7 +3820,7 @@ STATIC const mp_rom_map_elem_t py_apriltag_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_z_translation), MP_ROM_PTR(&py_apriltag_z_translation_obj) }, { MP_ROM_QSTR(MP_QSTR_x_rotation), MP_ROM_PTR(&py_apriltag_x_rotation_obj) }, { MP_ROM_QSTR(MP_QSTR_y_rotation), MP_ROM_PTR(&py_apriltag_y_rotation_obj) }, - { MP_ROM_QSTR(MP_QSTR_z_rotation), MP_ROM_PTR(&py_apriltag_z_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_z_rotation), MP_ROM_PTR(&py_apriltag_z_rotation_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_apriltag_locals_dict, py_apriltag_locals_dict_table); @@ -3651,26 +3830,25 @@ static const mp_obj_type_t py_apriltag_type = { .name = MP_QSTR_apriltag, .print = py_apriltag_print, .subscr = py_apriltag_subscr, - .locals_dict = (mp_obj_t) &py_apriltag_locals_dict, + .locals_dict = (mp_obj_t) &py_apriltag_locals_dict }; static mp_obj_t py_image_find_apriltags(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); - apriltag_families_t families = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_families), TAG36H11); + apriltag_families_t families = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_families), TAG36H11); // 2.8mm Focal Length w/ OV7725 sensor for reference. - float fx = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fx), (2.8 / 3.984) * arg_img->w); + float fx = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fx), (2.8 / 3.984) * arg_img->w); // 2.8mm Focal Length w/ OV7725 sensor for reference. - float fy = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fy), (2.8 / 2.952) * arg_img->h); + float fy = py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fy), (2.8 / 2.952) * arg_img->h); // Use the image versus the roi here since the image should be projected from the camera center. - float cx = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cx), arg_img->w * 0.5); + float cx = py_helper_keyword_float(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cx), arg_img->w * 0.5); // Use the image versus the roi here since the image should be projected from the camera center. - float cy = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cy), arg_img->h * 0.5); + float cy = py_helper_keyword_float(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_cy), arg_img->h * 0.5); list_t out; fb_alloc_mark(); @@ -3713,6 +3891,7 @@ static mp_obj_t py_image_find_apriltags(uint n_args, const mp_obj_t *args, mp_ma return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_apriltags_obj, 1, py_image_find_apriltags); #endif // IMLIB_ENABLE_APRILTAGS #ifdef IMLIB_ENABLE_DATAMATRICES @@ -3728,7 +3907,8 @@ static void py_datamatrix_print(const mp_print_t *print, mp_obj_t self_in, mp_pr { py_datamatrix_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, payload:\"%s\", rotation:%f, rows:%d, columns:%d, capacity:%d, padding:%d}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"rotation\":%f, \"rows\":%d, \"columns\":%d, \"capacity\":%d, \"padding\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -3815,7 +3995,7 @@ STATIC const mp_rom_map_elem_t py_datamatrix_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_rows), MP_ROM_PTR(&py_datamatrix_rows_obj) }, { MP_ROM_QSTR(MP_QSTR_columns), MP_ROM_PTR(&py_datamatrix_columns_obj) }, { MP_ROM_QSTR(MP_QSTR_capacity), MP_ROM_PTR(&py_datamatrix_capacity_obj) }, - { MP_ROM_QSTR(MP_QSTR_padding), MP_ROM_PTR(&py_datamatrix_padding_obj) }, + { MP_ROM_QSTR(MP_QSTR_padding), MP_ROM_PTR(&py_datamatrix_padding_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_datamatrix_locals_dict, py_datamatrix_locals_dict_table); @@ -3825,20 +4005,21 @@ static const mp_obj_type_t py_datamatrix_type = { .name = MP_QSTR_datamatrix, .print = py_datamatrix_print, .subscr = py_datamatrix_subscr, - .locals_dict = (mp_obj_t) &py_datamatrix_locals_dict, + .locals_dict = (mp_obj_t) &py_datamatrix_locals_dict }; static mp_obj_t py_image_find_datamatrices(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + int effort = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_effort), 200); list_t out; fb_alloc_mark(); - imlib_find_datamatrices(&out, arg_img, &roi, py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_effort), 200)); + imlib_find_datamatrices(&out, arg_img, &roi, effort); fb_alloc_free_till_mark(); mp_obj_list_t *objects_list = mp_obj_new_list(list_size(&out), NULL); @@ -3858,7 +4039,7 @@ static mp_obj_t py_image_find_datamatrices(uint n_args, const mp_obj_t *args, mp o->w = mp_obj_new_int(lnk_data.rect.w); o->h = mp_obj_new_int(lnk_data.rect.h); o->payload = mp_obj_new_str(lnk_data.payload, lnk_data.payload_len, false); - o->rotation = mp_obj_new_float((lnk_data.rotation * PI) / 180); + o->rotation = mp_obj_new_float(IM_DEG2RAD(lnk_data.rotation)); o->rows = mp_obj_new_int(lnk_data.rows); o->columns = mp_obj_new_int(lnk_data.columns); o->capacity = mp_obj_new_int(lnk_data.capacity); @@ -3870,6 +4051,7 @@ static mp_obj_t py_image_find_datamatrices(uint n_args, const mp_obj_t *args, mp return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_datamatrices_obj, 1, py_image_find_datamatrices); #endif // IMLIB_ENABLE_DATAMATRICES #ifdef IMLIB_ENABLE_BARCODES @@ -3885,7 +4067,8 @@ static void py_barcode_print(const mp_print_t *print, mp_obj_t self_in, mp_print { py_barcode_obj_t *self = self_in; mp_printf(print, - "{x:%d, y:%d, w:%d, h:%d, payload:\"%s\", type:%d, rotation:%f, quality:%d}", + "{\"x\":%d, \"y\":%d, \"w\":%d, \"h\":%d, \"payload\":\"%s\"," + " \"type\":%d, \"rotation\":%f, \"quality\":%d}", mp_obj_get_int(self->x), mp_obj_get_int(self->y), mp_obj_get_int(self->w), @@ -3962,7 +4145,7 @@ STATIC const mp_rom_map_elem_t py_barcode_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_payload), MP_ROM_PTR(&py_barcode_payload_fun_obj) }, { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&py_barcode_type_fun_obj) }, { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_barcode_rotation_fun_obj) }, - { MP_ROM_QSTR(MP_QSTR_quality), MP_ROM_PTR(&py_barcode_quality_fun_obj) }, + { MP_ROM_QSTR(MP_QSTR_quality), MP_ROM_PTR(&py_barcode_quality_fun_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_barcode_locals_dict, py_barcode_locals_dict_table); @@ -3972,16 +4155,15 @@ static const mp_obj_type_t py_barcode_type = { .name = MP_QSTR_barcode, .print = py_barcode_print, .subscr = py_barcode_subscr, - .locals_dict = (mp_obj_t) &py_barcode_locals_dict, + .locals_dict = (mp_obj_t) &py_barcode_locals_dict }; static mp_obj_t py_image_find_barcodes(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); list_t out; fb_alloc_mark(); @@ -4006,7 +4188,7 @@ static mp_obj_t py_image_find_barcodes(uint n_args, const mp_obj_t *args, mp_map o->h = mp_obj_new_int(lnk_data.rect.h); o->payload = mp_obj_new_str(lnk_data.payload, lnk_data.payload_len, false); o->type = mp_obj_new_int(lnk_data.type); - o->rotation = mp_obj_new_float((lnk_data.rotation * PI) / 180); + o->rotation = mp_obj_new_float(IM_DEG2RAD(lnk_data.rotation)); o->quality = mp_obj_new_int(lnk_data.quality); objects_list->items[i] = o; @@ -4015,6 +4197,7 @@ static mp_obj_t py_image_find_barcodes(uint n_args, const mp_obj_t *args, mp_map return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_barcodes_obj, 1, py_image_find_barcodes); #endif // IMLIB_ENABLE_BARCODES #ifdef IMLIB_ENABLE_FIND_DISPLACEMENT @@ -4029,7 +4212,7 @@ static void py_displacement_print(const mp_print_t *print, mp_obj_t self_in, mp_ { py_displacement_obj_t *self = self_in; mp_printf(print, - "{x_translation:%f, y_translation:%f, rotation:%f, scale:%f, response:%f}", + "{\"x_translation\":%f, \"y_translation\":%f, \"rotation\":%f, \"scale\":%f, \"response\":%f}", (double) mp_obj_get_float(self->x_translation), (double) mp_obj_get_float(self->y_translation), (double) mp_obj_get_float(self->rotation), @@ -4078,7 +4261,7 @@ STATIC const mp_rom_map_elem_t py_displacement_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_y_translation), MP_ROM_PTR(&py_displacement_y_translation_obj) }, { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&py_displacement_rotation_obj) }, { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&py_displacement_scale_obj) }, - { MP_ROM_QSTR(MP_QSTR_response), MP_ROM_PTR(&py_displacement_response_obj) }, + { MP_ROM_QSTR(MP_QSTR_response), MP_ROM_PTR(&py_displacement_response_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_displacement_locals_dict, py_displacement_locals_dict_table); @@ -4088,27 +4271,24 @@ static const mp_obj_type_t py_displacement_type = { .name = MP_QSTR_displacement, .print = py_displacement_print, .subscr = py_displacement_subscr, - .locals_dict = (mp_obj_t) &py_displacement_locals_dict, + .locals_dict = (mp_obj_t) &py_displacement_locals_dict }; static mp_obj_t py_image_find_displacement(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - image_t *arg_template_img = py_image_cobj(args[1]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_template_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); + image_t *arg_template_img = py_helper_arg_to_image_mutable(args[1]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); rectangle_t template_roi; - py_helper_lookup_rectangle_2(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_template_roi), arg_template_img, &template_roi); + py_helper_keyword_rectangle(arg_template_img, n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_template_roi), &template_roi); PY_ASSERT_FALSE_MSG((roi.w != template_roi.w) || (roi.h != template_roi.h), "ROI(w,h) != TEMPLATE_ROI(w,h)"); - bool logpolar = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_logpolar), false); - bool fix_rotation_scale = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fix_rotation_scale), false); + bool logpolar = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_logpolar), false); + bool fix_rotation_scale = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fix_rotation_scale), false); float x, y, r, s, response; fb_alloc_mark(); @@ -4125,25 +4305,21 @@ static mp_obj_t py_image_find_displacement(uint n_args, const mp_obj_t *args, mp return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_displacement_obj, 2, py_image_find_displacement); #endif // IMLIB_ENABLE_FIND_DISPLACEMENT #ifdef IMLIB_ENABLE_LENET static mp_obj_t py_image_find_number(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); // Make sure ROI is bigger than or equal to template size PY_ASSERT_TRUE_MSG((roi.w == LENET_INPUT_W && roi.h == LENET_INPUT_H), "Region of interest must be 28x28!"); - // Make sure ROI is smaller than or equal to image size - PY_ASSERT_TRUE_MSG(((roi.x + roi.w) <= arg_img->w && (roi.y + roi.h) <= arg_img->h), - "Region of interest is bigger than image!"); - int r = 0; float c = 0.0f; lenet5_t *lenet = (lenet5_t*) lenet_model_num; @@ -4156,148 +4332,38 @@ static mp_obj_t py_image_find_number(uint n_args, const mp_obj_t *args, mp_map_t return mp_obj_new_tuple(2, ret_obj); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_number_obj, 1, py_image_find_number); #endif //IMLIB_ENABLE_LENET #ifdef IMLIB_ENABLE_CNN -extern int imlib_classify_object(image_t *img, int8_t *output_data); static mp_obj_t py_image_classify_object(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); + image_t *arg_img = py_helper_arg_to_image_color(args[0]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); - - // Make sure ROI is smaller than or equal to image size - PY_ASSERT_TRUE_MSG(((roi.x + roi.w) <= arg_img->w && (roi.y + roi.h) <= arg_img->h), - "Region of interest is bigger than image!"); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); int8_t output_data[10]; imlib_classify_object(arg_img, output_data); - mp_obj_t output_list = mp_obj_new_list(0, NULL); + for (int i=0; i<10; i++) { mp_obj_list_append(output_list, mp_obj_new_int(output_data[i])); } return output_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_classify_object_obj, 1, py_image_classify_object); #endif //IMLIB_ENABLE_LENET -static mp_obj_t py_image_midpoint_pool(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int x_div = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); - int y_div = mp_obj_get_int(args[2]); - PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - - image_t out_img; - out_img.w = arg_img->w / x_div; - out_img.h = arg_img->h / y_div; - out_img.bpp = arg_img->bpp; - out_img.pixels = arg_img->pixels; - - int bias = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256; - imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, IM_MIN(IM_MAX(bias, 0), 256)); - arg_img->w = out_img.w; - arg_img->h = out_img.h; - return mp_const_none; -} - -static mp_obj_t py_image_midpoint_pooled(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) -{ - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int x_div = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); - int y_div = mp_obj_get_int(args[2]); - PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - - image_t out_img; - out_img.w = arg_img->w / x_div; - out_img.h = arg_img->h / y_div; - out_img.bpp = arg_img->bpp; - out_img.pixels = xalloc(out_img.w * out_img.h * out_img.bpp); - - int bias = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_bias), 0.5) * 256; - imlib_midpoint_pool(arg_img, &out_img, x_div, y_div, IM_MIN(IM_MAX(bias, 0), 256)); - return py_image_from_struct(&out_img); -} - -static mp_obj_t py_image_mean_pool(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int x_div = mp_obj_get_int(x_div_obj); - PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); - int y_div = mp_obj_get_int(y_div_obj); - PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - - image_t out_img; - out_img.w = arg_img->w / x_div; - out_img.h = arg_img->h / y_div; - out_img.bpp = arg_img->bpp; - out_img.pixels = arg_img->pixels; - - imlib_mean_pool(arg_img, &out_img, x_div, y_div); - arg_img->w = out_img.w; - arg_img->h = out_img.h; - // Check if this image is the one in the frame buffer... - if ((MAIN_FB()->pixels == arg_img->pixels) || (MAIN_FB()->pixels == arg_img->pixels)) { - MAIN_FB()->w = out_img.w; - MAIN_FB()->h = out_img.h; - } - - return img_obj; -} - -static mp_obj_t py_image_mean_pooled(mp_obj_t img_obj, mp_obj_t x_div_obj, mp_obj_t y_div_obj) -{ - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - - int x_div = mp_obj_get_int(x_div_obj); - PY_ASSERT_TRUE_MSG(x_div >= 1, "Width divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(x_div <= arg_img->w, "Width divisor must be less than <= img width"); - int y_div = mp_obj_get_int(y_div_obj); - PY_ASSERT_TRUE_MSG(y_div >= 1, "Height divisor must be greater than >= 1"); - PY_ASSERT_TRUE_MSG(y_div <= arg_img->h, "Height divisor must be less than <= img height"); - - image_t out_img; - out_img.w = arg_img->w / x_div; - out_img.h = arg_img->h / y_div; - out_img.bpp = arg_img->bpp; - out_img.pixels = xalloc(out_img.w * out_img.h * out_img.bpp); - - imlib_mean_pool(arg_img, &out_img, x_div, y_div); - return py_image_from_struct(&out_img); -} - static mp_obj_t py_image_find_template(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), - "This function is only supported on GRAYSCALE images"); - - image_t *arg_template = py_image_cobj(args[1]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_template), - "This function is only supported on GRAYSCALE images"); - + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); + image_t *arg_template = py_helper_arg_to_image_grayscale(args[1]); float arg_thresh = mp_obj_get_float(args[2]); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 3, kw_args, &roi); // Make sure ROI is bigger than or equal to template size PY_ASSERT_TRUE_MSG((roi.w >= arg_template->w && roi.h >= arg_template->h), @@ -4307,8 +4373,8 @@ static mp_obj_t py_image_find_template(uint n_args, const mp_obj_t *args, mp_map PY_ASSERT_TRUE_MSG(((roi.x + roi.w) <= arg_img->w && (roi.y + roi.h) <= arg_img->h), "Region of interest is bigger than image!"); - int step = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_step), 2); - int search = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_search), SEARCH_EX); + int step = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_step), 2); + int search = py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_search), SEARCH_EX); // Find template rectangle_t r; @@ -4330,31 +4396,24 @@ static mp_obj_t py_image_find_template(uint n_args, const mp_obj_t *args, mp_map } return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_template_obj, 3, py_image_find_template); static mp_obj_t py_image_find_features(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), - "This function is only supported on GRAYSCALE images"); - + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); cascade_t *cascade = py_cascade_cobj(args[1]); - cascade->threshold = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0.5f); - cascade->scale_factor = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); + cascade->threshold = py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0.5f); + cascade->scale_factor = py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); - rectangle_t arg_r; - py_helper_lookup_rectangle(kw_args, arg_img, &arg_r); - - rectangle_t rect; - if (!rectangle_subimg(arg_img, &arg_r, &rect)) { - return mp_obj_new_list(0, NULL); - } + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 4, kw_args, &roi); // Make sure ROI is bigger than feature size - PY_ASSERT_TRUE_MSG((rect.w > cascade->window.w && rect.h > cascade->window.h), + PY_ASSERT_TRUE_MSG((roi.w > cascade->window.w && roi.h > cascade->window.h), "Region of interest is smaller than detector window!"); // Detect objects - array_t *objects_array = imlib_detect_objects(arg_img, cascade, &rect); + array_t *objects_array = imlib_detect_objects(arg_img, cascade, &roi); // Add detected objects to a new Python list... mp_obj_t objects_list = mp_obj_new_list(0, NULL); @@ -4371,30 +4430,17 @@ static mp_obj_t py_image_find_features(uint n_args, const mp_obj_t *args, mp_map array_free(objects_array); return objects_list; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_features_obj, 2, py_image_find_features); -static mp_obj_t py_image_find_eye(mp_obj_t img_obj, mp_obj_t roi_obj) +static mp_obj_t py_image_find_eye(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), - "This function is only supported on GRAYSCALE images"); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); - mp_obj_t *array; - mp_obj_get_array_fixed_n(roi_obj, 4, &array); - - rectangle_t arg_r = { - mp_obj_get_int(array[0]), - mp_obj_get_int(array[1]), - mp_obj_get_int(array[2]), - mp_obj_get_int(array[3]), - }; - - rectangle_t rect; - if (!rectangle_subimg(arg_img, &arg_r, &rect)) { - return mp_const_none; - } + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); point_t iris; - imlib_find_iris(arg_img, &iris, &rect); + imlib_find_iris(arg_img, &iris, &roi); mp_obj_t eye_obj[2] = { mp_obj_new_int(iris.x), @@ -4403,42 +4449,39 @@ static mp_obj_t py_image_find_eye(mp_obj_t img_obj, mp_obj_t roi_obj) return mp_obj_new_tuple(2, eye_obj); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_eye_obj, 2, py_image_find_eye); -static mp_obj_t py_image_find_lbp(mp_obj_t img_obj, mp_obj_t roi_obj) +static mp_obj_t py_image_find_lbp(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(img_obj); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), - "This function is only supported on GRAYSCALE images"); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); - mp_obj_t *array; - mp_obj_get_array_fixed_n(roi_obj, 4, &array); - - rectangle_t roi = { - mp_obj_get_int(array[0]), - mp_obj_get_int(array[1]), - mp_obj_get_int(array[2]), - mp_obj_get_int(array[3]), - }; + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); py_lbp_obj_t *lbp_obj = m_new_obj(py_lbp_obj_t); lbp_obj->base.type = &py_lbp_type; lbp_obj->hist = imlib_lbp_desc(arg_img, &roi); return lbp_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lbp_obj, 2, py_image_find_lbp); static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), "This function is only supported on GRAYSCALE images"); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); - // Lookup args rectangle_t roi; - py_helper_lookup_rectangle(kw_args, arg_img, &roi); - int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 20); - bool normalized = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_normalized), false); - float scale_factor = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); - int max_keypoints = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_keypoints), 100); - corner_detector_t corner_detector = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_corner_detector), CORNER_AGAST); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); + + int threshold = + py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 20); + bool normalized = + py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_normalized), false); + float scale_factor = + py_helper_keyword_float(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale_factor), 1.5f); + int max_keypoints = + py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_max_keypoints), 100); + corner_detector_t corner_detector = + py_helper_keyword_int(n_args, args, 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_corner_detector), CORNER_AGAST); // Find keypoints array_t *kpts = orb_find_keypoints(arg_img, normalized, threshold, scale_factor, max_keypoints, corner_detector, &roi); @@ -4453,328 +4496,196 @@ static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_ma } return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *img = py_image_cobj(args[0]); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); edge_detector_t edge_type = mp_obj_get_int(args[1]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(img), "This function is only supported on GRAYSCALE images"); rectangle_t roi; - py_helper_lookup_rectangle(kw_args, img, &roi); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 2, kw_args, &roi); int thresh[2] = {100, 200}; - py_helper_lookup_int_array(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), thresh, 2); + mp_obj_t thresh_obj = py_helper_keyword_object(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold)); + + if (thresh_obj) { + mp_obj_t *thresh_array; + mp_obj_get_array_fixed_n(thresh_obj, 2, &thresh_array); + thresh[0] = mp_obj_get_int(thresh_array[0]); + thresh[1] = mp_obj_get_int(thresh_array[1]); + } switch (edge_type) { case EDGE_SIMPLE: { - imlib_edge_simple(img, &roi, thresh[0], thresh[1]); + imlib_edge_simple(arg_img, &roi, thresh[0], thresh[1]); break; } case EDGE_CANNY: { - imlib_edge_canny(img, &roi, thresh[0], thresh[1]); + imlib_edge_canny(arg_img, &roi, thresh[0], thresh[1]); break; } } - return mp_const_true; + return args[0]; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges); static mp_obj_t py_image_find_hog(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - image_t *arg_img = py_image_cobj(args[0]); - PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), "This function is only supported on GRAYSCALE images"); + image_t *arg_img = py_helper_arg_to_image_grayscale(args[0]); - rectangle_t arg_r; - py_helper_lookup_rectangle(kw_args, arg_img, &arg_r); + rectangle_t roi; + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &roi); - rectangle_t rect; - if (!rectangle_subimg(arg_img, &arg_r, &rect)) { - return mp_const_none; - } + int size = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 8); - int size = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 8); - imlib_find_hog(arg_img, &rect, size); + imlib_find_hog(arg_img, &roi, size); - return mp_const_none; + return args[0]; } - -/* Image file functions */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_to_fb_obj, 1, py_image_copy_to_fb); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_obj, 1, py_image_compress); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compress_for_ide_obj, 1, py_image_compress_for_ide); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_obj, 1, py_image_compressed); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_compressed_for_ide_obj, 1, py_image_compressed_for_ide); -/* Basic image functions */ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_clear_obj, py_image_clear); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_get_pixel_obj, py_image_get_pixel); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_set_pixel_obj, 4, 4, py_image_set_pixel); -/* Drawing functions */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_circle); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 3, py_image_draw_cross); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints); -/* Binary Methods */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_binary_obj, 2, py_image_binary); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_erode_obj, 2, py_image_erode); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate); -/* Math Methods */ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_replace_obj, 2, py_image_replace); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_add_obj, 2, py_image_add); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_sub_obj, 2, py_image_sub); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mul_obj, 2, py_image_mul); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_div_obj, 2, py_image_div); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_min_obj, 2, py_image_min); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_max_obj, 2, py_image_max); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_difference_obj, 2, py_image_difference); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_blend_obj, 2, py_image_blend); -/* Image Morphing */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_morph_obj, 3, py_image_morph); -/* Image Filtering */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mean_obj, 2, py_image_mean); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mode_obj, 2, py_image_mode); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 2, py_image_median); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gaussian_obj, 1, py_image_gaussian); -#ifdef IMLIB_ENABLE_LINPOLAR -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_linpolar_obj, 1, py_image_linpolar); -#endif -#ifdef IMLIB_ENABLE_LOGPOLAR -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_logpolar_obj, 1, py_image_logpolar); -#endif -#ifdef IMLIB_ENABLE_REMOVE_SHADOWS -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_remove_shadows_obj, 1, 2, py_image_remove_shadows); -#endif -#ifdef IMLIB_ENABLE_CHROMINVAR -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_chrominvar_obj, py_image_chrominvar); -#endif -#ifdef IMLIB_ENABLE_ILLUMINVAR -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_illuminvar_obj, py_image_illuminvar); -#endif -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_lens_corr_obj, 1, py_image_lens_corr); -#ifdef IMLIB_ENABLE_ROTATION_CORR -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_rotation_corr_obj, 1, py_image_rotation_corr); -#endif -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_mask_ellipse_obj, py_image_mask_ellipse); -/* Image Statistics */ -#ifdef IMLIB_ENABLE_GET_SIMILARITY -STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_get_similarity_obj, py_image_get_similarity); -#endif -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_histogram_obj, 1, py_image_get_histogram); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_statistics_obj, 1, py_image_get_statistics); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_regression_obj, 2, py_image_get_regression); -/* Color Tracking */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_blobs_obj, 2, py_image_find_blobs); -/* Shape Detection */ -#ifdef IMLIB_ENABLE_FIND_LINES -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lines_obj, 1, py_image_find_lines); -#endif -#ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_line_segments_obj, 1, py_image_find_line_segments); -#endif -#ifdef IMLIB_ENABLE_FIND_CIRCLES -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_circles_obj, 1, py_image_find_circles); -#endif -#ifdef IMLIB_ENABLE_FIND_RECTS -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_rects_obj, 1, py_image_find_rects); -#endif -/* Code Detection */ -#ifdef IMLIB_ENABLE_QRCODES -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_qrcodes_obj, 1, py_image_find_qrcodes); -#endif -#ifdef IMLIB_ENABLE_APRILTAGS -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_apriltags_obj, 1, py_image_find_apriltags); -#endif -#ifdef IMLIB_ENABLE_DATAMATRICES -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_datamatrices_obj, 1, py_image_find_datamatrices); -#endif -#ifdef IMLIB_ENABLE_BARCODES -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_barcodes_obj, 1, py_image_find_barcodes); -#endif -/* Template Matching */ -#ifdef IMLIB_ENABLE_FIND_DISPLACEMENT -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_displacement_obj, 2, py_image_find_displacement); -#endif -#ifdef IMLIB_ENABLE_LENET -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_number_obj, 1, py_image_find_number); -#endif -#ifdef IMLIB_ENABLE_CNN -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_classify_object_obj, 1, py_image_classify_object); -#endif -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pool_obj, 3, py_image_midpoint_pool); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_pooled_obj, 3, py_image_midpoint_pooled); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pool_obj, py_image_mean_pool); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_mean_pooled_obj, py_image_mean_pooled); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_template_obj, 3, py_image_find_template); -/* Feature Detection */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_features_obj, 2, py_image_find_features); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_eye_obj, py_image_find_eye); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_lbp_obj, py_image_find_lbp); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_hog_obj, 1, py_image_find_hog); -static const mp_map_elem_t locals_dict_table[] = { - /* Image file functions */ - {MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&py_image_copy_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), (mp_obj_t)&py_image_copy_to_fb_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_compress), (mp_obj_t)&py_image_compress_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_compress_for_ide), (mp_obj_t)&py_image_compress_for_ide_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_compressed), (mp_obj_t)&py_image_compressed_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_compressed_for_ide), (mp_obj_t)&py_image_compressed_for_ide_obj}, - /* Basic image functions */ - {MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_image_width_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_image_height_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&py_image_format_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&py_image_size_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&py_image_clear_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)&py_image_get_pixel_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)&py_image_set_pixel_obj}, - /* Drawing functions */ - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_line), (mp_obj_t)&py_image_draw_line_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_rectangle), (mp_obj_t)&py_image_draw_rectangle_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&py_image_draw_circle_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_string), (mp_obj_t)&py_image_draw_string_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_cross), (mp_obj_t)&py_image_draw_cross_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_draw_keypoints), (mp_obj_t)&py_image_draw_keypoints_obj}, + +static const mp_rom_map_elem_t locals_dict_table[] = { + /* Basic Methods */ + {MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&py_image_width_obj)}, + {MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&py_image_height_obj)}, + {MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&py_image_format_obj)}, + {MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_image_size_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(&py_image_get_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&py_image_set_pixel_obj)}, + {MP_ROM_QSTR(MP_QSTR_mean_pool), MP_ROM_PTR(&py_image_mean_pool_obj)}, + {MP_ROM_QSTR(MP_QSTR_mean_pooled), MP_ROM_PTR(&py_image_mean_pooled_obj)}, + {MP_ROM_QSTR(MP_QSTR_midpoint_pool), MP_ROM_PTR(&py_image_midpoint_pool_obj)}, + {MP_ROM_QSTR(MP_QSTR_midpoint_pooled), MP_ROM_PTR(&py_image_midpoint_pooled_obj)}, + {MP_ROM_QSTR(MP_QSTR_compress), MP_ROM_PTR(&py_image_compress_obj)}, + {MP_ROM_QSTR(MP_QSTR_compress_for_ide), MP_ROM_PTR(&py_image_compress_for_ide_obj)}, + {MP_ROM_QSTR(MP_QSTR_compressed), MP_ROM_PTR(&py_image_compressed_obj)}, + {MP_ROM_QSTR(MP_QSTR_compressed_for_ide), MP_ROM_PTR(&py_image_compressed_for_ide_obj)}, + {MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&py_image_copy_obj)}, + {MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&py_image_save_obj)}, + /* Drawing Methods */ + {MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&py_image_clear_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&py_image_draw_line_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_rectangle), MP_ROM_PTR(&py_image_draw_rectangle_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&py_image_draw_circle_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&py_image_draw_string_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_cross), MP_ROM_PTR(&py_image_draw_cross_obj)}, + {MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)}, /* Binary Methods */ - {MP_OBJ_NEW_QSTR(MP_QSTR_binary), (mp_obj_t)&py_image_binary_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)&py_image_invert_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_and), (mp_obj_t)&py_image_b_and_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_and), (mp_obj_t)&py_image_b_and_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_nand), (mp_obj_t)&py_image_b_nand_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_nand), (mp_obj_t)&py_image_b_nand_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_or), (mp_obj_t)&py_image_b_or_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_or), (mp_obj_t)&py_image_b_or_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_nor), (mp_obj_t)&py_image_b_nor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_nor), (mp_obj_t)&py_image_b_nor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_xor), (mp_obj_t)&py_image_b_xor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_xor), (mp_obj_t)&py_image_b_xor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_xnor), (mp_obj_t)&py_image_b_xnor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_b_xnor), (mp_obj_t)&py_image_b_xnor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_erode), (mp_obj_t)&py_image_erode_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_dilate), (mp_obj_t)&py_image_dilate_obj}, + {MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)}, + {MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&py_image_invert_obj)}, + {MP_ROM_QSTR(MP_QSTR_and), MP_ROM_PTR(&py_image_b_and_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_and), MP_ROM_PTR(&py_image_b_and_obj)}, + {MP_ROM_QSTR(MP_QSTR_nand), MP_ROM_PTR(&py_image_b_nand_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nand), MP_ROM_PTR(&py_image_b_nand_obj)}, + {MP_ROM_QSTR(MP_QSTR_or), MP_ROM_PTR(&py_image_b_or_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_or), MP_ROM_PTR(&py_image_b_or_obj)}, + {MP_ROM_QSTR(MP_QSTR_nor), MP_ROM_PTR(&py_image_b_nor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_nor), MP_ROM_PTR(&py_image_b_nor_obj)}, + {MP_ROM_QSTR(MP_QSTR_xor), MP_ROM_PTR(&py_image_b_xor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xor), MP_ROM_PTR(&py_image_b_xor_obj)}, + {MP_ROM_QSTR(MP_QSTR_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)}, + {MP_ROM_QSTR(MP_QSTR_b_xnor), MP_ROM_PTR(&py_image_b_xnor_obj)}, + {MP_ROM_QSTR(MP_QSTR_erode), MP_ROM_PTR(&py_image_erode_obj)}, + {MP_ROM_QSTR(MP_QSTR_dilate), MP_ROM_PTR(&py_image_dilate_obj)}, /* Math Methods */ - {MP_OBJ_NEW_QSTR(MP_QSTR_negate), (mp_obj_t)&py_image_negate_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&py_image_replace_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_add), (mp_obj_t)&py_image_add_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_sub), (mp_obj_t)&py_image_sub_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_mul), (mp_obj_t)&py_image_mul_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_div), (mp_obj_t)&py_image_div_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&py_image_min_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&py_image_max_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&py_image_difference_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_blend), (mp_obj_t)&py_image_blend_obj}, - /* Image Morphing */ - {MP_OBJ_NEW_QSTR(MP_QSTR_morph), (mp_obj_t)&py_image_morph_obj}, - /* Image Filtering */ - {MP_OBJ_NEW_QSTR(MP_QSTR_midpoint), (mp_obj_t)&py_image_midpoint_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&py_image_mean_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_mode), (mp_obj_t)&py_image_mode_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_gaussian), (mp_obj_t)&py_image_gaussian_obj}, + {MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)}, + {MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)}, + {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_image_add_obj)}, + {MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&py_image_sub_obj)}, + {MP_ROM_QSTR(MP_QSTR_mul), MP_ROM_PTR(&py_image_mul_obj)}, + {MP_ROM_QSTR(MP_QSTR_div), MP_ROM_PTR(&py_image_div_obj)}, + {MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&py_image_min_obj)}, + {MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&py_image_max_obj)}, + {MP_ROM_QSTR(MP_QSTR_difference), MP_ROM_PTR(&py_image_difference_obj)}, + {MP_ROM_QSTR(MP_QSTR_blend), MP_ROM_PTR(&py_image_blend_obj)}, + /* Filtering Methods */ + {MP_ROM_QSTR(MP_QSTR_histeq), MP_ROM_PTR(&py_image_histeq_obj)}, + {MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&py_image_mean_obj)}, + {MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&py_image_median_obj)}, + {MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&py_image_mode_obj)}, + {MP_ROM_QSTR(MP_QSTR_midpoint), MP_ROM_PTR(&py_image_midpoint_obj)}, + {MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&py_image_morph_obj)}, + {MP_ROM_QSTR(MP_QSTR_gaussian), MP_ROM_PTR(&py_image_gaussian_obj)}, + /* Shadow Removal Methods */ #ifdef IMLIB_ENABLE_REMOVE_SHADOWS - {MP_OBJ_NEW_QSTR(MP_QSTR_remove_shadows), (mp_obj_t)&py_image_remove_shadows_obj}, -#endif -#ifdef IMLIB_ENABLE_LINPOLAR - {MP_OBJ_NEW_QSTR(MP_QSTR_linpolar), (mp_obj_t)&py_image_linpolar_obj}, -#endif -#ifdef IMLIB_ENABLE_LOGPOLAR - {MP_OBJ_NEW_QSTR(MP_QSTR_logpolar), (mp_obj_t)&py_image_logpolar_obj}, + {MP_ROM_QSTR(MP_QSTR_remove_shadows), MP_ROM_PTR(&py_image_remove_shadows_obj)}, #endif #ifdef IMLIB_ENABLE_CHROMINVAR - {MP_OBJ_NEW_QSTR(MP_QSTR_chrominvar), (mp_obj_t)&py_image_chrominvar_obj}, + {MP_ROM_QSTR(MP_QSTR_chrominvar), MP_ROM_PTR(&py_image_chrominvar_obj)}, #endif #ifdef IMLIB_ENABLE_ILLUMINVAR - {MP_OBJ_NEW_QSTR(MP_QSTR_illuminvar), (mp_obj_t)&py_image_illuminvar_obj}, + {MP_ROM_QSTR(MP_QSTR_illuminvar), MP_ROM_PTR(&py_image_illuminvar_obj)}, #endif - {MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_lens_corr), (mp_obj_t)&py_image_lens_corr_obj}, + /* Geometric Methods */ +#ifdef IMLIB_ENABLE_LINPOLAR + {MP_ROM_QSTR(MP_QSTR_linpolar), MP_ROM_PTR(&py_image_linpolar_obj)}, +#endif +#ifdef IMLIB_ENABLE_LOGPOLAR + {MP_ROM_QSTR(MP_QSTR_logpolar), MP_ROM_PTR(&py_image_logpolar_obj)}, +#endif + {MP_ROM_QSTR(MP_QSTR_lens_corr), MP_ROM_PTR(&py_image_lens_corr_obj)}, #ifdef IMLIB_ENABLE_ROTATION_CORR - {MP_OBJ_NEW_QSTR(MP_QSTR_rotation_corr), (mp_obj_t)&py_image_rotation_corr_obj}, + {MP_ROM_QSTR(MP_QSTR_rotation_corr), MP_ROM_PTR(&py_image_rotation_corr_obj)}, #endif - {MP_OBJ_NEW_QSTR(MP_QSTR_mask_ellipse), (mp_obj_t)&py_image_mask_ellipse_obj}, - /* Image Statistics */ + {MP_ROM_QSTR(MP_QSTR_mask_ellipse), MP_ROM_PTR(&py_image_mask_ellipse_obj)}, + /* Get Methods */ #ifdef IMLIB_ENABLE_GET_SIMILARITY - {MP_OBJ_NEW_QSTR(MP_QSTR_get_similarity), (mp_obj_t)&py_image_get_similarity_obj}, + {MP_ROM_QSTR(MP_QSTR_get_similarity), MP_ROM_PTR(&py_image_get_similarity_obj)}, #endif - {MP_OBJ_NEW_QSTR(MP_QSTR_get_hist), (mp_obj_t)&py_image_get_histogram_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_get_histogram), (mp_obj_t)&py_image_get_histogram_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_histogram), (mp_obj_t)&py_image_get_histogram_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_get_stats), (mp_obj_t)&py_image_get_statistics_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_get_statistics), (mp_obj_t)&py_image_get_statistics_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_statistics), (mp_obj_t)&py_image_get_statistics_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_get_regression), (mp_obj_t)&py_image_get_regression_obj}, - /* Color Tracking */ - {MP_OBJ_NEW_QSTR(MP_QSTR_find_blobs), (mp_obj_t)&py_image_find_blobs_obj}, - /* Shape Detection */ + {MP_ROM_QSTR(MP_QSTR_get_hist), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_histogram), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_histogram), MP_ROM_PTR(&py_image_get_histogram_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_stats), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_statistics), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_statistics), MP_ROM_PTR(&py_image_get_statistics_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_regression), MP_ROM_PTR(&py_image_get_regression_obj)}, + /* Find Methods */ + {MP_ROM_QSTR(MP_QSTR_find_blobs), MP_ROM_PTR(&py_image_find_blobs_obj)}, #ifdef IMLIB_ENABLE_FIND_LINES - {MP_OBJ_NEW_QSTR(MP_QSTR_find_lines), (mp_obj_t)&py_image_find_lines_obj}, + {MP_ROM_QSTR(MP_QSTR_find_lines), MP_ROM_PTR(&py_image_find_lines_obj)}, #endif #ifdef IMLIB_ENABLE_FIND_LINE_SEGMENTS - {MP_OBJ_NEW_QSTR(MP_QSTR_find_line_segments), (mp_obj_t)&py_image_find_line_segments_obj}, + {MP_ROM_QSTR(MP_QSTR_find_line_segments), MP_ROM_PTR(&py_image_find_line_segments_obj)}, #endif #ifdef IMLIB_ENABLE_FIND_CIRCLES - {MP_OBJ_NEW_QSTR(MP_QSTR_find_circles), (mp_obj_t)&py_image_find_circles_obj}, + {MP_ROM_QSTR(MP_QSTR_find_circles), MP_ROM_PTR(&py_image_find_circles_obj)}, #endif #ifdef IMLIB_ENABLE_FIND_RECTS - {MP_OBJ_NEW_QSTR(MP_QSTR_find_rects), (mp_obj_t)&py_image_find_rects_obj}, + {MP_ROM_QSTR(MP_QSTR_find_rects), MP_ROM_PTR(&py_image_find_rects_obj)}, #endif - /* Code Detection */ #ifdef IMLIB_ENABLE_QRCODES - {MP_OBJ_NEW_QSTR(MP_QSTR_find_qrcodes), (mp_obj_t)&py_image_find_qrcodes_obj}, + {MP_ROM_QSTR(MP_QSTR_find_qrcodes), MP_ROM_PTR(&py_image_find_qrcodes_obj)}, #endif #ifdef IMLIB_ENABLE_APRILTAGS - {MP_OBJ_NEW_QSTR(MP_QSTR_find_apriltags), (mp_obj_t)&py_image_find_apriltags_obj}, + {MP_ROM_QSTR(MP_QSTR_find_apriltags), MP_ROM_PTR(&py_image_find_apriltags_obj)}, #endif #ifdef IMLIB_ENABLE_DATAMATRICES - {MP_OBJ_NEW_QSTR(MP_QSTR_find_datamatrices), (mp_obj_t)&py_image_find_datamatrices_obj}, + {MP_ROM_QSTR(MP_QSTR_find_datamatrices), MP_ROM_PTR(&py_image_find_datamatrices_obj)}, #endif #ifdef IMLIB_ENABLE_BARCODES - {MP_OBJ_NEW_QSTR(MP_QSTR_find_barcodes), (mp_obj_t)&py_image_find_barcodes_obj}, + {MP_ROM_QSTR(MP_QSTR_find_barcodes), MP_ROM_PTR(&py_image_find_barcodes_obj)}, #endif - /* Template Matching */ #ifdef IMLIB_ENABLE_FIND_DISPLACEMENT - {MP_OBJ_NEW_QSTR(MP_QSTR_find_displacement), (mp_obj_t)&py_image_find_displacement_obj}, + {MP_ROM_QSTR(MP_QSTR_find_displacement), MP_ROM_PTR(&py_image_find_displacement_obj)}, #endif #ifdef IMLIB_ENABLE_LENET - {MP_OBJ_NEW_QSTR(MP_QSTR_find_number), (mp_obj_t)&py_image_find_number_obj}, + {MP_ROM_QSTR(MP_QSTR_find_number), MP_ROM_PTR(&py_image_find_number_obj)}, #endif #ifdef IMLIB_ENABLE_CNN - {MP_OBJ_NEW_QSTR(MP_QSTR_classify_object), (mp_obj_t)&py_image_classify_object_obj}, + {MP_ROM_QSTR(MP_QSTR_classify_object), MP_ROM_PTR(&py_image_classify_object_obj)}, #endif - {MP_OBJ_NEW_QSTR(MP_QSTR_midpoint_pool), (mp_obj_t)&py_image_midpoint_pool_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_midpoint_pooled), (mp_obj_t)&py_image_midpoint_pooled_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_mean_pool), (mp_obj_t)&py_image_mean_pool_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_mean_pooled), (mp_obj_t)&py_image_mean_pooled_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_template), (mp_obj_t)&py_image_find_template_obj}, - /* Feature Detection */ - {MP_OBJ_NEW_QSTR(MP_QSTR_find_features), (mp_obj_t)&py_image_find_features_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_eye), (mp_obj_t)&py_image_find_eye_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_lbp), (mp_obj_t)&py_image_find_lbp_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_keypoints), (mp_obj_t)&py_image_find_keypoints_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_edges), (mp_obj_t)&py_image_find_edges_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_hog), (mp_obj_t)&py_image_find_hog_obj}, - { NULL, NULL }, + {MP_ROM_QSTR(MP_QSTR_find_template), MP_ROM_PTR(&py_image_find_template_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_features), MP_ROM_PTR(&py_image_find_features_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_eye), MP_ROM_PTR(&py_image_find_eye_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_lbp), MP_ROM_PTR(&py_image_find_lbp_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_keypoints), MP_ROM_PTR(&py_image_find_keypoints_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_edges), MP_ROM_PTR(&py_image_find_edges_obj)}, + {MP_ROM_QSTR(MP_QSTR_find_hog), MP_ROM_PTR(&py_image_find_hog_obj)} }; + STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); static const mp_obj_type_t py_image_type = { @@ -4783,7 +4694,7 @@ static const mp_obj_type_t py_image_type = { .print = py_image_print, .buffer_p = { .get_buffer = py_image_get_buffer }, .subscr = py_image_subscr, - .locals_dict = (mp_obj_t)&locals_dict, + .locals_dict = (mp_obj_t) &locals_dict }; // ImageWriter Object // @@ -4796,7 +4707,7 @@ typedef struct py_imagewriter_obj { static void py_imagewriter_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_imagewriter_obj_t *self = self_in; - mp_printf(print, "{size:%d}", f_size(&self->fp)); + mp_printf(print, "{\"size\":%d}", f_size(&self->fp)); } mp_obj_t py_imagewriter_size(mp_obj_t self_in) @@ -4824,13 +4735,13 @@ mp_obj_t py_imagewriter_add_frame(mp_obj_t self_in, mp_obj_t img_obj) write_data(fp, arg_img->data, size); if (size % 16) write_data(fp, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16 - (size % 16)); // Pad to multiple of 16 bytes. - return mp_const_none; + return self_in; } mp_obj_t py_imagewriter_close(mp_obj_t self_in) { file_close(&((py_imagewriter_obj_t *) self_in)->fp); - return mp_const_none; + return self_in; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagewriter_size_obj, py_imagewriter_size); @@ -4840,7 +4751,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagewriter_close_obj, py_imagewriter_close) STATIC const mp_rom_map_elem_t py_imagewriter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_imagewriter_size_obj) }, { MP_ROM_QSTR(MP_QSTR_add_frame), MP_ROM_PTR(&py_imagewriter_add_frame_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagewriter_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagewriter_close_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_imagewriter_locals_dict, py_imagewriter_locals_dict_table); @@ -4849,7 +4760,7 @@ static const mp_obj_type_t py_imagewriter_type = { { &mp_type_type }, .name = MP_QSTR_imagewriter, .print = py_imagewriter_print, - .locals_dict = (mp_obj_t) &py_imagewriter_locals_dict, + .locals_dict = (mp_obj_t) &py_imagewriter_locals_dict }; mp_obj_t py_image_imagewriter(mp_obj_t path) @@ -4866,6 +4777,7 @@ mp_obj_t py_image_imagewriter(mp_obj_t path) obj->ms = systick_current_millis(); return obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagewriter_obj, py_image_imagewriter); // ImageReader Object // typedef struct py_imagereader_obj { @@ -4877,7 +4789,7 @@ typedef struct py_imagereader_obj { static void py_imagereader_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_imagereader_obj_t *self = self_in; - mp_printf(print, "{size:%d}", f_size(&self->fp)); + mp_printf(print, "{\"size\":%d}", f_size(&self->fp)); } mp_obj_t py_imagereader_size(mp_obj_t self_in) @@ -4889,14 +4801,14 @@ mp_obj_t py_imagereader_next_frame(uint n_args, const mp_obj_t *args, mp_map_t * { // Don't use the file buffer here... - bool copy_to_fb = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), true); + bool copy_to_fb = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), true); if (copy_to_fb) fb_update_jpeg_buffer(); FIL *fp = &((py_imagereader_obj_t *) args[0])->fp; image_t image = {0}; if (f_eof(fp)) { - if (!py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true)) { + if (!py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true)) { return mp_const_none; } @@ -4945,7 +4857,7 @@ mp_obj_t py_imagereader_next_frame(uint n_args, const mp_obj_t *args, mp_map_t * mp_obj_t py_imagereader_close(mp_obj_t self_in) { file_close(&((py_imagereader_obj_t *) self_in)->fp); - return mp_const_none; + return self_in; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagereader_size_obj, py_imagereader_size); @@ -4955,7 +4867,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_imagereader_close_obj, py_imagereader_close) STATIC const mp_rom_map_elem_t py_imagereader_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_imagereader_size_obj) }, { MP_ROM_QSTR(MP_QSTR_next_frame), MP_ROM_PTR(&py_imagereader_next_frame_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagereader_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_imagereader_close_obj) } }; STATIC MP_DEFINE_CONST_DICT(py_imagereader_locals_dict, py_imagereader_locals_dict_table); @@ -4964,7 +4876,7 @@ static const mp_obj_type_t py_imagereader_type = { { &mp_type_type }, .name = MP_QSTR_imagereader, .print = py_imagereader_print, - .locals_dict = (mp_obj_t) &py_imagereader_locals_dict, + .locals_dict = (mp_obj_t) &py_imagereader_locals_dict }; mp_obj_t py_image_imagereader(mp_obj_t path) @@ -4981,6 +4893,7 @@ mp_obj_t py_image_imagereader(mp_obj_t path) obj->ms = systick_current_millis(); return obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagereader_obj, py_image_imagereader); mp_obj_t py_image(int w, int h, int bpp, void *pixels) { @@ -5017,6 +4930,7 @@ mp_obj_t py_image_rgb_to_lab(mp_obj_t tuple) mp_obj_new_int(lab_color.A), mp_obj_new_int(lab_color.B)}); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_lab_obj, py_image_rgb_to_lab); mp_obj_t py_image_lab_to_rgb(mp_obj_t tuple) { @@ -5034,6 +4948,7 @@ mp_obj_t py_image_lab_to_rgb(mp_obj_t tuple) mp_obj_new_int(rgb_color.green), mp_obj_new_int(rgb_color.blue)}); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_lab_to_rgb_obj, py_image_lab_to_rgb); mp_obj_t py_image_rgb_to_grayscale(mp_obj_t tuple) { @@ -5048,6 +4963,7 @@ mp_obj_t py_image_rgb_to_grayscale(mp_obj_t tuple) return mp_obj_new_int(grayscale_color.G); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_grayscale_obj, py_image_rgb_to_grayscale); mp_obj_t py_image_grayscale_to_rgb(mp_obj_t not_tuple) { @@ -5060,13 +4976,15 @@ mp_obj_t py_image_grayscale_to_rgb(mp_obj_t not_tuple) mp_obj_new_int(rgb_color.green), mp_obj_new_int(rgb_color.blue)}); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_grayscale_to_rgb_obj, py_image_grayscale_to_rgb); mp_obj_t py_image_load_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - bool copy_to_fb = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false); + const char *path = mp_obj_str_get_str(args[0]); + + bool copy_to_fb = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_copy_to_fb), false); if (copy_to_fb) fb_update_jpeg_buffer(); - const char *path = mp_obj_str_get_str(args[0]); image_t image = {0}; if (copy_to_fb) { @@ -5083,15 +5001,16 @@ mp_obj_t py_image_load_image(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg uint32_t size = image_size(&image); PY_ASSERT_TRUE_MSG((size <= OMV_RAW_BUF_SIZE), "FB Overflow!"); - image.pixels = MAIN_FB()->pixels; MAIN_FB()->w = image.w; MAIN_FB()->h = image.h; MAIN_FB()->bpp = image.bpp; + image.data = MAIN_FB()->pixels; } imlib_load_image(&image, path); return py_image_from_struct(&image); } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_image_obj, 1, py_image_load_image); mp_obj_t py_image_load_cascade(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -5105,7 +5024,7 @@ mp_obj_t py_image_load_cascade(uint n_args, const mp_obj_t *args, mp_map_t *kw_a } // Read the number of stages - int stages = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("stages")), cascade.n_stages); + int stages = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("stages")), cascade.n_stages); // Check the number of stages if (stages > 0 && stages < cascade.n_stages) { cascade.n_stages = stages; @@ -5117,6 +5036,7 @@ mp_obj_t py_image_load_cascade(uint n_args, const mp_obj_t *args, mp_map_t *kw_a o->_cobj = cascade; return o; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_cascade); mp_obj_t py_image_load_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -5181,6 +5101,7 @@ error: } return desc; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 1, py_image_load_descriptor); mp_obj_t py_image_save_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -5231,6 +5152,7 @@ error: } return mp_const_true; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 2, py_image_save_descriptor); static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -5252,8 +5174,8 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_ } else if (desc1_type == &py_kp_type) { py_kp_obj_t *kpts1 = ((py_kp_obj_t*)args[0]); py_kp_obj_t *kpts2 = ((py_kp_obj_t*)args[1]); - int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 85); - int filter_outliers = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_filter_outliers), false); + int threshold = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 85); + int filter_outliers = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_filter_outliers), false); // Sanity checks PY_ASSERT_TYPE(kpts1, &py_kp_type); @@ -5308,6 +5230,7 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_ return match_obj; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 2, py_image_match_descriptor); int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) { @@ -5331,70 +5254,56 @@ int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *ro return 0; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagewriter_obj, py_image_imagewriter); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_imagereader_obj, py_image_imagereader); -/* Color space functions */ -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_lab_obj, py_image_rgb_to_lab); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_lab_to_rgb_obj, py_image_lab_to_rgb); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_grayscale_obj, py_image_rgb_to_grayscale); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_grayscale_to_rgb_obj, py_image_grayscale_to_rgb); -/* Image Module Functions */ -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_image_obj, 1, py_image_load_image); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_cascade); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 1, py_image_load_descriptor); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 2, py_image_save_descriptor); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 2, py_image_match_descriptor); -static const mp_map_elem_t globals_dict_table[] = { - {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_SEARCH_EX), MP_OBJ_NEW_SMALL_INT(SEARCH_EX)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_SEARCH_DS), MP_OBJ_NEW_SMALL_INT(SEARCH_DS)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_CANNY), MP_OBJ_NEW_SMALL_INT(EDGE_CANNY)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_SIMPLE), MP_OBJ_NEW_SMALL_INT(EDGE_SIMPLE)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CORNER_FAST), MP_OBJ_NEW_SMALL_INT(CORNER_FAST)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CORNER_AGAST), MP_OBJ_NEW_SMALL_INT(CORNER_AGAST)}, +static const mp_rom_map_elem_t globals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image)}, + {MP_ROM_QSTR(MP_QSTR_SEARCH_EX), MP_ROM_INT(SEARCH_EX)}, + {MP_ROM_QSTR(MP_QSTR_SEARCH_DS), MP_ROM_INT(SEARCH_DS)}, + {MP_ROM_QSTR(MP_QSTR_EDGE_CANNY), MP_ROM_INT(EDGE_CANNY)}, + {MP_ROM_QSTR(MP_QSTR_EDGE_SIMPLE), MP_ROM_INT(EDGE_SIMPLE)}, + {MP_ROM_QSTR(MP_QSTR_CORNER_FAST), MP_ROM_INT(CORNER_FAST)}, + {MP_ROM_QSTR(MP_QSTR_CORNER_AGAST), MP_ROM_INT(CORNER_AGAST)}, #ifdef IMLIB_ENABLE_APRILTAGS - {MP_OBJ_NEW_QSTR(MP_QSTR_TAG16H5), MP_OBJ_NEW_SMALL_INT(TAG16H5)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TAG25H7), MP_OBJ_NEW_SMALL_INT(TAG25H7)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TAG25H9), MP_OBJ_NEW_SMALL_INT(TAG25H9)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TAG36H10), MP_OBJ_NEW_SMALL_INT(TAG36H10)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TAG36H11), MP_OBJ_NEW_SMALL_INT(TAG36H11)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ARTOOLKIT), MP_OBJ_NEW_SMALL_INT(ARTOOLKIT)}, + {MP_ROM_QSTR(MP_QSTR_TAG16H5), MP_ROM_INT(TAG16H5)}, + {MP_ROM_QSTR(MP_QSTR_TAG25H7), MP_ROM_INT(TAG25H7)}, + {MP_ROM_QSTR(MP_QSTR_TAG25H9), MP_ROM_INT(TAG25H9)}, + {MP_ROM_QSTR(MP_QSTR_TAG36H10), MP_ROM_INT(TAG36H10)}, + {MP_ROM_QSTR(MP_QSTR_TAG36H11), MP_ROM_INT(TAG36H11)}, + {MP_ROM_QSTR(MP_QSTR_ARTOOLKIT), MP_ROM_INT(ARTOOLKIT)}, #endif #ifdef IMLIB_ENABLE_BARCODES - {MP_OBJ_NEW_QSTR(MP_QSTR_EAN2), MP_OBJ_NEW_SMALL_INT(BARCODE_EAN2)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_EAN5), MP_OBJ_NEW_SMALL_INT(BARCODE_EAN5)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_EAN8), MP_OBJ_NEW_SMALL_INT(BARCODE_EAN8)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_UPCE), MP_OBJ_NEW_SMALL_INT(BARCODE_UPCE)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ISBN10), MP_OBJ_NEW_SMALL_INT(BARCODE_ISBN10)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_UPCA), MP_OBJ_NEW_SMALL_INT(BARCODE_UPCA)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_EAN13), MP_OBJ_NEW_SMALL_INT(BARCODE_EAN13)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ISBN13), MP_OBJ_NEW_SMALL_INT(BARCODE_ISBN13)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_I25), MP_OBJ_NEW_SMALL_INT(BARCODE_I25)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_DATABAR), MP_OBJ_NEW_SMALL_INT(BARCODE_DATABAR)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_DATABAR_EXP), MP_OBJ_NEW_SMALL_INT(BARCODE_DATABAR_EXP)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CODABAR), MP_OBJ_NEW_SMALL_INT(BARCODE_CODABAR)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CODE39), MP_OBJ_NEW_SMALL_INT(BARCODE_CODE39)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_PDF417), MP_OBJ_NEW_SMALL_INT(BARCODE_PDF417)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CODE93), MP_OBJ_NEW_SMALL_INT(BARCODE_CODE93)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_CODE128), MP_OBJ_NEW_SMALL_INT(BARCODE_CODE128)}, + {MP_ROM_QSTR(MP_QSTR_EAN2), MP_ROM_INT(BARCODE_EAN2)}, + {MP_ROM_QSTR(MP_QSTR_EAN5), MP_ROM_INT(BARCODE_EAN5)}, + {MP_ROM_QSTR(MP_QSTR_EAN8), MP_ROM_INT(BARCODE_EAN8)}, + {MP_ROM_QSTR(MP_QSTR_UPCE), MP_ROM_INT(BARCODE_UPCE)}, + {MP_ROM_QSTR(MP_QSTR_ISBN10), MP_ROM_INT(BARCODE_ISBN10)}, + {MP_ROM_QSTR(MP_QSTR_UPCA), MP_ROM_INT(BARCODE_UPCA)}, + {MP_ROM_QSTR(MP_QSTR_EAN13), MP_ROM_INT(BARCODE_EAN13)}, + {MP_ROM_QSTR(MP_QSTR_ISBN13), MP_ROM_INT(BARCODE_ISBN13)}, + {MP_ROM_QSTR(MP_QSTR_I25), MP_ROM_INT(BARCODE_I25)}, + {MP_ROM_QSTR(MP_QSTR_DATABAR), MP_ROM_INT(BARCODE_DATABAR)}, + {MP_ROM_QSTR(MP_QSTR_DATABAR_EXP), MP_ROM_INT(BARCODE_DATABAR_EXP)}, + {MP_ROM_QSTR(MP_QSTR_CODABAR), MP_ROM_INT(BARCODE_CODABAR)}, + {MP_ROM_QSTR(MP_QSTR_CODE39), MP_ROM_INT(BARCODE_CODE39)}, + {MP_ROM_QSTR(MP_QSTR_PDF417), MP_ROM_INT(BARCODE_PDF417)}, + {MP_ROM_QSTR(MP_QSTR_CODE93), MP_ROM_INT(BARCODE_CODE93)}, + {MP_ROM_QSTR(MP_QSTR_CODE128), MP_ROM_INT(BARCODE_CODE128)}, #endif - {MP_OBJ_NEW_QSTR(MP_QSTR_ImageWriter), (mp_obj_t)&py_image_imagewriter_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ImageReader), (mp_obj_t)&py_image_imagereader_obj}, - /* Color space functions */ - {MP_OBJ_NEW_QSTR(MP_QSTR_rgb_to_lab), (mp_obj_t)&py_image_rgb_to_lab_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_lab_to_rgb), (mp_obj_t)&py_image_lab_to_rgb_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_rgb_to_grayscale), (mp_obj_t)&py_image_rgb_to_grayscale_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_grayscale_to_rgb), (mp_obj_t)&py_image_grayscale_to_rgb_obj}, - /* Image Module Functions */ - {MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)&py_image_load_image_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_HaarCascade), (mp_obj_t)&py_image_load_cascade_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_load_descriptor), (mp_obj_t)&py_image_load_descriptor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_save_descriptor), (mp_obj_t)&py_image_save_descriptor_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_match_descriptor), (mp_obj_t)&py_image_match_descriptor_obj}, + {MP_ROM_QSTR(MP_QSTR_ImageWriter), MP_ROM_PTR(&py_image_imagewriter_obj)}, + {MP_ROM_QSTR(MP_QSTR_ImageReader), MP_ROM_PTR(&py_image_imagereader_obj)}, + {MP_ROM_QSTR(MP_QSTR_rgb_to_lab), MP_ROM_PTR(&py_image_rgb_to_lab_obj)}, + {MP_ROM_QSTR(MP_QSTR_lab_to_rgb), MP_ROM_PTR(&py_image_lab_to_rgb_obj)}, + {MP_ROM_QSTR(MP_QSTR_rgb_to_grayscale), MP_ROM_PTR(&py_image_rgb_to_grayscale_obj)}, + {MP_ROM_QSTR(MP_QSTR_grayscale_to_rgb), MP_ROM_PTR(&py_image_grayscale_to_rgb_obj)}, + {MP_ROM_QSTR(MP_QSTR_Image), MP_ROM_PTR(&py_image_load_image_obj)}, + {MP_ROM_QSTR(MP_QSTR_HaarCascade), MP_ROM_PTR(&py_image_load_cascade_obj)}, + {MP_ROM_QSTR(MP_QSTR_load_descriptor), MP_ROM_PTR(&py_image_load_descriptor_obj)}, + {MP_ROM_QSTR(MP_QSTR_save_descriptor), MP_ROM_PTR(&py_image_save_descriptor_obj)}, + {MP_ROM_QSTR(MP_QSTR_match_descriptor), MP_ROM_PTR(&py_image_match_descriptor_obj)} }; + STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); const mp_obj_module_t image_module = { .base = { &mp_type_module }, - .globals = (mp_obj_t)&globals_dict, + .globals = (mp_obj_t) &globals_dict }; diff --git a/src/omv/py/py_lcd.c b/src/omv/py/py_lcd.c index dd4b9006e..e2a34f879 100644 --- a/src/omv/py/py_lcd.c +++ b/src/omv/py/py_lcd.c @@ -151,7 +151,7 @@ static mp_obj_t py_lcd_deinit() static mp_obj_t py_lcd_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { py_lcd_deinit(); - switch (py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), LCD_SHIELD)) { + switch (py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_type), LCD_SHIELD)) { case LCD_NONE: return mp_const_none; case LCD_SHIELD: @@ -278,10 +278,8 @@ static mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_a image_t *arg_img = py_image_cobj(args[0]); PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); - rectangle_t arg_r; - py_helper_lookup_rectangle(kw_args, arg_img, &arg_r); rectangle_t rect; - if (!rectangle_subimg(arg_img, &arg_r, &rect)) ff_no_intersection(NULL); + py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &rect); // Fit X. int l_pad = 0, r_pad = 0; diff --git a/src/omv/py/py_mjpeg.c b/src/omv/py/py_mjpeg.c index 01c100f54..4d856d96e 100644 --- a/src/omv/py/py_mjpeg.c +++ b/src/omv/py/py_mjpeg.c @@ -28,8 +28,8 @@ typedef struct py_mjpeg_obj { static mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { py_mjpeg_obj_t *mjpeg = m_new_obj(py_mjpeg_obj_t); - mjpeg->width = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); - mjpeg->height = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); + mjpeg->width = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), MAIN_FB()->w); + mjpeg->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h); mjpeg->frames = 0; // private mjpeg->bytes = 0; // private mjpeg->base.type = &py_mjpeg_type; @@ -65,7 +65,7 @@ static mp_obj_t py_mjpeg_add_frame(uint n_args, const mp_obj_t *args, mp_map_t * || (arg_mjpeg->height != arg_img->h), "Unexpected image geometry"); - int arg_q = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); + int arg_q = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_quality), 50); arg_q = IM_MIN(IM_MAX(arg_q, 1), 100); mjpeg_add_frame(&arg_mjpeg->fp, &arg_mjpeg->frames, &arg_mjpeg->bytes, arg_img, arg_q); return mp_const_none; diff --git a/src/omv/py/py_sensor.c b/src/omv/py/py_sensor.c index 61fcd4c35..593d97cc9 100644 --- a/src/omv/py/py_sensor.c +++ b/src/omv/py/py_sensor.c @@ -346,8 +346,8 @@ static mp_obj_t py_sensor_set_colorbar(mp_obj_t enable) { static mp_obj_t py_sensor_set_auto_gain(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { int enable = mp_obj_get_int(args[0]); - float gain_db = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), NAN); - float gain_db_ceiling = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db_ceiling), NAN); + float gain_db = py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db), NAN); + float gain_db_ceiling = py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gain_db_ceiling), NAN); if (sensor_set_auto_gain(enable, gain_db, gain_db_ceiling) != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); } @@ -363,7 +363,7 @@ static mp_obj_t py_sensor_get_gain_db() { } static mp_obj_t py_sensor_set_auto_exposure(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - int exposure_us = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_exposure_us), -1); + int exposure_us = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_exposure_us), -1); if (sensor_set_auto_exposure(mp_obj_get_int(args[0]), exposure_us) != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); } @@ -381,7 +381,7 @@ static mp_obj_t py_sensor_get_exposure_us() { static mp_obj_t py_sensor_set_auto_whitebal(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { int enable = mp_obj_get_int(args[0]); float rgb_gain_db[3] = {NAN, NAN, NAN}; - py_helper_lookup_float_array(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_gain_db), rgb_gain_db, 3); + py_helper_keyword_float_array(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rgb_gain_db), rgb_gain_db, 3); if (sensor_set_auto_whitebal(enable, rgb_gain_db[0], rgb_gain_db[1], rgb_gain_db[2]) != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sensor control failed!")); } diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index 8cb33c393..e57e80b8c 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -39,6 +39,7 @@ Q(height) Q(format) Q(size) Q(get_pixel) +Q(rgbtuple) Q(set_pixel) Q(draw_line) Q(draw_rectangle)