Kwabena/drawing updates (#422)

* Add ellipse drawing function.
This commit is contained in:
Kwabena W. Agyeman 2018-12-31 08:32:13 -08:00 committed by Ibrahim Abd Elkader
parent a3e502a3a6
commit b47dbe2c15
7 changed files with 237 additions and 12 deletions

View File

@ -0,0 +1,35 @@
# Ellipse Drawing
#
# This example shows off drawing ellipses on the OpenMV Cam.
import sensor, image, time, pyb
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # or GRAYSCALE...
sensor.set_framesize(sensor.QVGA) # or QQVGA...
sensor.skip_frames(time = 2000)
clock = time.clock()
while(True):
clock.tick()
img = sensor.snapshot()
for i in range(10):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
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...
r = (pyb.rng() % 127) + 128
g = (pyb.rng() % 127) + 128
b = (pyb.rng() % 127) + 128
# 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)
print(clock.fps())

View File

@ -14,12 +14,12 @@ while(True):
clock.tick()
img = sensor.snapshot()
w = img.width()
h = img.height()
# Draws an image in the frame buffer. In this case we're
# drawing the image we're currently drawing which causes
# graphical glitches but is cool. Pass an optional mask
# image to control what pixels are drawn.
img.draw_image(img, w//4, h//4, x_scale=0.5, y_scale=0.5)
small_img = img.mean_pooled(4, 4) # Makes a copy.
x = (img.width()//2)-(small_img.width()//2)
y = (img.height()//2)-(small_img.height()//2)
# Draws an image in the frame buffer.Pass an optional
# mask image to control what pixels are drawn.
img.draw_image(small_img, x, y, x_scale=1, y_scale=1)
print(clock.fps())

View File

@ -31,7 +31,7 @@
//#define IMLIB_ENABLE_MIDPOINT
// Enable Gaussian
#define IMLIB_ENABLE_GAUSSIAN
//#define IMLIB_ENABLE_GAUSSIAN
// Enable Laplacian
//#define IMLIB_ENABLE_LAPLACIAN

View File

@ -170,6 +170,104 @@ void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness
}
}
// https://scratch.mit.edu/projects/50039326/
static void scratch_draw_pixel(image_t *img, int x0, int y0, int dx, int dy, float shear_dx, float shear_dy, int r0, int r1, int c)
{
point_fill(img, x0 + dx, y0 + dy + fast_floorf((dx * shear_dy) / shear_dx), r0, r1, c);
}
// https://scratch.mit.edu/projects/50039326/
static void scratch_draw_line(image_t *img, int x0, int y0, int dx, int dy0, int dy1, float shear_dx, float shear_dy, int c)
{
imlib_draw_line(img, x0 + dx, y0 + dy0 + fast_floorf((dx * shear_dy) / shear_dx),
x0 + dx, y0 + dy1 + fast_floorf((dx * shear_dy) / shear_dx), c, 1);
}
// https://scratch.mit.edu/projects/50039326/
static void scratch_draw_sheared_ellipse(image_t *img, int x0, int y0, int width, int height, bool filled, float shear_dx, float shear_dy, int c, int thickness)
{
int thickness0 = (thickness - 0) / 2;
int thickness1 = (thickness - 1) / 2;
if (((thickness > 0) || filled) && (shear_dx != 0)) {
int a_squared = width * width;
int four_a_squared = a_squared * 4;
int b_squared = height * height;
int four_b_squared = b_squared * 4;
int x = 0;
int y = height;
int sigma = (2 * b_squared) + (a_squared * (1 - (2 * height)));
while ((b_squared * x) <= (a_squared * y)) {
if (filled) {
scratch_draw_line(img, x0, y0, x, -y, y, shear_dx, shear_dy, c);
scratch_draw_line(img, x0, y0, -x, -y, y, shear_dx, shear_dy, c);
} else {
scratch_draw_pixel(img, x0, y0, x, y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, -x, y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, x, -y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, -x, -y, shear_dx, shear_dy, -thickness0, thickness1, c);
}
if (sigma >= 0) {
sigma += four_a_squared * (1 - y);
y -= 1;
}
sigma += b_squared * ((4 * x) + 6);
x += 1;
}
x = width;
y = 0;
sigma = (2 * a_squared) + (b_squared * (1 - (2 * width)));
while ((a_squared * y) <= (b_squared * x)) {
if (filled) {
scratch_draw_line(img, x0, y0, x, -y, y, shear_dx, shear_dy, c);
scratch_draw_line(img, x0, y0, -x, -y, y, shear_dx, shear_dy, c);
} else {
scratch_draw_pixel(img, x0, y0, x, y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, -x, y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, x, -y, shear_dx, shear_dy, -thickness0, thickness1, c);
scratch_draw_pixel(img, x0, y0, -x, -y, shear_dx, shear_dy, -thickness0, thickness1, c);
}
if (sigma >= 0) {
sigma += four_b_squared * (1 - x);
x -= 1;
}
sigma += a_squared * ((4 * y) + 6);
y += 1;
}
}
}
// https://scratch.mit.edu/projects/50039326/
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)) {
scratch_draw_sheared_ellipse(img, x, y, x_axis / 2, y_axis / 2, filled, 1, 0, c, thickness);
} else if ((rotation % 180) == 90) {
scratch_draw_sheared_ellipse(img, x, y, y_axis / 2, x_axis / 2, filled, 1, 0, c, thickness);
} else {
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)));
float shear_x_axis = fast_fabsf(shear_dx);
float shear_y_axis = IM_DIV((y_axis * x_axis), shear_x_axis);
scratch_draw_sheared_ellipse(img, x, y, fast_floorf(shear_x_axis / 2), fast_floorf(shear_y_axis / 2), filled, shear_dx, shear_dy, c, thickness);
}
}
}
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);
}
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale, int x_spacing, int y_spacing, bool mono_space)
{
const int anchor = x_off;
@ -246,6 +344,63 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int
}
}
static int safe_map_pixel(image_t *dst, image_t *src, int pixel)
{
switch (dst->bpp) {
case IMAGE_BPP_BINARY: {
switch (src->bpp) {
case IMAGE_BPP_BINARY: {
return pixel;
}
case IMAGE_BPP_GRAYSCALE: {
return COLOR_GRAYSCALE_TO_BINARY(pixel);
}
case IMAGE_BPP_RGB565: {
return COLOR_RGB565_TO_BINARY(pixel);
}
default: {
return 0;
}
}
}
case IMAGE_BPP_GRAYSCALE: {
switch (src->bpp) {
case IMAGE_BPP_BINARY: {
return COLOR_BINARY_TO_GRAYSCALE(pixel);
}
case IMAGE_BPP_GRAYSCALE: {
return pixel;
}
case IMAGE_BPP_RGB565: {
return COLOR_RGB565_TO_GRAYSCALE(pixel);
}
default: {
return 0;
}
}
}
case IMAGE_BPP_RGB565: {
switch (src->bpp) {
case IMAGE_BPP_BINARY: {
return COLOR_BINARY_TO_RGB565(pixel);
}
case IMAGE_BPP_GRAYSCALE: {
return COLOR_GRAYSCALE_TO_RGB565(pixel);
}
case IMAGE_BPP_RGB565: {
return pixel;
}
default: {
return 0;
}
}
}
default: {
return 0;
}
}
}
void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float x_scale, float y_scale, image_t *mask)
{
float over_xscale = IM_DIV(1.0, x_scale), over_yscale = IM_DIV(1.0f, y_scale);
@ -256,8 +411,9 @@ void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float
for (int x = 0, xx = fast_roundf(other->w * x_scale); x < xx; x++) {
int other_x = fast_roundf(x * over_xscale);
if (mask && (!image_get_mask_pixel(mask, other_x, other_y))) continue;
imlib_set_pixel(img, x_off + x, y_off + y, imlib_get_pixel(other, other_x, other_y));
if ((!mask) || image_get_mask_pixel(mask, other_x, other_y)) {
imlib_set_pixel(img, x_off + x, y_off + y, safe_map_pixel(img, other, imlib_get_pixel(other, other_x, other_y)));
}
}
}
}

View File

@ -1274,6 +1274,7 @@ void imlib_set_pixel(image_t *img, int x, int y, int p);
void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness);
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, int scale, int x_spacing, int y_spacing, bool mono_space);
void imlib_draw_image(image_t *img, image_t *other, int x_off, int y_off, float x_scale, float y_scale, image_t *mask);
void imlib_flood_fill(image_t *img, int x, int y,

View File

@ -1309,6 +1309,31 @@ STATIC mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 2, py_image_draw_circle);
STATIC mp_obj_t py_image_draw_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]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 1, 4, &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_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 =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
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);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_ellipse_obj, 2, py_image_draw_ellipse);
STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
@ -1403,7 +1428,7 @@ STATIC mp_obj_t py_image_draw_image(uint n_args, const mp_obj_t *args, mp_map_t
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
image_t *arg_other =
py_helper_keyword_to_image_mutable_mask(n_args, args, 1, kw_args);
py_helper_arg_to_image_mutable(args[1]);
const mp_obj_t *arg_vec;
uint offset = py_helper_consume_array(n_args, args, 2, 2, &arg_vec);
@ -5269,6 +5294,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&py_image_draw_line_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_rectangle), MP_ROM_PTR(&py_image_draw_rectangle_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&py_image_draw_circle_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_ellipse), MP_ROM_PTR(&py_image_draw_ellipse_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_string), MP_ROM_PTR(&py_image_draw_string_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_cross), MP_ROM_PTR(&py_image_draw_cross_obj)},
{MP_ROM_QSTR(MP_QSTR_draw_arrow), MP_ROM_PTR(&py_image_draw_arrow_obj)},

View File

@ -398,6 +398,13 @@ Q(draw_circle)
// duplicate Q(thickness)
// duplicate Q(fill)
// Draw Ellipse
Q(draw_ellipse)
Q(rotation)
// duplicate Q(color)
// duplicate Q(thickness)
// duplicate Q(fill)
// Draw String
Q(draw_string)
// duplicate Q(color)
@ -800,7 +807,7 @@ Q(h)
Q(pixels)
Q(cx)
Q(cy)
Q(rotation)
// duplicate Q(rotation)
Q(code)
Q(count)
Q(area)