From e0e112468ead61d33f8ab31e0ba6f8f3ca2f438e Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 5 Mar 2018 00:49:36 -0500 Subject: [PATCH] Argument Parsing Done Correctly All of our argument parsing code has now been updated to handle positional as well as keyword arguments in our python libraries. Basically, python allows you to pass some number of positional arguments to functions/methods followed by keyword arguments (you cannot have more positional arguments after keyword arguments). Previously, our code would only look for keyword arguments. Now, it works better and will grab as many positional arguments as it can followed by processing keyword arguments. Note: If the case of a positional argument value for a parameter being passed followed by a keyword for that same parameter the keyword value is taken (since it comes aftward). Because arguments were passed in keyword form before this update has no affect on current code. However, moving forward, argument positions are now locked and cannot be moved around. --- src/omv/img/imlib.h | 20 + src/omv/py/py_assert.h | 1 + src/omv/py/py_fir.c | 26 +- src/omv/py/py_gif.c | 10 +- src/omv/py/py_helper.c | 356 +++-- src/omv/py/py_helper.h | 48 +- src/omv/py/py_image.c | 2865 ++++++++++++++++++-------------------- src/omv/py/py_lcd.c | 6 +- src/omv/py/py_mjpeg.c | 6 +- src/omv/py/py_sensor.c | 8 +- src/omv/py/qstrdefsomv.h | 1 + 11 files changed, 1707 insertions(+), 1640 deletions(-) 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)