Merge pull request #322 from kwagyeman/master

Upgrade Drawing Features
This commit is contained in:
Ibrahim Abd Elkader 2018-03-12 16:38:24 +02:00 committed by GitHub
commit 0a5146e393
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 541 additions and 355 deletions

View File

@ -153,6 +153,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
binary.o \
blob.o \
draw.o \
qrcode.o \
apriltag.o \
dmtx.o \

View File

@ -24,6 +24,7 @@ SRCS += $(addprefix , \
SRCS += $(addprefix img/, \
binary.c \
blob.c \
draw.c \
qrcode.c \
apriltag.c \
dmtx.c \

211
src/omv/img/draw.c Normal file
View File

@ -0,0 +1,211 @@
/* This file is part of the OpenMV project.
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
* This work is licensed under the MIT license, see the file LICENSE for details.
*/
#include "font.h"
#include "imlib.h"
// Get pixel (handles boundary check and image type check).
int imlib_get_pixel(image_t *img, int x, int y)
{
if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) {
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
return IMAGE_GET_BINARY_PIXEL(img, x, y);
}
case IMAGE_BPP_GRAYSCALE: {
return IMAGE_GET_GRAYSCALE_PIXEL(img, x, y);
}
case IMAGE_BPP_RGB565: {
return IMAGE_GET_RGB565_PIXEL(img, x, y);
}
default: {
return -1;
}
}
}
return -1;
}
// Set pixel (handles boundary check and image type check).
void imlib_set_pixel(image_t *img, int x, int y, int p)
{
if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) {
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
IMAGE_PUT_BINARY_PIXEL(img, x, y, p);
break;
}
case IMAGE_BPP_GRAYSCALE: {
IMAGE_PUT_GRAYSCALE_PIXEL(img, x, y, p);
break;
}
case IMAGE_BPP_RGB565: {
IMAGE_PUT_RGB565_PIXEL(img, x, y, p);
break;
}
default: {
break;
}
}
}
}
// https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
static void point_fill(image_t *img, int cx, int cy, int r0, int r1, int c)
{
for (int y = r0; y <= r1; y++) {
for (int x = r0; x <= r1; x++) {
if (((x * x) + (y * y)) <= (r0 * r0)) {
imlib_set_pixel(img, cx + x, cy + y, c);
}
}
}
}
// https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness)
{
if (thickness > 0) {
int thickness0 = (thickness - 0) / 2;
int thickness1 = (thickness - 1) / 2;
int dx = abs(x1 - x0), sx = (x0 < x1) ? 1 : -1;
int dy = abs(y1 - y0), sy = (y0 < y1) ? 1 : -1;
int err = ((dx > dy) ? dx : -dy) / 2;
for (;;) {
point_fill(img, x0, y0, -thickness0, thickness1, c);
if ((x0 == x1) && (y0 == y1)) break;
int e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
}
static void xLine(image_t *img, int x1, int x2, int y, int c)
{
while (x1 <= x2) imlib_set_pixel(img, x1++, y, c);
}
static void yLine(image_t *img, int x, int y1, int y2, int c)
{
while (y1 <= y2) imlib_set_pixel(img, x, y1++, c);
}
void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill)
{
if (fill) {
for (int y = ry, yy = ry + rh; y < yy; y++) {
for (int x = rx, xx = rx + rw; x < xx; x++) {
imlib_set_pixel(img, x, y, c);
}
}
} else if (thickness > 0) {
int thickness0 = (thickness - 0) / 2;
int thickness1 = (thickness - 1) / 2;
for (int i = rx - thickness0, j = rx + rw + thickness1, k = ry + rh - 1; i < j; i++) {
yLine(img, i, ry - thickness0, ry + thickness1, c);
yLine(img, i, k - thickness0, k + thickness1, c);
}
for (int i = ry - thickness0, j = ry + rh + thickness1, k = rx + rw - 1; i < j; i++) {
xLine(img, rx - thickness0, rx + thickness1, i, c);
xLine(img, k - thickness0, k + thickness1, i, c);
}
}
}
// https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm
void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill)
{
if (fill) {
point_fill(img, cx, cy, -r, r, c);
} else if (thickness > 0) {
int thickness0 = (thickness - 0) / 2;
int thickness1 = (thickness - 1) / 2;
int xo = r + thickness0;
int xi = IM_MAX(r - thickness1, 0);
int xi_tmp = xi;
int y = 0;
int erro = 1 - xo;
int erri = 1 - xi;
while(xo >= y) {
xLine(img, cx + xi, cx + xo, cy + y, c);
yLine(img, cx + y, cy + xi, cy + xo, c);
xLine(img, cx - xo, cx - xi, cy + y, c);
yLine(img, cx - y, cy + xi, cy + xo, c);
xLine(img, cx - xo, cx - xi, cy - y, c);
yLine(img, cx - y, cy - xo, cy - xi, c);
xLine(img, cx + xi, cx + xo, cy - y, c);
yLine(img, cx + y, cy - xo, cy - xi, c);
y++;
if (erro < 0) {
erro += 2 * y + 1;
} else {
xo--;
erro += 2 * (y - xo + 1);
}
if (y > xi_tmp) {
xi = y;
} else {
if (erri < 0) {
erri += 2 * y + 1;
} else {
xi--;
erri += 2 * (y - xi + 1);
}
}
}
}
}
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale)
{
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 * scale; // newline height == space height
continue;
}
if ((ch < ' ') || (ch > '~')) { // handle unknown characters
imlib_draw_rectangle(img,
x_off + ((scale * 3) / 2),
y_off + ((scale * 3) / 2),
(font[0].w * scale) - (((scale * 3) / 2) * 2),
(font[0].h * scale) - (((scale * 3) / 2) * 2),
c, scale, false);
continue;
}
const glyph_t *g = &font[ch - ' '];
for (int y = 0, yy = g->h * scale; y < yy; y++) {
for (int x = 0, xx = g->w * scale; x < xx; x++) {
if (g->data[y / scale] & (1 << (g->w - (x / scale)))) {
imlib_set_pixel(img, (x_off + x), (y_off + y), c);
}
}
}
x_off += g->w * scale;
}
}

View File

@ -117,7 +117,7 @@ void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size)
bin_t *bin = array_at(gds, i);
int x2 = l * cos_table[bin->d];
int y2 = l * sin_table[bin->d];
imlib_draw_line(src, (x1 - x2), (y1 + y2), (x1 + x2), (y1 - y2), bin->m);
imlib_draw_line(src, (x1 - x2), (y1 + y2), (x1 + x2), (y1 - y2), bin->m, 1);
}
hog_index += N_BINS;

View File

@ -519,139 +519,6 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
}
}
void imlib_copy_image(image_t *dst, image_t *src, rectangle_t *roi)
{
if (IM_IS_JPEG(src)) {
dst->w = src->w;
dst->h = src->h;
dst->bpp = src->bpp;
dst->pixels = xalloc(src->bpp);
memcpy(dst->pixels, src->pixels, src->bpp);
} else {
rectangle_t rect;
if (!rectangle_subimg(src, roi, &rect)) ff_no_intersection(NULL);
dst->w = rect.w;
dst->h = rect.h;
dst->bpp = src->bpp;
dst->pixels = xalloc(rect.w * rect.h * src->bpp);
uint8_t *dst_pointer = dst->pixels;
for (int i = rect.y; i < (rect.y + rect.h); i++) {
int length = rect.w * src->bpp;
memcpy(dst_pointer,
src->pixels + (rect.x * src->bpp) + (i * src->w * src->bpp),
length);
dst_pointer += length;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Get pixel (handles boundary check and image type check).
int imlib_get_pixel(image_t *img, int x, int y)
{
return (IM_X_INSIDE(img, x) && IM_Y_INSIDE(img, y)) ?
( IM_IS_GS(img)
? IM_GET_GS_PIXEL(img, x, y)
: IM_GET_RGB565_PIXEL(img, x, y) )
: 0;
}
// Set pixel (handles boundary check and image type check).
void imlib_set_pixel(image_t *img, int x, int y, int p)
{
if (IM_X_INSIDE(img, x) && IM_Y_INSIDE(img, y)) {
if (IM_IS_GS(img)) {
IM_SET_GS_PIXEL(img, x, y, p);
} else {
IM_SET_RGB565_PIXEL(img, x, y, 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;
}
}
////////////////////////////////////////////////////////////////////////////////
void imlib_histeq(image_t *img)

View File

@ -218,7 +218,7 @@ extern const uint8_t g826_table[256];
__typeof__ (r5) _r5 = (r5); \
__typeof__ (g6) _g6 = (g6); \
__typeof__ (b5) _b5 = (b5); \
(_r5 << 3) | (_g6 >> 3) | (_g6 << 13) | (_b5 << 8); \
(_r5 << 3) | (_g6 >> 3) | ((_g6 & 0x7) << 13) | (_b5 << 8); \
})
#define COLOR_R8_G8_B8_TO_RGB565(r8, g8, b8) COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(r8), COLOR_G8_TO_G6(g8), COLOR_B8_TO_B5(b8))
@ -1107,7 +1107,6 @@ bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_setti
void imlib_image_operation(image_t *img, const char *path, image_t *other, line_op_t op, void *data);
void imlib_load_image(image_t *img, const char *path);
void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int quality);
void imlib_copy_image(image_t *dst, image_t *src, rectangle_t *roi);
/* GIF functions */
void gif_open(FIL *fp, int width, int height, bool color, bool loop);
@ -1119,10 +1118,6 @@ void mjpeg_open(FIL *fp, int width, int height);
void mjpeg_add_frame(FIL *fp, uint32_t *frames, uint32_t *bytes, image_t *img, int quality);
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps);
/* Basic image functions */
int imlib_get_pixel(image_t *img, int x, int y);
void imlib_set_pixel(image_t *img, int x, int y, int p);
/* Point functions */
point_t *point_alloc(int16_t x, int16_t y);
bool point_equal(point_t *p1, point_t *p2);
@ -1136,12 +1131,6 @@ bool rectangle_subimg(image_t *img, rectangle_t *r, rectangle_t *r_out);
array_t *rectangle_merge(array_t *rectangles);
void rectangle_expand(rectangle_t *r, int x, int y);
/* 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);
/* Image Morphing */
void imlib_morph(image_t *img, const int ksize, const int8_t *krn, const float m, const int b);
@ -1226,6 +1215,13 @@ void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_t
// HoG
void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size);
// Drawing Functions
int imlib_get_pixel(image_t *img, int x, int y);
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_string(image_t *img, int x_off, int y_off, const char *str, int c, int scale);
// Binary Functions
void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero);
void imlib_invert(image_t *img);

View File

@ -181,9 +181,9 @@ int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uin
} else {
mp_obj_t *arg_color;
mp_obj_get_array_fixed_n(kw_arg->value, 3, &arg_color);
default_val = COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(mp_obj_get_int(arg_color[0])),
COLOR_G8_TO_G6(mp_obj_get_int(arg_color[1])),
COLOR_B8_TO_B5(mp_obj_get_int(arg_color[2])));
default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN),
IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN),
IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN));
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
default_val = COLOR_RGB565_TO_BINARY(default_val);
@ -204,9 +204,9 @@ int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uin
} else {
mp_obj_t *arg_color;
mp_obj_get_array_fixed_n(args[arg_index], 3, &arg_color);
default_val = COLOR_R5_G6_B5_TO_RGB565(COLOR_R8_TO_R5(mp_obj_get_int(arg_color[0])),
COLOR_G8_TO_G6(mp_obj_get_int(arg_color[1])),
COLOR_B8_TO_B5(mp_obj_get_int(arg_color[2])));
default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN),
IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN),
IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN));
switch(img->bpp) {
case IMAGE_BPP_BINARY: {
default_val = COLOR_RGB565_TO_BINARY(default_val);

View File

@ -106,6 +106,12 @@ static const mp_obj_type_t py_kp_type = {
.unary_op = py_kp_unary_op,
};
py_kp_obj_t *py_kpts_obj(mp_obj_t kpts_obj)
{
PY_ASSERT_TYPE(kpts_obj, &py_kp_type);
return kpts_obj;
}
// LBP descriptor /////////////////////////////////////////////////////////////
typedef struct _py_lbp_obj_t {
@ -1012,9 +1018,11 @@ STATIC mp_obj_t py_image_draw_line(uint n_args, const mp_obj_t *args, mp_map_t *
int arg_y1 = mp_obj_get_int(arg_vec[3]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c);
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_line_obj, 2, py_image_draw_line);
@ -1031,9 +1039,13 @@ STATIC mp_obj_t py_image_draw_rectangle(uint n_args, const mp_obj_t *args, mp_ma
int arg_rh = mp_obj_get_int(arg_vec[3]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c);
imlib_draw_rectangle(arg_img, arg_rx, arg_ry, arg_rw, arg_rh, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_rectangle_obj, 2, py_image_draw_rectangle);
@ -1049,9 +1061,13 @@ STATIC mp_obj_t py_image_draw_circle(uint n_args, const mp_obj_t *args, mp_map_t
int arg_cr = mp_obj_get_int(arg_vec[2]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c);
imlib_draw_circle(arg_img, arg_cx, arg_cy, arg_cr, arg_c, arg_thickness, arg_fill);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_circle);
@ -1067,9 +1083,11 @@ STATIC mp_obj_t py_image_draw_string(uint n_args, const mp_obj_t *args, mp_map_t
const char *arg_str = mp_obj_str_get_str(arg_vec[2]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_scale =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale), 1);
imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, arg_c);
imlib_draw_string(arg_img, arg_x_off, arg_y_off, arg_str, arg_c, arg_scale);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string);
@ -1084,36 +1102,79 @@ STATIC mp_obj_t py_image_draw_cross(uint n_args, const mp_obj_t *args, mp_map_t
int arg_y = mp_obj_get_int(arg_vec[1]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 5);
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
imlib_draw_line(arg_img, arg_x-arg_s, arg_y , arg_x+arg_s, arg_y , arg_c);
imlib_draw_line(arg_img, arg_x , arg_y-arg_s, arg_x , arg_y+arg_s, arg_c);
imlib_draw_line(arg_img, arg_x - arg_s, arg_y , arg_x + arg_s, arg_y , arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x , arg_y - arg_s, arg_x , arg_y + arg_s, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 2, py_image_draw_cross);
STATIC mp_obj_t py_image_draw_arrow(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_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 =
py_helper_keyword_color(arg_img, n_args, args, offset + 0, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, offset + 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10);
int arg_thickness =
py_helper_keyword_int(n_args, args, offset + 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
int dx = (arg_x1 - arg_x0);
int dy = (arg_y1 - arg_y0);
float length = fast_sqrtf((dx * dx) + (dy * dy));
float ux = dx / length;
float uy = dy / length;
float vx = -uy;
float vy = ux;
int a0x = fast_roundf(arg_x1 - (arg_s * ux) + (arg_s * vx * 0.5));
int a0y = fast_roundf(arg_y1 - (arg_s * uy) + (arg_s * vy * 0.5));
int a1x = fast_roundf(arg_x1 - (arg_s * ux) - (arg_s * vx * 0.5));
int a1y = fast_roundf(arg_y1 - (arg_s * uy) - (arg_s * vy * 0.5));
imlib_draw_line(arg_img, arg_x0, arg_y0, arg_x1, arg_y1, arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x1, arg_y1, a0x, a0y, arg_c, arg_thickness);
imlib_draw_line(arg_img, arg_x1, arg_y1, a1x, a1y, arg_c, arg_thickness);
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_arrow_obj, 2, py_image_draw_arrow);
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_helper_arg_to_image_mutable(args[0]);
py_kp_obj_t *kpts_obj = (py_kp_obj_t*) args[1];
PY_ASSERT_TYPE(kpts_obj, &py_kp_type);
py_kp_obj_t *kpts_obj = py_kpts_obj(args[1]);
int arg_c =
py_helper_keyword_color(arg_img, n_args, args, 2, kw_args, -1); // White.
int arg_s =
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), arg_img->w * 0.1f);
py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 10);
int arg_thickness =
py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thickness), 1);
bool arg_fill =
py_helper_keyword_int(n_args, args, 5, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_fill), false);
for (int i=0; i<array_length(kpts_obj->kpts); i++) {
for (int i = 0, ii = array_length(kpts_obj->kpts); i < ii; i++) {
kp_t *kp = array_at(kpts_obj->kpts, i);
int cx = kp->x;
int cy = kp->y;
int size = arg_s/2;
int si = sin_table[kp->angle] * size;
int co = cos_table[kp->angle] * size;
imlib_draw_line(arg_img, cx, cy, cx+co, cy+si, arg_c);
imlib_draw_circle(arg_img, cx, cy, size, arg_c);
int si = sin_table[kp->angle] * arg_s;
int co = cos_table[kp->angle] * arg_s;
imlib_draw_line(arg_img, cx, cy, cx + co, cy + si, arg_c, arg_thickness);
imlib_draw_circle(arg_img, cx, cy, (arg_s - 2) / 2, arg_c, arg_thickness, arg_fill);
}
return args[0];
@ -4572,6 +4633,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&py_image_draw_circle_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)},
{MP_ROM_QSTR(MP_QSTR_draw_keypoints), MP_ROM_PTR(&py_image_draw_keypoints_obj)},
/* Binary Methods */
{MP_ROM_QSTR(MP_QSTR_binary), MP_ROM_PTR(&py_image_binary_obj)},

View File

@ -38,15 +38,6 @@ Q(width)
Q(height)
Q(format)
Q(size)
Q(get_pixel)
Q(rgbtuple)
Q(set_pixel)
Q(draw_line)
Q(draw_rectangle)
Q(draw_circle)
Q(draw_string)
Q(draw_cross)
Q(draw_keypoints)
Q(morph)
Q(midpoint)
Q(mean)
@ -70,7 +61,6 @@ Q(find_edges)
Q(find_hog)
Q(cmp_lbp)
Q(quality)
Q(color)
Q(roi)
Q(offset)
Q(threshold)
@ -330,6 +320,55 @@ Q(CPUFREQ_216MHZ)
Q(get_frequency)
Q(set_frequency)
// Get Pixel
Q(get_pixel)
Q(rgbtuple)
// Set Pixel
Q(set_pixel)
Q(color)
// Draw Line
Q(draw_line)
// duplicate Q(color)
Q(thickness)
// Draw Rectangle
Q(draw_rectangle)
// duplicate Q(color)
// duplicate Q(thickness)
Q(fill)
// Draw Circle
Q(draw_circle)
// duplicate Q(color)
// duplicate Q(thickness)
// duplicate Q(fill)
// Draw String
Q(draw_string)
// duplicate Q(color)
// duplicate Q(scale)
// Draw Cross
Q(draw_cross)
// duplicate Q(color)
// duplicate Q(size)
// duplicate Q(thickness)
// Draw Arrow
Q(draw_arrow)
// duplicate Q(color)
// duplicate Q(size)
// duplicate Q(thickness)
// Draw Keypoints
Q(draw_keypoints)
// duplicate Q(color)
// duplicate Q(size)
// duplicate Q(thickness)
// duplicate Q(fill)
// Binary
Q(binary)
Q(invert)

View File

@ -0,0 +1,31 @@
# Arrow Drawing
#
# This example shows off drawing arrows 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):
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)
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 x0, y0, x1, and y1. Otherwise, it expects a (x0,y0,x1,y1) tuple.
img.draw_arrow(x0, y0, x1, y1, color = (r, g, b), size = 30, thickness = 2)
print(clock.fps())

View File

@ -0,0 +1,31 @@
# Circle Drawing
#
# This example shows off drawing circles 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 = pyb.rng() % (max(img.height(), img.width())//2)
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, and radius. Otherwise, it expects a (x,y,radius) tuple.
img.draw_circle(x, y, radius, color = (r, g, b), thickness = 2, fill = False)
print(clock.fps())

View File

@ -1,55 +0,0 @@
# Color Drawing Example
#
# This example shows off your OpenMV Cam's built-in drawing capabilities. This
# example was originally a test but serves as good reference code. Please put
# your IDE into non-JPEG mode to see the best drawing quality.
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.
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], 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], 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], 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], color = [0, 0, int(c)])
sensor.snapshot()
time.sleep(1000)

View File

@ -1,118 +0,0 @@
# Crazy Drawing Example
#
# This example shows off your OpenMV Cam's built-in drawing capabilities. This
# example was originally a test but serves as good reference code. Please put
# your IDE into non-JPEG mode to see the best drawing quality.
import pyb, sensor, image, math
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,29 @@
# Cross Drawing
#
# This example shows off drawing crosses 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)
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 and y. Otherwise, it expects a (x,y) tuple.
img.draw_cross(x, y, color = (r, g, b), size = 10, thickness = 2)
print(clock.fps())

View File

@ -0,0 +1,31 @@
# Line Drawing
#
# This example shows off drawing lines 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):
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)
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 x0, y0, x1, and y1. Otherwise, it expects a (x0,y0,x1,y1) tuple.
img.draw_line(x0, y0, x1, y1, color = (r, g, b), thickness = 2)
print(clock.fps())

View File

@ -0,0 +1,31 @@
# Rectangle Drawing
#
# This example shows off drawing rectangles 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)
w = (pyb.rng() % (img.width()//2))
h = (pyb.rng() % (img.height()//2))
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, w, and h. Otherwise, it expects a (x,y,w,h) tuple.
img.draw_rectangle(x, y, w, h, color = (r, g, b), thickness = 2, fill = False)
print(clock.fps())

View File

@ -0,0 +1,29 @@
# Text Drawing
#
# This example shows off drawing text 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)
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, and text. Otherwise, it expects a (x,y,text) tuple.
img.draw_string(x, y, "Hello World!", color = (r, g, b), scale = 2)
print(clock.fps())