From 1f72c3750dcedfeff1acec63806118bb5d835417 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 11 Feb 2019 00:35:24 -0500 Subject: [PATCH 1/7] Add back mask methods. --- src/omv/img/binary.c | 46 +++++++++++++++ src/omv/img/imlib.h | 1 + src/omv/py/py_image.c | 122 +++++++++++++++++++++++++++++++++++++++ src/omv/py/qstrdefsomv.h | 10 ++++ 4 files changed, 179 insertions(+) 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) From 954431ef529b04de75d161fa051a8c51de8daa99 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 11 Feb 2019 01:02:28 -0500 Subject: [PATCH 2/7] Add mask functionality to clear. --- src/omv/img/binary.c | 46 ---------------------------------------- src/omv/img/imlib.c | 42 ++++++++++++++++++++++++++++++++++++ src/omv/img/imlib.h | 2 +- src/omv/py/py_image.c | 17 ++++++++++----- src/omv/py/qstrdefsomv.h | 3 ++- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/src/omv/img/binary.c b/src/omv/img/binary.c index 94ecc07d5..e14830f9b 100644 --- a/src/omv/img/binary.c +++ b/src/omv/img/binary.c @@ -6,51 +6,6 @@ #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; @@ -62,7 +17,6 @@ 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.c b/src/omv/img/imlib.c index fbe1b975e..369153d57 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -755,6 +755,48 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual //////////////////////////////////////////////////////////////////////////////// +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); + for (int x = 0, xx = img->w; x < xx; x++) { + if (image_get_mask_pixel(mask, x, y) ^ 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); + for (int x = 0, xx = img->w; x < xx; x++) { + if (image_get_mask_pixel(mask, x, y) ^ 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); + for (int x = 0, xx = img->w; x < xx; x++) { + if (image_get_mask_pixel(mask, x, y) ^ invert) { + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, 0); + } + } + } + break; + } + default: { + break; + } + } +} + // A simple algorithm for correcting lens distortion. // See http://www.tannerhelland.com/4743/simple-algorithm-correcting-lens-distortion/ void imlib_lens_corr(image_t *img, float strength, float zoom) diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index 6d592fce4..7dba9b61f 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -1251,6 +1251,7 @@ void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_t void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size); // Helper Functions +void imlib_zero(image_t *img, image_t *mask, bool invert); void imlib_flood_fill_int(image_t *out, image_t *img, int x, int y, int seed_threshold, int floating_threshold, flood_fill_call_back_t cb, void *data); @@ -1267,7 +1268,6 @@ 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 e0a45a771..5c918d941 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1578,13 +1578,20 @@ 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) +STATIC mp_obj_t py_image_clear(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - 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; + image_t *arg_img = py_helper_arg_to_image_mutable_bayer(args[0]); + image_t *arg_msk = py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args); + + if (!arg_msk) { + memset(arg_img->data, 0, image_size(arg_img)); + } else { + imlib_zero(arg_img, arg_msk, false); + } + + return args[0]; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_clear_obj, py_image_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_clear_obj, 1, py_image_clear); STATIC mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index 1fec57a58..c88270b29 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -431,6 +431,7 @@ Q(save) // Clear Q(clear) +Q(mask) // Draw Line Q(draw_line) @@ -488,7 +489,7 @@ Q(draw_image) // duplicate Q(x_scale) // duplicate Q(y_scale) Q(alpha) -Q(mask) +// duplicate Q(mask) // Draw Keypoints Q(draw_keypoints) From ca94ffec424614ad0a53790a737e8d25302d5d0d Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 11 Feb 2019 01:34:45 -0500 Subject: [PATCH 3/7] Avoid using roundf While this shouldn't happen the method seems to sometimes round up past limits. For example, 1 * 2.0 could be 3 because the 2.0 might be like 2.0000000000001. So, avoid using roundf. There are other methods this needs to be switched out on. But, will do these ones for now. Note that not all roundf values must be removed... just areas where there's a clear limit on the max value returned from roundf. --- src/omv/img/draw.c | 54 +++++++++++++++++----------------- src/omv/img/filter.c | 68 +++++++++++++++++++++---------------------- src/omv/img/imlib.c | 24 +++++++-------- src/omv/py/py_image.c | 16 +++++----- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/omv/img/draw.c b/src/omv/img/draw.c index 6982ec9eb..e1b8acf60 100644 --- a/src/omv/img/draw.c +++ b/src/omv/img/draw.c @@ -280,17 +280,17 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int if ((ch == '\n') || (ch == '\r')) { // handle '\n' or '\r' strings x_off = anchor; - y_off += fast_roundf(font[0].h * scale) + y_spacing; // newline height == space height + y_off += fast_floorf(font[0].h * scale) + y_spacing; // newline height == space height continue; } if ((ch < ' ') || (ch > '~')) { // handle unknown characters imlib_draw_rectangle(img, - x_off + (fast_roundf(scale * 3) / 2), - y_off + (fast_roundf(scale * 3) / 2), - fast_roundf(font[0].w * scale) - ((fast_roundf(scale * 3) / 2) * 2), - fast_roundf(font[0].h * scale) - ((fast_roundf(scale * 3) / 2) * 2), - c, fast_roundf(scale), false); + x_off + (fast_floorf(scale * 3) / 2), + y_off + (fast_floorf(scale * 3) / 2), + fast_floorf(font[0].w * scale) - ((fast_floorf(scale * 3) / 2) * 2), + fast_floorf(font[0].h * scale) - ((fast_floorf(scale * 3) / 2) * 2), + c, fast_floorf(scale), false); continue; } @@ -303,7 +303,7 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int for (int x = 0, xx = g->w; x < xx; x++) { for (int y = 0, yy = g->h; y < yy; y++) { if (g->data[y] & (1 << (g->w - 1 - x))) { - x_off -= fast_roundf(x * scale); + x_off -= fast_floorf(x * scale); exit = true; break; } @@ -313,16 +313,16 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int } } - for (int y = 0, yy = fast_roundf(g->h * scale); y < yy; y++) { - for (int x = 0, xx = fast_roundf(g->w * scale); x < xx; x++) { - if (g->data[fast_roundf(y / scale)] & (1 << (g->w - 1 - fast_roundf(x / scale)))) { + for (int y = 0, yy = fast_floorf(g->h * scale); y < yy; y++) { + for (int x = 0, xx = fast_floorf(g->w * scale); x < xx; x++) { + if (g->data[fast_floorf(y / scale)] & (1 << (g->w - 1 - fast_floorf(x / scale)))) { imlib_set_pixel(img, (x_off + x), (y_off + y), c); } } } if (mono_space) { - x_off += fast_roundf(g->w * scale) + x_spacing; + x_off += fast_floorf(g->w * scale) + x_spacing; } else { // Find the last pixel set and offset to that. bool exit = false; @@ -330,7 +330,7 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int for (int x = g->w - 1; x >= 0; x--) { for (int y = g->h - 1; y >= 0; y--) { if (g->data[y] & (1 << (g->w - 1 - x))) { - x_off += fast_roundf((x + 2) * scale) + x_spacing; + x_off += fast_floorf((x + 2) * scale) + x_spacing; exit = true; break; } @@ -339,7 +339,7 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int if (exit) break; } - if (!exit) x_off += fast_roundf(scale * 3); // space char + if (!exit) x_off += fast_floorf(scale * 3); // space char } } } @@ -405,11 +405,11 @@ void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float { float over_xscale = IM_DIV(1.0, x_scale), over_yscale = IM_DIV(1.0f, y_scale), beta = 1 - alpha; - for (int y = 0, yy = fast_roundf(other->h * y_scale); y < yy; y++) { - int other_y = fast_roundf(y * over_yscale); + for (int y = 0, yy = fast_floorf(other->h * y_scale); y < yy; y++) { + int other_y = fast_floorf(y * over_yscale); - for (int x = 0, xx = fast_roundf(other->w * x_scale); x < xx; x++) { - int other_x = fast_roundf(x * over_xscale); + for (int x = 0, xx = fast_floorf(other->w * x_scale); x < xx; x++) { + int other_x = fast_floorf(x * over_xscale); if ((!mask) || image_get_mask_pixel(mask, other_x, other_y)) { int pixel = safe_map_pixel(img, other, imlib_get_pixel(other, other_x, other_y)); @@ -446,22 +446,22 @@ void imlib_flood_fill(image_t *img, int x, int y, switch(img->bpp) { case IMAGE_BPP_BINARY: { - color_seed_threshold = fast_roundf(seed_threshold * COLOR_BINARY_MAX); - color_floating_threshold = fast_roundf(floating_threshold * COLOR_BINARY_MAX); + color_seed_threshold = fast_floorf(seed_threshold * COLOR_BINARY_MAX); + color_floating_threshold = fast_floorf(floating_threshold * COLOR_BINARY_MAX); break; } case IMAGE_BPP_GRAYSCALE: { - color_seed_threshold = fast_roundf(seed_threshold * COLOR_GRAYSCALE_MAX); - color_floating_threshold = fast_roundf(floating_threshold * COLOR_GRAYSCALE_MAX); + color_seed_threshold = fast_floorf(seed_threshold * COLOR_GRAYSCALE_MAX); + color_floating_threshold = fast_floorf(floating_threshold * COLOR_GRAYSCALE_MAX); break; } case IMAGE_BPP_RGB565: { - color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(seed_threshold * COLOR_R5_MAX), - fast_roundf(seed_threshold * COLOR_G6_MAX), - fast_roundf(seed_threshold * COLOR_B5_MAX)); - color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(floating_threshold * COLOR_R5_MAX), - fast_roundf(floating_threshold * COLOR_G6_MAX), - fast_roundf(floating_threshold * COLOR_B5_MAX)); + color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(seed_threshold * COLOR_R5_MAX), + fast_floorf(seed_threshold * COLOR_G6_MAX), + fast_floorf(seed_threshold * COLOR_B5_MAX)); + color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(floating_threshold * COLOR_R5_MAX), + fast_floorf(floating_threshold * COLOR_G6_MAX), + fast_floorf(floating_threshold * COLOR_B5_MAX)); break; } default: { diff --git a/src/omv/img/filter.c b/src/omv/img/filter.c index b5b2e3038..7b34beb4c 100644 --- a/src/omv/img/filter.c +++ b/src/omv/img/filter.c @@ -32,7 +32,7 @@ void imlib_histeq(image_t *img, image_t *mask) if (mask && (!image_get_mask_pixel(mask, x, y))) continue; int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x); IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, - fast_roundf((s * hist[pixel - COLOR_BINARY_MIN]) + COLOR_BINARY_MIN)); + fast_floorf((s * hist[pixel - COLOR_BINARY_MIN]) + COLOR_BINARY_MIN)); } } @@ -62,7 +62,7 @@ void imlib_histeq(image_t *img, image_t *mask) if (mask && (!image_get_mask_pixel(mask, x, y))) continue; int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x); IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, - fast_roundf((s * hist[pixel - COLOR_GRAYSCALE_MIN]) + COLOR_GRAYSCALE_MIN)); + fast_floorf((s * hist[pixel - COLOR_GRAYSCALE_MIN]) + COLOR_GRAYSCALE_MIN)); } } @@ -92,7 +92,7 @@ void imlib_histeq(image_t *img, image_t *mask) if (mask && (!image_get_mask_pixel(mask, x, y))) continue; int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, - imlib_yuv_to_rgb(fast_roundf(s * hist[COLOR_RGB565_TO_Y(pixel) - COLOR_Y_MIN]), + imlib_yuv_to_rgb(fast_floorf(s * hist[COLOR_RGB565_TO_Y(pixel) - COLOR_Y_MIN]), COLOR_RGB565_TO_U(pixel), COLOR_RGB565_TO_V(pixel))); } @@ -149,7 +149,7 @@ void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset } } - int pixel = fast_roundf(acc * over_n); + int pixel = fast_floorf(acc * over_n); if (threshold) { if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -204,7 +204,7 @@ void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset } } - int pixel = fast_roundf(acc * over_n); + int pixel = fast_floorf(acc * over_n); if (threshold) { if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -262,9 +262,9 @@ void imlib_mean_filter(image_t *img, const int ksize, bool threshold, int offset } } - int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(r_acc * over_n), - fast_roundf(g_acc * over_n), - fast_roundf(b_acc * over_n)); + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(r_acc * over_n), + fast_floorf(g_acc * over_n), + fast_floorf(b_acc * over_n)); if (threshold) { if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { @@ -310,7 +310,7 @@ void imlib_median_filter(image_t *img, const int ksize, float percentile, bool t buf.h = brows; buf.bpp = img->bpp; - int n = ((ksize*2)+1)*((ksize*2)+1), int_percentile = fast_roundf(percentile * (n - 1)); + int n = ((ksize*2)+1)*((ksize*2)+1), int_percentile = fast_floorf(percentile * (n - 1)); switch(img->bpp) { case IMAGE_BPP_BINARY: { @@ -782,7 +782,7 @@ void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool thres } } - int pixel = fast_roundf((min*min_bias)+(max*max_bias)); + int pixel = fast_floorf((min*min_bias)+(max*max_bias)); if (threshold) { if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -839,7 +839,7 @@ void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool thres } } - int pixel = fast_roundf((min*min_bias)+(max*max_bias)); + int pixel = fast_floorf((min*min_bias)+(max*max_bias)); if (threshold) { if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -905,9 +905,9 @@ void imlib_midpoint_filter(image_t *img, const int ksize, float bias, bool thres } } - int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf((r_min*min_bias)+(r_max*max_bias)), - fast_roundf((g_min*min_bias)+(g_max*max_bias)), - fast_roundf((b_min*min_bias)+(b_max*max_bias))); + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_floorf((r_min*min_bias)+(r_max*max_bias)), + fast_floorf((g_min*min_bias)+(g_max*max_bias)), + fast_floorf((b_min*min_bias)+(b_max*max_bias))); if (threshold) { if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { @@ -980,7 +980,7 @@ void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, c } } - int pixel = IM_MAX(IM_MIN(fast_roundf(acc * m) + b, COLOR_BINARY_MAX), COLOR_BINARY_MIN); + int pixel = IM_MAX(IM_MIN(fast_floorf(acc * m) + b, COLOR_BINARY_MAX), COLOR_BINARY_MIN); if (threshold) { if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -1035,7 +1035,7 @@ void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, c } } - int pixel = IM_MAX(IM_MIN(fast_roundf(acc * m) + b, COLOR_GRAYSCALE_MAX), COLOR_GRAYSCALE_MIN); + int pixel = IM_MAX(IM_MIN(fast_floorf(acc * m) + b, COLOR_GRAYSCALE_MAX), COLOR_GRAYSCALE_MIN); if (threshold) { if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -1093,9 +1093,9 @@ void imlib_morph(image_t *img, const int ksize, const int *krn, const float m, c } } - int pixel = COLOR_R5_G6_B5_TO_RGB565(IM_MAX(IM_MIN(fast_roundf(r_acc * m) + b, COLOR_R5_MAX), COLOR_R5_MIN), - IM_MAX(IM_MIN(fast_roundf(g_acc * m) + b, COLOR_G6_MAX), COLOR_G6_MIN), - IM_MAX(IM_MIN(fast_roundf(b_acc * m) + b, COLOR_B5_MAX), COLOR_B5_MIN)); + int pixel = COLOR_R5_G6_B5_TO_RGB565(IM_MAX(IM_MIN(fast_floorf(r_acc * m) + b, COLOR_R5_MAX), COLOR_R5_MIN), + IM_MAX(IM_MIN(fast_floorf(g_acc * m) + b, COLOR_G6_MAX), COLOR_G6_MIN), + IM_MAX(IM_MIN(fast_floorf(b_acc * m) + b, COLOR_B5_MAX), COLOR_B5_MIN)); if (threshold) { if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { @@ -1196,7 +1196,7 @@ void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, fl } } - int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_BINARY_MAX)); + int pixel = fast_floorf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_BINARY_MAX)); if (threshold) { if (((pixel - offset) < IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -1273,7 +1273,7 @@ void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, fl } } - int pixel = fast_roundf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_GRAYSCALE_MAX)); + int pixel = fast_floorf(IM_MIN(IM_DIV(i_acc, w_acc), COLOR_GRAYSCALE_MAX)); if (threshold) { if (((pixel - offset) < IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x)) ^ invert) { @@ -1377,9 +1377,9 @@ void imlib_bilateral_filter(image_t *img, const int ksize, float color_sigma, fl } } - int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(IM_MIN(IM_DIV(r_i_acc, r_w_acc), COLOR_R5_MAX)), - fast_roundf(IM_MIN(IM_DIV(g_i_acc, g_w_acc), COLOR_G6_MAX)), - fast_roundf(IM_MIN(IM_DIV(b_i_acc, b_w_acc), COLOR_B5_MAX))); + int pixel = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(IM_MIN(IM_DIV(r_i_acc, r_w_acc), COLOR_R5_MAX)), + fast_floorf(IM_MIN(IM_DIV(g_i_acc, g_w_acc), COLOR_G6_MAX)), + fast_floorf(IM_MIN(IM_DIV(b_i_acc, b_w_acc), COLOR_B5_MAX))); if (threshold) { if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { @@ -1527,22 +1527,22 @@ void imlib_cartoon_filter(image_t *img, float seed_threshold, float floating_thr switch(img->bpp) { case IMAGE_BPP_BINARY: { - color_seed_threshold = fast_roundf(seed_threshold * COLOR_BINARY_MAX); - color_floating_threshold = fast_roundf(floating_threshold * COLOR_BINARY_MAX); + color_seed_threshold = fast_floorf(seed_threshold * COLOR_BINARY_MAX); + color_floating_threshold = fast_floorf(floating_threshold * COLOR_BINARY_MAX); break; } case IMAGE_BPP_GRAYSCALE: { - color_seed_threshold = fast_roundf(seed_threshold * COLOR_GRAYSCALE_MAX); - color_floating_threshold = fast_roundf(floating_threshold * COLOR_GRAYSCALE_MAX); + color_seed_threshold = fast_floorf(seed_threshold * COLOR_GRAYSCALE_MAX); + color_floating_threshold = fast_floorf(floating_threshold * COLOR_GRAYSCALE_MAX); break; } case IMAGE_BPP_RGB565: { - color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(seed_threshold * COLOR_R5_MAX), - fast_roundf(seed_threshold * COLOR_G6_MAX), - fast_roundf(seed_threshold * COLOR_B5_MAX)); - color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_roundf(floating_threshold * COLOR_R5_MAX), - fast_roundf(floating_threshold * COLOR_G6_MAX), - fast_roundf(floating_threshold * COLOR_B5_MAX)); + color_seed_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(seed_threshold * COLOR_R5_MAX), + fast_floorf(seed_threshold * COLOR_G6_MAX), + fast_floorf(seed_threshold * COLOR_B5_MAX)); + color_floating_threshold = COLOR_R5_G6_B5_TO_RGB565(fast_floorf(floating_threshold * COLOR_R5_MAX), + fast_floorf(floating_threshold * COLOR_G6_MAX), + fast_floorf(floating_threshold * COLOR_B5_MAX)); break; } default: { diff --git a/src/omv/img/imlib.c b/src/omv/img/imlib.c index 369153d57..8e0145150 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -314,7 +314,7 @@ int8_t imlib_rgb565_to_l(uint16_t pixel) y = (y>0.008856f) ? fast_cbrtf(y) : ((y * 7.787037f) + 0.137931f); - return fast_roundf(116 * y) - 16; + return fast_floorf(116 * y) - 16; } int8_t imlib_rgb565_to_a(uint16_t pixel) @@ -329,7 +329,7 @@ int8_t imlib_rgb565_to_a(uint16_t pixel) x = (x>0.008856f) ? fast_cbrtf(x) : ((x * 7.787037f) + 0.137931f); y = (y>0.008856f) ? fast_cbrtf(y) : ((y * 7.787037f) + 0.137931f); - return fast_roundf(500 * (x-y)); + return fast_floorf(500 * (x-y)); } int8_t imlib_rgb565_to_b(uint16_t pixel) @@ -344,7 +344,7 @@ int8_t imlib_rgb565_to_b(uint16_t pixel) y = (y>0.008856f) ? fast_cbrtf(y) : ((y * 7.787037f) + 0.137931f); z = (z>0.008856f) ? fast_cbrtf(z) : ((z * 7.787037f) + 0.137931f); - return fast_roundf(200 * (y-z)); + return fast_floorf(200 * (y-z)); } int8_t imlib_rgb565_to_y(uint16_t pixel) @@ -394,9 +394,9 @@ uint16_t imlib_lab_to_rgb(uint8_t l, int8_t a, int8_t b) g_lin = (g_lin>0.0031308f) ? ((1.055f*powf(g_lin, 0.416666f))-0.055f) : (g_lin*12.92f); b_lin = (b_lin>0.0031308f) ? ((1.055f*powf(b_lin, 0.416666f))-0.055f) : (b_lin*12.92f); - uint32_t red = IM_MAX(IM_MIN(fast_roundf(r_lin * COLOR_R8_MAX), COLOR_R8_MAX), COLOR_R8_MIN); - uint32_t green = IM_MAX(IM_MIN(fast_roundf(g_lin * COLOR_G8_MAX), COLOR_G8_MAX), COLOR_G8_MIN); - uint32_t blue = IM_MAX(IM_MIN(fast_roundf(b_lin * COLOR_B8_MAX), COLOR_B8_MAX), COLOR_B8_MIN); + uint32_t red = IM_MAX(IM_MIN(fast_floorf(r_lin * COLOR_R8_MAX), COLOR_R8_MAX), COLOR_R8_MIN); + uint32_t green = IM_MAX(IM_MIN(fast_floorf(g_lin * COLOR_G8_MAX), COLOR_G8_MAX), COLOR_G8_MIN); + uint32_t blue = IM_MAX(IM_MIN(fast_floorf(b_lin * COLOR_B8_MAX), COLOR_B8_MAX), COLOR_B8_MIN); return COLOR_R8_G8_B8_TO_RGB565(red, green, blue); } @@ -826,8 +826,8 @@ void imlib_lens_corr(image_t *img, float strength, float zoom) float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); - int sourceX = halfWidth + fast_roundf(theta * zoomedX); - int sourceY = halfHeight + fast_roundf(theta * zoomedY); + int sourceX = halfWidth + fast_floorf(theta * zoomedX); + int sourceY = halfHeight + fast_floorf(theta * zoomedY); if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { uint32_t *ptr = tmp + (((img->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * sourceY); @@ -859,8 +859,8 @@ void imlib_lens_corr(image_t *img, float strength, float zoom) float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); - int sourceX = halfWidth + fast_roundf(theta * zoomedX); - int sourceY = halfHeight + fast_roundf(theta * zoomedY); + int sourceX = halfWidth + fast_floorf(theta * zoomedX); + int sourceY = halfHeight + fast_floorf(theta * zoomedY); if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { uint8_t *ptr = tmp + (img->w * sourceY); @@ -892,8 +892,8 @@ void imlib_lens_corr(image_t *img, float strength, float zoom) float r = lens_corr_radius * fast_sqrtf(newX2 + newY2); float theta = (r < 0.0000001f) ? 1.0f : (fast_atanf(r) / r); - int sourceX = halfWidth + fast_roundf(theta * zoomedX); - int sourceY = halfHeight + fast_roundf(theta * zoomedY); + int sourceX = halfWidth + fast_floorf(theta * zoomedX); + int sourceY = halfHeight + fast_floorf(theta * zoomedY); if ((0 <= sourceX) && (sourceX < img->w) && (0 <= sourceY) && (sourceY < img->h)) { uint16_t *ptr = tmp + (img->w * sourceY); diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index 5c918d941..d1aa72960 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1430,9 +1430,9 @@ static mp_obj_t py_image_copy_int(uint n_args, const mp_obj_t *args, mp_map_t *k } image_t image; - image.w = fast_roundf(roi.w * arg_x_scale); + image.w = fast_floorf(roi.w * arg_x_scale); PY_ASSERT_TRUE_MSG(image.w >= 1, "Output image width is 0!"); - image.h = fast_roundf(roi.h * arg_y_scale); + image.h = fast_floorf(roi.h * arg_y_scale); PY_ASSERT_TRUE_MSG(image.h >= 1, "Output image height is 0!"); image.bpp = arg_img->bpp; image.data = NULL; @@ -1478,33 +1478,33 @@ static mp_obj_t py_image_copy_int(uint n_args, const mp_obj_t *args, mp_map_t *k switch(arg_img->bpp) { case IMAGE_BPP_BINARY: { for (int y = 0, yy = image.h; y < yy; y++) { - uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, fast_roundf(y * over_yscale) + roi.y); + uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y); uint32_t *row_ptr_2 = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&image, y); for (int x = 0, xx = image.w; x < xx; x++) { IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_2, x, - IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, fast_roundf(x * over_xscale) + roi.x)); + IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x)); } } break; } case IMAGE_BPP_GRAYSCALE: { for (int y = 0, yy = image.h; y < yy; y++) { - uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, fast_roundf(y * over_yscale) + roi.y); + uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y); uint8_t *row_ptr_2 = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y); for (int x = 0, xx = image.w; x < xx; x++) { IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_2, x, - IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, fast_roundf(x * over_xscale) + roi.x)); + IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x)); } } break; } case IMAGE_BPP_RGB565: { for (int y = 0, yy = image.h; y < yy; y++) { - uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, fast_roundf(y * over_yscale) + roi.y); + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(arg_img, fast_floorf(y * over_yscale) + roi.y); uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y); for (int x = 0, xx = image.w; x < xx; x++) { IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x, - IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, fast_roundf(x * over_xscale) + roi.x)); + IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, fast_floorf(x * over_xscale) + roi.x)); } } break; From 5b3cd7c9db784720a732a303c3c21dbfe2f02744 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 11 Feb 2019 01:50:33 -0500 Subject: [PATCH 4/7] Make rotation not an optional argument for ellipses. --- .../examples/03-Drawing/ellipse_drawing.py | 4 ++-- src/omv/py/py_image.c | 20 ++++++++----------- src/omv/py/qstrdefsomv.h | 4 +--- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/scripts/examples/03-Drawing/ellipse_drawing.py b/scripts/examples/03-Drawing/ellipse_drawing.py index e824a1180..dc788454b 100644 --- a/scripts/examples/03-Drawing/ellipse_drawing.py +++ b/scripts/examples/03-Drawing/ellipse_drawing.py @@ -29,7 +29,7 @@ while(True): # If the first argument is a scaler then this method expects # to see x, y, radius x, and radius y. # Otherwise, it expects a (x,y,radius_x,radius_y) tuple. - img.draw_ellipse(x, y, radius_x, radius_y, \ - rotation = rot, color = (r, g, b), thickness = 2, fill = False) + img.draw_ellipse(x, y, radius_x, radius_y, rot, + color = (r, g, b), thickness = 2, fill = False) print(clock.fps()) diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index d1aa72960..b816355c6 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1581,7 +1581,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save); STATIC mp_obj_t py_image_clear(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]); - image_t *arg_msk = py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args); + + image_t *arg_msk = + py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args); if (!arg_msk) { memset(arg_img->data, 0, image_size(arg_img)); @@ -1664,14 +1666,13 @@ STATIC mp_obj_t py_image_draw_ellipse(uint n_args, const mp_obj_t *args, mp_map_ 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); + uint offset = py_helper_consume_array(n_args, args, 1, 5, &arg_vec); int arg_cx = mp_obj_get_int(arg_vec[0]); int arg_cy = mp_obj_get_int(arg_vec[1]); int arg_rx = mp_obj_get_int(arg_vec[2]); int arg_ry = mp_obj_get_int(arg_vec[3]); + int arg_r = mp_obj_get_int(arg_vec[4]); - int arg_rotation = - py_helper_keyword_int(n_args, args, offset + 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_rotation), 0); int arg_c = py_helper_keyword_color(arg_img, n_args, args, offset + 1, kw_args, -1); // White. int arg_thickness = @@ -1679,7 +1680,7 @@ STATIC mp_obj_t py_image_draw_ellipse(uint n_args, const mp_obj_t *args, mp_map_ bool arg_fill = py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false); - imlib_draw_ellipse(arg_img, arg_cx, arg_cy, arg_rx, arg_ry, arg_rotation, arg_c, arg_thickness, arg_fill); + imlib_draw_ellipse(arg_img, arg_cx, arg_cy, arg_rx, arg_ry, arg_r, arg_c, arg_thickness, arg_fill); return args[0]; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_ellipse_obj, 2, py_image_draw_ellipse); @@ -1975,7 +1976,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_mask_circle_obj, 1, py_image_mask_cir 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; @@ -1984,14 +1984,13 @@ STATIC mp_obj_t py_image_mask_ellipse(uint n_args, const mp_obj_t *args, mp_map_ if (n_args > 1) { const mp_obj_t *arg_vec; - offset = py_helper_consume_array(n_args, args, 1, 5, &arg_vec); + 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; @@ -1999,9 +1998,6 @@ STATIC mp_obj_t py_image_mask_ellipse(uint n_args, const mp_obj_t *args, mp_map_ 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; @@ -2009,7 +2005,7 @@ STATIC mp_obj_t py_image_mask_ellipse(uint n_args, const mp_obj_t *args, mp_map_ 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_draw_ellipse(&temp, arg_cx, arg_cy, arg_rx, arg_ry, arg_r, -1, 0, true); imlib_zero(arg_img, &temp, true); fb_free(); diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index c88270b29..bd4c0e70e 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -452,7 +452,6 @@ Q(draw_circle) // Draw Ellipse Q(draw_ellipse) -Q(rotation) // duplicate Q(color) // duplicate Q(thickness) // duplicate Q(fill) @@ -515,7 +514,6 @@ Q(mask_circle) // Mask Ellipse Q(mask_ellipse) -// duplicate Q(rotation) // Binary Q(binary) @@ -893,7 +891,7 @@ Q(cx) Q(cxf) Q(cy) Q(cyf) -// duplicate Q(rotation) +Q(rotation) Q(rotation_deg) Q(rotation_rad) Q(code) From ae9f1833f87b2bf63aa3584ea901adf2f50e6022 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Wed, 13 Feb 2019 02:07:06 -0500 Subject: [PATCH 5/7] Fix rotation issues. --- src/omv/img/draw.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/omv/img/draw.c b/src/omv/img/draw.c index e1b8acf60..43bc00187 100644 --- a/src/omv/img/draw.c +++ b/src/omv/img/draw.c @@ -248,11 +248,28 @@ static void scratch_draw_sheared_ellipse(image_t *img, int x0, int y0, int width static void scratch_draw_rotated_ellipse(image_t *img, int x, int y, int x_axis, int y_axis, int rotation, bool filled, int c, int thickness) { if ((x_axis > 0) && (y_axis > 0)) { - if ((x_axis == y_axis) || ((rotation % 180) == 0)) { + if ((x_axis == y_axis) || (rotation == 0)) { scratch_draw_sheared_ellipse(img, x, y, x_axis / 2, y_axis / 2, filled, 1, 0, c, thickness); - } else if ((rotation % 180) == 90) { + } else if (rotation == 90) { scratch_draw_sheared_ellipse(img, x, y, y_axis / 2, x_axis / 2, filled, 1, 0, c, thickness); } else { + + // Avoid rotations above 90. + if (rotation > 90) { + rotation -= 90; + int temp = x_axis; + x_axis = y_axis; + y_axis = temp; + } + + // Avoid rotations above 45. + if (rotation > 45) { + rotation -= 90; + int temp = x_axis; + x_axis = y_axis; + y_axis = temp; + } + float theta = fast_atanf(IM_DIV(y_axis, x_axis) * (-tanf(IM_DEG2RAD(rotation)))); float shear_dx = (x_axis * cosf(theta) * cosf(IM_DEG2RAD(rotation))) - (y_axis * sinf(theta) * sinf(IM_DEG2RAD(rotation))); float shear_dy = (x_axis * cosf(theta) * sinf(IM_DEG2RAD(rotation))) + (y_axis * sinf(theta) * cosf(IM_DEG2RAD(rotation))); @@ -265,7 +282,10 @@ static void scratch_draw_rotated_ellipse(image_t *img, int x, int y, int x_axis, void imlib_draw_ellipse(image_t *img, int cx, int cy, int rx, int ry, int rotation, int c, int thickness, bool fill) { - scratch_draw_rotated_ellipse(img, cx, cy, rx * 2, ry * 2, rotation, fill, c, thickness); + int r = rotation % 180; + if (r < 0) r += 180; + + scratch_draw_rotated_ellipse(img, cx, cy, rx * 2, ry * 2, r, fill, c, thickness); } void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space) From ee321933d2945f0cbe7b8875e7f9fe909a4ac779 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Wed, 13 Feb 2019 02:10:33 -0500 Subject: [PATCH 6/7] Update ellipse drawing without limit. --- scripts/examples/03-Drawing/ellipse_drawing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/examples/03-Drawing/ellipse_drawing.py b/scripts/examples/03-Drawing/ellipse_drawing.py index dc788454b..9080a99d2 100644 --- a/scripts/examples/03-Drawing/ellipse_drawing.py +++ b/scripts/examples/03-Drawing/ellipse_drawing.py @@ -20,7 +20,7 @@ while(True): y = (pyb.rng() % (2*img.height())) - (img.height()//2) radius_x = pyb.rng() % (max(img.height(), img.width())//2) radius_y = pyb.rng() % (max(img.height(), img.width())//2) - rot = pyb.rng() % 45 # Avoid large rotation angles with fill on... + rot = pyb.rng() r = (pyb.rng() % 127) + 128 g = (pyb.rng() % 127) + 128 From cd586f66bcc5cdf4660e461cbe055054b8b95422 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sat, 16 Feb 2019 21:18:20 -0500 Subject: [PATCH 7/7] Upgrade text drawing to support rotations of the character and string. --- scripts/examples/03-Drawing/text_drawing.py | 6 +- src/omv/img/draw.c | 102 ++++++++++++++------ src/omv/img/imlib.h | 3 +- src/omv/py/py_image.c | 17 +++- src/omv/py/qstrdefsomv.h | 6 ++ 5 files changed, 103 insertions(+), 31 deletions(-) diff --git a/scripts/examples/03-Drawing/text_drawing.py b/scripts/examples/03-Drawing/text_drawing.py index 4ac405301..da37af656 100644 --- a/scripts/examples/03-Drawing/text_drawing.py +++ b/scripts/examples/03-Drawing/text_drawing.py @@ -24,6 +24,10 @@ while(True): # If the first argument is a scaler then this method expects # to see x, y, and text. Otherwise, it expects a (x,y,text) tuple. - img.draw_string(x, y, "Hello World!", color = (r, g, b), scale = 2, mono_space = False) + + # Character and string rotation can be done at 0, 90, 180, 270, and etc. degrees. + img.draw_string(x, y, "Hello World!", color = (r, g, b), scale = 2, mono_space = False, + char_rotation = 0, char_hmirror = False, char_vflip = False, + string_rotation = 0, string_hmirror = False, string_vflip = False) print(clock.fps()) diff --git a/src/omv/img/draw.c b/src/omv/img/draw.c index 43bc00187..37f13d461 100644 --- a/src/omv/img/draw.c +++ b/src/omv/img/draw.c @@ -288,8 +288,27 @@ void imlib_draw_ellipse(image_t *img, int cx, int cy, int rx, int ry, int rotati scratch_draw_rotated_ellipse(img, cx, cy, rx * 2, ry * 2, r, fill, c, thickness); } -void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space) +// char rotation == 0, 90, 180, 360, etc. +// string rotation == 0, 90, 180, 360, etc. +void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space, + int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_vflip) { + char_rotation %= 360; + if (char_rotation < 0) char_rotation += 360; + char_rotation = (char_rotation / 90) * 90; + + string_rotation %= 360; + if (string_rotation < 0) string_rotation += 360; + string_rotation = (string_rotation / 90) * 90; + + bool char_swap_w_h = (char_rotation == 90) || (char_rotation == 270); + bool char_upsidedown = (char_rotation == 180) || (char_rotation == 270); + + if (string_hmirror) x_off -= fast_floorf(font[0].w * scale) - 1; + if (string_vflip) y_off -= fast_floorf(font[0].h * scale) - 1; + + int org_x_off = x_off; + int org_y_off = y_off; const int anchor = x_off; for(char ch, last = '\0'; (ch = *str); str++, last = ch) { @@ -300,17 +319,11 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int if ((ch == '\n') || (ch == '\r')) { // handle '\n' or '\r' strings x_off = anchor; - y_off += fast_floorf(font[0].h * scale) + y_spacing; // newline height == space height + y_off += (string_vflip ? -1 : +1) * (fast_floorf((char_swap_w_h ? font[0].w : font[0].h) * scale) + y_spacing); // newline height == space height continue; } if ((ch < ' ') || (ch > '~')) { // handle unknown characters - imlib_draw_rectangle(img, - x_off + (fast_floorf(scale * 3) / 2), - y_off + (fast_floorf(scale * 3) / 2), - fast_floorf(font[0].w * scale) - ((fast_floorf(scale * 3) / 2) * 2), - fast_floorf(font[0].h * scale) - ((fast_floorf(scale * 3) / 2) * 2), - c, fast_floorf(scale), false); continue; } @@ -320,46 +333,81 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int // Find the first pixel set and offset to that. bool exit = false; - for (int x = 0, xx = g->w; x < xx; x++) { - for (int y = 0, yy = g->h; y < yy; y++) { - if (g->data[y] & (1 << (g->w - 1 - x))) { - x_off -= fast_floorf(x * scale); - exit = true; - break; + if (!char_swap_w_h) { + for (int x = 0, xx = g->w; x < xx; x++) { + for (int y = 0, yy = g->h; y < yy; y++) { + if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] & + (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) { + x_off += (string_hmirror ? +1 : -1) * fast_floorf(x * scale); + exit = true; + break; + } } - } - if (exit) break; + if (exit) break; + } + } else { + for (int y = g->h - 1; y >= 0; y--) { + for (int x = 0, xx = g->w; x < xx; x++) { + if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] & + (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) { + x_off += (string_hmirror ? +1 : -1) * fast_floorf((g->h - 1 - y) * scale); + exit = true; + break; + } + } + + if (exit) break; + } } } for (int y = 0, yy = fast_floorf(g->h * scale); y < yy; y++) { for (int x = 0, xx = fast_floorf(g->w * scale); x < xx; x++) { if (g->data[fast_floorf(y / scale)] & (1 << (g->w - 1 - fast_floorf(x / scale)))) { - imlib_set_pixel(img, (x_off + x), (y_off + y), c); + int16_t x_tmp = x_off + (char_hmirror ? (xx - x - 1) : x), y_tmp = y_off + (char_vflip ? (yy - y - 1) : y); + point_rotate(x_tmp, y_tmp, IM_DEG2RAD(char_rotation), x_off + (xx / 2), y_off + (yy / 2), &x_tmp, &y_tmp); + point_rotate(x_tmp, y_tmp, IM_DEG2RAD(string_rotation), org_x_off, org_y_off, &x_tmp, &y_tmp); + imlib_set_pixel(img, x_tmp, y_tmp, c); } } } if (mono_space) { - x_off += fast_floorf(g->w * scale) + x_spacing; + x_off += (string_hmirror ? -1 : +1) * (fast_floorf((char_swap_w_h ? g->h : g->w) * scale) + x_spacing); } else { // Find the last pixel set and offset to that. bool exit = false; - for (int x = g->w - 1; x >= 0; x--) { - for (int y = g->h - 1; y >= 0; y--) { - if (g->data[y] & (1 << (g->w - 1 - x))) { - x_off += fast_floorf((x + 2) * scale) + x_spacing; - exit = true; - break; + if (!char_swap_w_h) { + for (int x = g->w - 1; x >= 0; x--) { + for (int y = g->h - 1; y >= 0; y--) { + if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] & + (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) { + x_off += (string_hmirror ? -1 : +1) * (fast_floorf((x + 2) * scale) + x_spacing); + exit = true; + break; + } } - } - if (exit) break; + if (exit) break; + } + } else { + for (int y = 0, yy = g->h; y < yy; y++) { + for (int x = g->w - 1; x >= 0; x--) { + if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] & + (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) { + x_off += (string_hmirror ? -1 : +1) * (fast_floorf(((g->h - 1 - y) + 2) * scale) + x_spacing); + exit = true; + break; + } + } + + if (exit) break; + } } - if (!exit) x_off += fast_floorf(scale * 3); // space char + if (!exit) x_off += (string_hmirror ? -1 : +1) * fast_floorf(scale * 3); // space char } } } diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index 7dba9b61f..e8d5efb61 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -1262,7 +1262,8 @@ void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int th void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill); void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill); void imlib_draw_ellipse(image_t *img, int cx, int cy, int rx, int ry, int rotation, int c, int thickness, bool fill); -void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space); +void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space, + int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_hflip); void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float x_scale, float y_scale, float alpha, image_t *mask); void imlib_flood_fill(image_t *img, int x, int y, float seed_threshold, float floating_threshold, diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index b816355c6..b2ad3cff0 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1706,10 +1706,23 @@ STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t py_helper_keyword_int(n_args, args, offset + 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_y_spacing), 0); bool arg_mono_space = py_helper_keyword_int(n_args, args, offset + 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mono_space), true); + int arg_char_rotation = + py_helper_keyword_int(n_args, args, offset + 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_rotation), 0); + int arg_char_hmirror = + py_helper_keyword_int(n_args, args, offset + 6, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_hmirror), false); + int arg_char_vflip = + py_helper_keyword_int(n_args, args, offset + 7, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_char_vflip), false); + int arg_string_rotation = + py_helper_keyword_int(n_args, args, offset + 8, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_rotation), 0); + int arg_string_hmirror = + py_helper_keyword_int(n_args, args, offset + 9, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_hmirror), false); + int arg_string_vflip = + py_helper_keyword_int(n_args, args, offset + 10, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_string_vflip), false); imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, - arg_c, arg_scale, arg_x_spacing, arg_y_spacing, - arg_mono_space); + arg_c, arg_scale, arg_x_spacing, arg_y_spacing, arg_mono_space, + arg_char_rotation, arg_char_hmirror, arg_char_vflip, + arg_string_rotation, arg_string_hmirror, arg_string_vflip); return args[0]; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 2, py_image_draw_string); diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index bd4c0e70e..caf4c6f09 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -463,6 +463,12 @@ Q(draw_string) Q(x_spacing) Q(y_spacing) Q(mono_space) +Q(char_rotation) +Q(char_hmirror) +Q(char_vflip) +Q(string_rotation) +Q(string_hmirror) +Q(string_vflip) // Draw Cross Q(draw_cross)