diff --git a/src/omv/img/binary.c b/src/omv/img/binary.c index e14830f9b..94ecc07d5 100644 --- a/src/omv/img/binary.c +++ b/src/omv/img/binary.c @@ -6,6 +6,51 @@ #include "imlib.h" #ifdef IMLIB_ENABLE_BINARY_OPS +void imlib_zero(image_t *img, image_t *mask, bool invert) +{ + switch(img->bpp) { + case IMAGE_BPP_BINARY: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); + uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(mask, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(row_ptr_2, x) ^ invert) { + IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + case IMAGE_BPP_GRAYSCALE: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); + uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(mask, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(row_ptr_2, x) ^ invert) { + IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + case IMAGE_BPP_RGB565: { + for (int y = 0, yy = img->h; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); + uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(mask, y); + for (int x = 0, xx = img->w; x < xx; x++) { + if (IMAGE_GET_BINARY_PIXEL_FAST(row_ptr_2, x) ^ invert) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + default: { + break; + } + } +} + void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask) { image_t bmp; @@ -17,6 +62,7 @@ void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, b for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) { color_thresholds_list_lnk_data_t lnk_data; iterator_get(thresholds, it, &lnk_data); + switch(img->bpp) { case IMAGE_BPP_BINARY: { for (int y = 0, yy = img->h; y < yy; y++) { diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index d804fd8fc..6d592fce4 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -1267,6 +1267,7 @@ void imlib_flood_fill(image_t *img, int x, int y, float seed_threshold, float floating_threshold, int c, bool invert, bool clear_background, image_t *mask); // Binary Functions +void imlib_zero(image_t *img, image_t *mask, bool invert); void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask); void imlib_invert(image_t *img); void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask); diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index 1434dfad5..e0a45a771 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1892,6 +1892,125 @@ STATIC mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_ma } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints); +STATIC mp_obj_t py_image_mask_rectangle(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_rx; + int arg_ry; + int arg_rw; + int arg_rh; + + if (n_args > 1) { + const mp_obj_t *arg_vec; + py_helper_consume_array(n_args, args, 1, 4, &arg_vec); + arg_rx = mp_obj_get_int(arg_vec[0]); + arg_ry = mp_obj_get_int(arg_vec[1]); + arg_rw = mp_obj_get_int(arg_vec[2]); + arg_rh = mp_obj_get_int(arg_vec[3]); + } else { + arg_rx = arg_img->w / 4; + arg_ry = arg_img->h / 4; + arg_rw = arg_img->w / 2; + arg_rh = arg_img->h / 2; + } + + fb_alloc_mark(); + image_t temp; + temp.w = arg_img->w; + temp.h = arg_img->h; + temp.bpp = IMAGE_BPP_BINARY; + temp.data = fb_alloc0(image_size(&temp)); + + imlib_draw_rectangle(&temp, arg_rx, arg_ry, arg_rw, arg_rh, -1, 0, true); + imlib_zero(arg_img, &temp, true); + + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_rectangle_obj, 1, py_image_mask_rectangle); + +STATIC mp_obj_t py_image_mask_circle(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_cx; + int arg_cy; + int arg_cr; + + if (n_args > 1) { + const mp_obj_t *arg_vec; + py_helper_consume_array(n_args, args, 1, 3, &arg_vec); + arg_cx = mp_obj_get_int(arg_vec[0]); + arg_cy = mp_obj_get_int(arg_vec[1]); + arg_cr = mp_obj_get_int(arg_vec[2]); + } else { + arg_cx = arg_img->w / 2; + arg_cy = arg_img->h / 2; + arg_cr = IM_MIN(arg_img->w, arg_img->h) / 2; + } + + fb_alloc_mark(); + image_t temp; + temp.w = arg_img->w; + temp.h = arg_img->h; + temp.bpp = IMAGE_BPP_BINARY; + temp.data = fb_alloc0(image_size(&temp)); + + imlib_draw_circle(&temp, arg_cx, arg_cy, arg_cr, -1, 0, true); + imlib_zero(arg_img, &temp, true); + + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_circle_obj, 1, py_image_mask_circle); + +STATIC mp_obj_t py_image_mask_ellipse(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]); + uint offset; + int arg_cx; + int arg_cy; + int arg_rx; + int arg_ry; + int arg_r; + + if (n_args > 1) { + const mp_obj_t *arg_vec; + offset = py_helper_consume_array(n_args, args, 1, 5, &arg_vec); + arg_cx = mp_obj_get_int(arg_vec[0]); + arg_cy = mp_obj_get_int(arg_vec[1]); + arg_rx = mp_obj_get_int(arg_vec[2]); + arg_ry = mp_obj_get_int(arg_vec[3]); + arg_r = mp_obj_get_int(arg_vec[4]); + } else { + offset = 1; + arg_cx = arg_img->w / 2; + arg_cy = arg_img->h / 2; + arg_rx = arg_img->w / 2; + arg_ry = arg_img->h / 2; + arg_r = 0; + } + + int arg_rotation = + py_helper_keyword_int(n_args, args, offset, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rotation), arg_r); + + fb_alloc_mark(); + image_t temp; + temp.w = arg_img->w; + temp.h = arg_img->h; + temp.bpp = IMAGE_BPP_BINARY; + temp.data = fb_alloc0(image_size(&temp)); + + imlib_draw_ellipse(&temp, arg_cx, arg_cy, arg_rx, arg_ry, arg_rotation, -1, 0, true); + imlib_zero(arg_img, &temp, true); + + fb_free(); + fb_alloc_free_till_mark(); + return args[0]; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_ellipse_obj, 1, py_image_mask_ellipse); + #ifdef IMLIB_ENABLE_FLOOD_FILL STATIC mp_obj_t py_image_flood_fill(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -6215,6 +6334,9 @@ static const mp_rom_map_elem_t locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_flood_fill), MP_ROM_PTR(&py_func_unavailable_obj)}, #endif {MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)}, + {MP_ROM_QSTR(MP_QSTR_mask_rectangle), MP_ROM_PTR(&py_image_mask_rectangle_obj)}, + {MP_ROM_QSTR(MP_QSTR_mask_circle), MP_ROM_PTR(&py_image_mask_circle_obj)}, + {MP_ROM_QSTR(MP_QSTR_mask_ellipse), MP_ROM_PTR(&py_image_mask_ellipse_obj)}, /* Binary Methods */ #ifdef IMLIB_ENABLE_BINARY_OPS {MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)}, diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index 5c8c20d60..1fec57a58 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -506,6 +506,16 @@ Q(invert) Q(clear_background) // duplicate Q(mask) +// Mask Rectangle +Q(mask_rectangle) + +// Mask Circle +Q(mask_circle) + +// Mask Ellipse +Q(mask_ellipse) +// duplicate Q(rotation) + // Binary Q(binary) // duplicate Q(invert)