diff --git a/scripts/examples/03-Drawing/ellipse_drawing.py b/scripts/examples/03-Drawing/ellipse_drawing.py index e824a1180..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 @@ -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/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 6982ec9eb..37f13d461 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,11 +282,33 @@ 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) +// 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) { @@ -280,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_roundf(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_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); continue; } @@ -300,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_roundf(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_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)))) { - imlib_set_pixel(img, (x_off + x), (y_off + y), c); + 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)))) { + 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_roundf(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_roundf((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_roundf(scale * 3); // space char + if (!exit) x_off += (string_hmirror ? -1 : +1) * fast_floorf(scale * 3); // space char } } } @@ -405,11 +473,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 +514,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 fbe1b975e..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); } @@ -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) @@ -784,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); @@ -817,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); @@ -850,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/img/imlib.h b/src/omv/img/imlib.h index d804fd8fc..e8d5efb61 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); @@ -1261,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 1434dfad5..b2ad3cff0 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; @@ -1578,13 +1578,22 @@ 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) { @@ -1657,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 = @@ -1672,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); @@ -1698,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); @@ -1892,6 +1913,120 @@ 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]); + 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; + 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 { + 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; + } + + 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_r, -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 +6350,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..caf4c6f09 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) @@ -451,7 +452,6 @@ Q(draw_circle) // Draw Ellipse Q(draw_ellipse) -Q(rotation) // duplicate Q(color) // duplicate Q(thickness) // duplicate Q(fill) @@ -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) @@ -488,7 +494,7 @@ Q(draw_image) // duplicate Q(x_scale) // duplicate Q(y_scale) Q(alpha) -Q(mask) +// duplicate Q(mask) // Draw Keypoints Q(draw_keypoints) @@ -506,6 +512,15 @@ Q(invert) Q(clear_background) // duplicate Q(mask) +// Mask Rectangle +Q(mask_rectangle) + +// Mask Circle +Q(mask_circle) + +// Mask Ellipse +Q(mask_ellipse) + // Binary Q(binary) // duplicate Q(invert) @@ -882,7 +897,7 @@ Q(cx) Q(cxf) Q(cy) Q(cyf) -// duplicate Q(rotation) +Q(rotation) Q(rotation_deg) Q(rotation_rad) Q(code)