New drawing functions.

All the drawing functions have been updated to handle automatic clipping
when drawing offscren and work with both grayscale and RGB565.
Additionally, all functions now accept color arguments.

I've also updated the example scripts with the new functions and tested
them out to make sure they work.

Additionally, I wrote a test suite for the drawing functions to make
sure they work.
This commit is contained in:
Kwabena W. Agyeman 2016-02-18 22:40:12 -05:00
parent 04a2e89fd5
commit bcd5151412
10 changed files with 537 additions and 267 deletions

View File

@ -46,6 +46,87 @@ 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 dx = abs(x1-x0);
int dy = abs(y1-y0);
int sx = x0<x1 ? 1 : -1;
int sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)/2;
for (;;) {
imlib_set_pixel(img, x0, y0, c);
if (x0==x1 && y0==y1) break;
int e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c)
{
if (rw<=0 || rh<=0) {
return;
}
for (int i=rx, j=rx+rw, k=ry+rh-1; i<j; i++) {
imlib_set_pixel(img, i, ry, c);
imlib_set_pixel(img, i, k, c);
}
for (int i=ry+1, j=ry+rh-1, k=rx+rw-1; i<j; i++) {
imlib_set_pixel(img, rx, i, c);
imlib_set_pixel(img, k, i, c);
}
}
void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c)
{
int x = r, y = 0, radiusError = 1-x;
while (x>=y) {
imlib_set_pixel(img, x + cx, y + cy, c);
imlib_set_pixel(img, y + cx, x + cy, c);
imlib_set_pixel(img, -x + cx, y + cy, c);
imlib_set_pixel(img, -y + cx, x + cy, c);
imlib_set_pixel(img, -x + cx, -y + cy, c);
imlib_set_pixel(img, -y + cx, -x + cy, c);
imlib_set_pixel(img, x + cx, -y + cy, c);
imlib_set_pixel(img, y + cx, -x + cy, c);
y++;
if (radiusError<0) {
radiusError += 2 * y + 1;
} else {
x--;
radiusError += 2 * (y - x + 1);
}
}
}
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c)
{
const int anchor = x_off;
for(char ch, last='\0'; (ch=*str); str++, last=ch) {
if (last=='\r' && ch=='\n') { // handle "\r\n" strings
continue;
}
if (ch=='\n' || ch=='\r') { // handle '\n' or '\r' strings
x_off = anchor;
y_off += font[0].h; // newline height == space height
continue;
}
if (ch<' ' || ch>'~') {
imlib_draw_rectangle(img,(x_off+1),(y_off+1),font[0].w-2,font[0].h-2,c);
continue;
}
const glyph_t *g = &font[ch-' '];
for (int y=0; y<g->h; y++) {
for (int x=0; x<g->w; x++) {
if (g->data[y] & (1<<(g->w-x))) {
imlib_set_pixel(img, (x_off+x), (y_off+y), c);
}
}
}
x_off += g->w;
}
}
uint32_t imlib_lab_distance(struct color *c0, struct color *c1)
{
uint32_t sum=0;
@ -580,121 +661,6 @@ void imlib_scale(struct image *src, struct image *dst, interp_t interp)
}
}
void imlib_draw_rectangle(struct image *image, struct rectangle *r)
{
int i;
uint8_t c=0xFF;
int x = IM_MIN(IM_MAX(r->x, 0), image->w-1);
int y = IM_MIN(IM_MAX(r->y, 0), image->h-1);
int w = (x+r->w) >= image->w ? (image->w-x-1):r->w;
int h = (y+r->h) >= image->h ? (image->h-y-1):r->h;
x *= image->bpp;
w *= image->bpp;
int col = image->w*image->bpp;
for (i=0; i<w; i++) {
image->pixels[y*col + x + i] = c;
image->pixels[(y+h)*col + x + i] = c;
}
for (i=0; i<h; i++) {
image->pixels[(y+i)*col + x] = c;
image->pixels[(y+i)*col + x + w] = c;
if (image->bpp>1) {
image->pixels[(y+i)*col + x+1] = c;
image->pixels[(y+i)*col + x + w+1] = c;
}
}
if (image->bpp>1) {
for (i=0; i<h; i++) {
image->pixels[(y+i)*col + x+1] = c;
image->pixels[(y+i)*col + x + w+1] = c;
}
}
}
void imlib_draw_circle(struct image *image, int cx, int cy, int r, color_t *color)
{
int x = r, y = 0;
int radiusError = 1-x;
uint16_t c = IM_RGB565(color->r, color->g, color->b);
if (cx+r >= image->w || cx-r < 0 ||
cy+r >= image->h || cy-r < 0) {
return;
}
while(x >= y) {
imlib_set_pixel(image, x + cx, y + cy, c);
imlib_set_pixel(image, y + cx, x + cy, c);
imlib_set_pixel(image, -x + cx, y + cy, c);
imlib_set_pixel(image, -y + cx, x + cy, c);
imlib_set_pixel(image, -x + cx, -y + cy, c);
imlib_set_pixel(image, -y + cx, -x + cy, c);
imlib_set_pixel(image, x + cx, -y + cy, c);
imlib_set_pixel(image, y + cx, -x + cy, c);
y++;
if (radiusError<0) {
radiusError += 2 * y + 1;
} else {
x--;
radiusError+= 2 * (y - x + 1);
}
}
}
void imlib_draw_line(image_t *src, int x0, int y0, int x1, int y1)
{
int dx, dy, sx, sy, err, e2;
if (x0<0||y0<0||x1>src->w||y1>src->h) {
return;
}
dx = abs(x1-x0);
dy = abs(y1-y0);
sx = x0<x1 ? 1 : -1;
sy = y0<y1 ? 1 : -1;
err = (dx>dy ? dx : -dy)/2;
for (;;) {
src->data[src->w*y0+x0]=0xFF;
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
// TODO check image bounds
void imlib_draw_string(image_t *src, int x_off, int y_off, const char *str, color_t *c)
{
const glyph_t *g;
uint8_t *srcp8 = (uint8_t*)src->pixels;
uint16_t *srcp16 = (uint16_t*)src->pixels;
uint16_t color = IM_RGB565(c->r, c->g, c->b);
for(char c; (c=*str); str++) {
if (c < ' ' || c > '~') {
continue;
}
g = &font[c-' '];
for (int y=0; y<g->h; y++) {
for (int x=0; x<g->w; x++) {
if (g->data[y] & (0x80>>x)){
if (src->bpp == 1) {
srcp8[(y_off+y)*src->w+x_off+x]=color;
} else {
srcp16[(y_off+y)*src->w+x_off+x]=color;
}
}
}
}
x_off += g->w;
}
}
void imlib_histeq(struct image *src)
{
int i, sum;

View File

@ -282,6 +282,12 @@ bool rectangle_intersects(rectangle_t *r1, rectangle_t *r2);
bool rectangle_subimg(image_t *img, rectangle_t *r, rectangle_t *r_out);
array_t *rectangle_merge(array_t *rectangles);
/* Drawing functions */
void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c);
void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c);
void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c);
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c);
/* Clustering functions */
array_t *cluster_kmeans(array_t *points, int k);
@ -350,12 +356,6 @@ int imlib_lbp_desc_load(const char *path, uint8_t **desc);
/* Eye detector */
void imlib_find_eyes(image_t *src, point_t *left, point_t *right, rectangle_t *roi);
/* Drawing functions */
void imlib_draw_rectangle(struct image *image, struct rectangle *r);
void imlib_draw_circle(struct image *image, int cx, int cy, int r, color_t *c);
void imlib_draw_line(image_t *src, int x0, int y0, int x1, int y1);
void imlib_draw_string(image_t *src, int x, int y, const char *str, color_t *c);
/* Misc */
void imlib_scale(struct image *src, struct image *dst, interp_t interp);
void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off);

View File

@ -238,6 +238,263 @@ static mp_obj_t py_image_set_pixel(mp_obj_t img_obj, mp_obj_t x_obj, mp_obj_t y_
return mp_const_none;
}
static mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
mp_obj_t *arg_vec; mp_obj_get_array_fixed_n(args[1], 4, &arg_vec);
int arg_x0 = mp_obj_get_int(arg_vec[0]);
int arg_y0 = mp_obj_get_int(arg_vec[1]);
int arg_x1 = mp_obj_get_int(arg_vec[2]);
int arg_y1 = mp_obj_get_int(arg_vec[3]);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 3) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[2]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[2], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c);
return mp_const_none;
}
static mp_obj_t py_image_draw_rectangle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
mp_obj_t *arg_vec; mp_obj_get_array_fixed_n(args[1], 4, &arg_vec);
int arg_rx = mp_obj_get_int(arg_vec[0]);
int arg_ry = mp_obj_get_int(arg_vec[1]);
int arg_rw = mp_obj_get_int(arg_vec[2]);
int arg_rh = mp_obj_get_int(arg_vec[3]);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 3) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[2]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[2], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c);
return mp_const_none;
}
static mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
int arg_cx = mp_obj_get_int(args[1]);
int arg_cy = mp_obj_get_int(args[2]);
int arg_r = mp_obj_get_int(args[3]);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 5) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[4]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[3], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_r, arg_c);
return mp_const_none;
}
static mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
int arg_x_off = mp_obj_get_int(args[1]);
int arg_y_off = mp_obj_get_int(args[2]);
const char *arg_str = mp_obj_str_get_str(args[3]);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 5) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[4]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[3], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, arg_c);
return mp_const_none;
}
static mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
int arg_x = mp_obj_get_int(args[1]);
int arg_y = mp_obj_get_int(args[2]);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 4) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[3]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[2], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
int size = 5;
mp_map_elem_t *kw_ksize = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("size")), MP_MAP_LOOKUP);
if (kw_ksize != NULL) {
size = mp_obj_get_int(kw_ksize->value);
}
imlib_draw_line(arg_img, arg_x-size, arg_y, arg_x+size, arg_y, arg_c);
imlib_draw_line(arg_img, arg_x, arg_y-size, arg_x, arg_y+size, arg_c);
return mp_const_none;
}
static mp_obj_t py_image_draw_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
image_t *arg_img = py_image_cobj(args[0]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img),
"Operation not supported on JPEG");
mp_obj_t kpts_obj = args[1];
PY_ASSERT_TYPE(kpts_obj, &py_kp_type);
int arg_c = -1; // white
mp_map_elem_t *kw_kcolor = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("color")), MP_MAP_LOOKUP);
if (kw_kcolor != NULL) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(kw_kcolor->value);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(kw_kcolor->value, 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
} else if(n_args >= 3) {
if(IM_IS_GS(arg_img)) {
arg_c = mp_obj_get_int(args[2]);
} else {
mp_obj_t *arg_color; mp_obj_get_array_fixed_n(args[2], 3, &arg_color);
int red = IM_R825(mp_obj_get_int(arg_color[0]));
int green = IM_G826(mp_obj_get_int(arg_color[1]));
int blue = IM_B825(mp_obj_get_int(arg_color[2]));
arg_c = IM_RGB565(red, green, blue);
}
}
int size = 10;
mp_map_elem_t *kw_ksize = mp_map_lookup(kw_args,
MP_OBJ_NEW_QSTR(qstr_from_str("size")), MP_MAP_LOOKUP);
if (kw_ksize != NULL) {
size = mp_obj_get_int(kw_ksize->value);
}
for (int i=0; i<((py_kp_obj_t*)kpts_obj)->size; i++) {
kp_t *kp = &((py_kp_obj_t*)kpts_obj)->kpts[i];
float co = arm_cos_f32(kp->angle);
float si = arm_sin_f32(kp->angle);
imlib_draw_line(arg_img, kp->x, kp->y, kp->x+(co*size), kp->y+(si*size), arg_c);
imlib_draw_circle(arg_img, kp->x, kp->y, (size-2)/2, arg_c);
}
return mp_const_none;
}
static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
int res;
@ -553,71 +810,6 @@ static mp_obj_t py_image_compress(mp_obj_t image_obj, mp_obj_t quality)
return py_image_from_struct(&cimage);
}
static mp_obj_t py_image_draw_line(mp_obj_t image_obj, mp_obj_t line_obj)
{
/* get image pointer */
struct image *image;
image = py_image_cobj(image_obj);
mp_obj_t *array;
mp_obj_get_array_fixed_n(line_obj, 4, &array);
int x0 = mp_obj_get_int(array[0]);
int y0 = mp_obj_get_int(array[1]);
int x1 = mp_obj_get_int(array[2]);
int y1 = mp_obj_get_int(array[3]);
imlib_draw_line(image, x0, y0, x1, y1);
return mp_const_none;
}
static mp_obj_t py_image_draw_circle(mp_obj_t image_obj, mp_obj_t c_obj, mp_obj_t r_obj)
{
int cx, cy, r;
mp_obj_t *array;
struct image *image;
color_t c = {.r=0xFF, .g=0xFF, .b=0xFF};
/* get image pointer */
image = py_image_cobj(image_obj);
/* center */
mp_obj_get_array_fixed_n(c_obj, 2, &array);
cx = mp_obj_get_int(array[0]);
cy = mp_obj_get_int(array[1]);
/* radius */
r = mp_obj_get_int(r_obj);
imlib_draw_circle(image, cx, cy, r, &c);
return mp_const_none;
}
static mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args)
{
int x = mp_obj_get_int(args[1]);
int y = mp_obj_get_int(args[2]);
image_t *image =py_image_cobj(args[0]);
const char *str = mp_obj_str_get_str(args[3]);
color_t c = {.r=0xFF, .g=0xFF, .b=0xFF};
// check x, y
PY_ASSERT_TRUE_MSG(x>=0 && x<image->w, "Image index out of range");
PY_ASSERT_TRUE_MSG(y>=0 && y<image->h, "Image index out of range");
PY_ASSERT_TRUE_MSG(image->bpp <= 2, "This function is not supported on JPEG images");
if (n_args == 5) {
// get color
mp_obj_t *array;
mp_obj_get_array_fixed_n(args[4], 3, &array);
c.r = mp_obj_get_int(array[0]);
c.g = mp_obj_get_int(array[1]);
c.b = mp_obj_get_int(array[2]);
}
imlib_draw_string(image, x, y, str, &c);
return mp_const_none;
}
static mp_obj_t py_image_erode(mp_obj_t image_obj, mp_obj_t ksize_obj)
{
image_t *image = NULL;
@ -658,51 +850,6 @@ static mp_obj_t py_image_morph(mp_obj_t image_obj, mp_obj_t ksize_obj)
return mp_const_none;
}
static mp_obj_t py_image_draw_rectangle(mp_obj_t image_obj, mp_obj_t rectangle_obj)
{
struct rectangle r;
struct image *image;
mp_obj_t *array;
mp_obj_get_array_fixed_n(rectangle_obj, 4, &array);
r.x = mp_obj_get_int(array[0]);
r.y = mp_obj_get_int(array[1]);
r.w = mp_obj_get_int(array[2]);
r.h = mp_obj_get_int(array[3]);
/* get image pointer */
image = py_image_cobj(image_obj);
imlib_draw_rectangle(image, &r);
return mp_const_none;
}
static mp_obj_t py_image_draw_keypoints(mp_obj_t image_obj, mp_obj_t kpts_obj)
{
image_t *image = NULL;
py_kp_obj_t *kpts=NULL;
/* get pointer */
image = py_image_cobj(image_obj);
kpts = (py_kp_obj_t*)kpts_obj;
/* sanity checks */
PY_ASSERT_TRUE_MSG(image->bpp == 1,
"This function is only supported on GRAYSCALE images");
PY_ASSERT_TYPE(kpts_obj, &py_kp_type);
color_t cl = {.r=0xFF, .g=0xFF, .b=0xFF};
for (int i=0; i<kpts->size; i++) {
kp_t *kp = &kpts->kpts[i];
float co = arm_cos_f32(kp->angle);
float si = arm_sin_f32(kp->angle);
imlib_draw_line(image, kp->x, kp->y, kp->x+(co*10), kp->y+(si*10));
imlib_draw_circle(image, kp->x, kp->y, 4, &cl);
}
return mp_const_none;
}
static mp_obj_t py_image_find_blobs(mp_obj_t image_obj)
{
/* C stuff */
@ -1033,6 +1180,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_get_pixel_obj, py_image_get_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_set_pixel_obj, 4, 4, py_image_set_pixel);
/* Drawing functions */
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 3, py_image_draw_cross);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scale_obj, py_image_scale);
@ -1051,12 +1205,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_dilate_obj, py_image_dilate);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_morph_obj, py_image_morph);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_compress_obj, py_image_compress);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_draw_line_obj, py_image_draw_line);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_draw_circle_obj, py_image_draw_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_draw_rectangle_obj, py_image_draw_rectangle);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_draw_keypoints_obj, py_image_draw_keypoints);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_draw_string_obj, 4, 5, py_image_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_find_blobs_obj, py_image_find_blobs);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_find_template_obj, py_image_find_template);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_features_obj, 2, py_image_find_features);
@ -1073,7 +1221,14 @@ static const mp_map_elem_t locals_dict_table[] = {
{MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&py_image_size_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_get_pixel), (mp_obj_t)&py_image_get_pixel_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_set_pixel), (mp_obj_t)&py_image_set_pixel_obj},
/* Drawing functions */
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_line), (mp_obj_t)&py_image_draw_line_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_rectangle), (mp_obj_t)&py_image_draw_rectangle_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&py_image_draw_circle_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_string), (mp_obj_t)&py_image_draw_string_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_cross), (mp_obj_t)&py_image_draw_cross_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_keypoints), (mp_obj_t)&py_image_draw_keypoints_obj},
/* basic image functions */
{MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_scale), (mp_obj_t)&py_image_scale_obj},
@ -1092,13 +1247,6 @@ static const mp_map_elem_t locals_dict_table[] = {
// {MP_OBJ_NEW_QSTR(MP_QSTR_morph), (mp_obj_t)&py_image_morph_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_compress), (mp_obj_t)&py_image_compress_obj},
/* drawing functions */
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_line), (mp_obj_t)&py_image_draw_line_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&py_image_draw_circle_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_rectangle), (mp_obj_t)&py_image_draw_rectangle_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_keypoints), (mp_obj_t)&py_image_draw_keypoints_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_string), (mp_obj_t)&py_image_draw_string_obj},
/* objects/feature detection */
{MP_OBJ_NEW_QSTR(MP_QSTR_find_blobs), (mp_obj_t)&py_image_find_blobs_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_find_template), (mp_obj_t)&py_image_find_template_obj},

View File

@ -18,8 +18,10 @@ for i in range(0, 3):
x = int(320/2)
y = int(240/2)
image.draw_circle((x, y), 50)
image.draw_circle(x, y, 50)
image.draw_line((x, y, int(50*sin(45))+x, int(50*cos(45))+y))
image.draw_rectangle((x-60, y-60, 120, 120))
image.draw_string(10, 10, "OpenMV", (0xFF, 0xFF, 0xFF))
image.draw_string(10, 25, "Hello World", (0xFF, 0xFF, 0xFF))
image.draw_string(10, 10, "OpenMV", 0xFF)
image.draw_string(10, 25, "Hello World", 0xFF)
# Flush buffer...
sensor.snapshot()

View File

@ -14,10 +14,6 @@ sensor.set_pixformat(sensor.GRAYSCALE)
face_cascade = image.HaarCascade("frontalface", stages=16)
print(face_cascade)
def draw_cross(img, x, y, l):
img.draw_line((x-l, y, x+l, y))
img.draw_line((x, y-l, x, y+l))
# FPS clock
clock = time.clock()
while (True):
@ -35,8 +31,8 @@ while (True):
for roi in objects:
#img.histeq()
eyes = img.find_eyes(roi)
draw_cross(img, eyes[0], eyes[1], 5)
draw_cross(img, eyes[2], eyes[3], 5)
img.draw_cross(eyes[0], eyes[1])
img.draw_cross(eyes[2], eyes[3])
img.draw_rectangle(roi)
if (len(objects)):

View File

@ -18,10 +18,6 @@ print(face_cascade, eyes_cascade)
# FPS clock
clock = time.clock()
def draw_cross(img, x, y, l):
img.draw_line((x-l, y, x+l, y))
img.draw_line((x, y-l, x, y+l))
while (True):
clock.tick()
@ -43,8 +39,8 @@ while (True):
e = [face[0]+e[0], face[1]+e[1], e[2], e[3]] # Add face offset
img.draw_rectangle(e)
# Draw crosshair, add width/2 and height/2
draw_cross(img, e[0]+int(e[2]/2), e[1]+int(e[3]/2), 5)
img.draw_cross(e[0]+int(e[2]/2), e[1]+int(e[3]/2))
# Print FPS.
# Note: Actual FPS is higher, streaming the FB makes it slower.
print(clock.fps())
print(clock.fps())

View File

@ -49,7 +49,6 @@ while (True):
c=img.match_keypoints(kpts1, kpts2, 70)
if (c):
l=10
img.draw_line((c[0]-l, c[1], c[0]+l, c[1]))
img.draw_line((c[0], c[1]-l, c[0], c[1]+l))
img.draw_cross(c[0], c[1])
time.sleep(10)
print (clock.fps())

View File

@ -26,10 +26,6 @@ while (kpts1 == None):
print (kpts1)
time.sleep(1000)
def draw_cross(img, x, y, l):
img.draw_line((x-l, y, x+l, y))
img.draw_line((x, y-l, x, y+l))
clock = time.clock()
while (True):
clock.tick()
@ -40,6 +36,6 @@ while (True):
c=img.match_keypoints(kpts1, kpts2, MATCHING_THRESH)
if (c):
draw_cross(img, c[0], c[1], 10)
img.draw_cross(c[0], c[1], size = 10)
time.sleep(10)
print (clock.fps())

104
usr/tests/test_drawing_1.py Normal file
View File

@ -0,0 +1,104 @@
import pyb, sensor, image
sensor.reset()
sensor.set_framesize(sensor.QVGA)
while(True):
# Test Set Pixel
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.set_pixel(x, y, 255)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.set_pixel(x, y, (255, 255, 255))
# Test Draw Line
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x0 = (pyb.rng() % (2*img.width())) - (img.width()//2)
y0 = (pyb.rng() % (2*img.height())) - (img.height()//2)
x1 = (pyb.rng() % (2*img.width())) - (img.width()//2)
y1 = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_line([x0, y0, x1, y1])
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x0 = (pyb.rng() % (2*img.width())) - (img.width()//2)
y0 = (pyb.rng() % (2*img.height())) - (img.height()//2)
x1 = (pyb.rng() % (2*img.width())) - (img.width()//2)
y1 = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_line([x0, y0, x1, y1])
# Test Draw Rectangle
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
w = (pyb.rng() % img.width())
h = (pyb.rng() % img.height())
img.draw_rectangle([x, y, w, h])
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
w = (pyb.rng() % img.width())
h = (pyb.rng() % img.height())
img.draw_rectangle([x, y, w, h])
# Test Draw Circle
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
r = (pyb.rng() % (img.width() if (img.width() > img.height()) else img.height()))
img.draw_circle(x, y, r)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
r = (pyb.rng() % (img.width() if (img.width() > img.height()) else img.height()))
img.draw_circle(x, y, r)
# Test Draw String
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_string(x, y, "Hello\nWorld!")
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_string(x, y, "Hello\nWorld!")
# Test Draw Cross
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_cross(x, y)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for j in range(100):
x = (pyb.rng() % (2*img.width())) - (img.width()//2)
y = (pyb.rng() % (2*img.height())) - (img.height()//2)
img.draw_cross(x, y)

View File

@ -0,0 +1,63 @@
import sensor, image, time
sensor.reset()
sensor.set_framesize(sensor.QVGA)
# All drawing functions use the same code to pass color.
# So we just need to test one function.
# TODO: Why does MP need int(c) when c is computed using "//"?
while(True):
# Test Draw Line (GRAYSCALE)
sensor.set_pixformat(sensor.GRAYSCALE)
for i in range(10):
img = sensor.snapshot()
for i in range(img.width()):
c = ((i * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], int(c))
sensor.snapshot()
time.sleep(1000)
for i in range(img.width()):
c = (((img.width() - i) * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], color = int(c))
sensor.snapshot()
time.sleep(1000)
# Test Draw Line (RGB565)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for i in range(img.width()):
c = ((i * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], [int(c), 0, 0])
sensor.snapshot()
time.sleep(1000)
for i in range(img.width()):
c = (((img.width() - i) * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], color = [int(c), 0, 0])
sensor.snapshot()
time.sleep(1000)
# Test Draw Line (RGB565)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for i in range(img.width()):
c = ((i * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], [0, int(c), 0])
sensor.snapshot()
time.sleep(1000)
for i in range(img.width()):
c = (((img.width() - i) * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], color = [0, int(c), 0])
sensor.snapshot()
time.sleep(1000)
# Test Draw Line (RGB565)
sensor.set_pixformat(sensor.RGB565)
for i in range(10):
img = sensor.snapshot()
for i in range(img.width()):
c = ((i * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], [0, 0, int(c)])
sensor.snapshot()
time.sleep(1000)
for i in range(img.width()):
c = (((img.width() - i) * 255) + (img.width()/2)) // img.width()
img.draw_line([i, 0, i, img.height()-1], color = [0, 0, int(c)])
sensor.snapshot()
time.sleep(1000)