diff --git a/src/omv/img/imlib.c b/src/omv/img/imlib.c index 085c68285..c1e98acac 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -9,16 +9,13 @@ #include #include #include -#include #include -#include "array.h" -#include "imlib.h" -#include "ff.h" -#include "ff_wrapper.h" -#include "mdefs.h" #include "font.h" +#include "array.h" +#include "ff_wrapper.h" #include "fb_alloc.h" #include "xalloc.h" +#include "imlib.h" // Gamma uncompress extern const float xyz_table[256]; @@ -798,58 +795,67 @@ void imlib_blend(image_t *img, const char *path, image_t *other, int alpha) //////////////////////////////////////////////////////////////////////////////// -int imlib_image_mean(struct image *src) +void imlib_histeq(image_t *img) +{ + if (IM_IS_GS(img)) { + int a = img->w * img->h; + float s = IM_MAX_GS / ((float)a); + uint32_t *hist = fb_alloc0(IM_G_HIST_SIZE * sizeof(uint32_t)); + + /* compute image histogram */ + for (int i=0; ipixels[i]] += 1; + } + + /* compute the CDF */ + for (int i=0, sum=0; ipixels[i] = s * hist[img->pixels[i]]; + } + + fb_free(); + } else { + // do nothing for now + } +} + +//////////////////////////////////////////////////////////////////////////////// + +int imlib_image_mean(image_t *src) { int s=0; - int x,y; - int n = src->w*src->h; + int n=src->w*src->h; - for (y=0; yh; y++) { - for (x=0; xw; x++) { - s += src->data[src->w*y+x]; - } + for (int i=0; ipixels[i]; } /* mean */ return s/n; } -void imlib_histeq(struct image *src) +// One pass standard deviation. +int imlib_image_std(image_t *src) { - int i, sum; - int a = src->w*src->h; - uint32_t hist[IM_MAX_GS+1]={0}; - - /* compute image histogram */ - for (i=0; ipixels[i]]+=1; - } - - /* compute the CDF */ - for (i=0, sum=0; ipixels[i] = (uint8_t) ((IM_MAX_GS/(float)a) * hist[src->pixels[i]]); - } -} - -// One pass standard deviation -int imlib_std(image_t *image) -{ - int w=image->w; - int h=image->h; - int n = w*h; - uint8_t *data = image->pixels; + int w=src->w; + int h=src->h; + int n=w*h; + uint8_t *data=src->pixels; uint32_t s=0, sq=0; for (int i=0; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * MicroPython helper functions. + * + */ #include "py_helper.h" int py_helper_lookup_int(mp_map_t *kw_args, mp_obj_t kw, int default_val) diff --git a/src/omv/py/py_helper.h b/src/omv/py/py_helper.h index ba107cf42..f8dc49e2b 100644 --- a/src/omv/py/py_helper.h +++ b/src/omv/py/py_helper.h @@ -8,6 +8,8 @@ */ #ifndef __PY_HELPER_H__ #define __PY_HELPER_H__ +#include +#include "imlib.h" int py_helper_lookup_int(mp_map_t *kw_args, mp_obj_t kw, int default_val); float py_helper_lookup_float(mp_map_t *kw_args, mp_obj_t kw, float default_val); int py_helper_lookup_color(mp_map_t *kw_args, int default_color); diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index a3268e7c9..72e0e0cf4 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -6,27 +6,26 @@ * Image Python module. * */ -#include "mp.h" +#include +#include #include "imlib.h" #include "array.h" #include "sensor.h" #include "ff.h" #include "xalloc.h" #include "fb_alloc.h" -#include "arm_math.h" +#include "framebuffer.h" #include "py_assert.h" #include "py_helper.h" #include "py_image.h" -#include "omv_boardconfig.h" -#include "framebuffer.h" -extern sensor_t sensor; static const mp_obj_type_t py_cascade_type; static const mp_obj_type_t py_image_type; extern const char *ffs_strerror(FRESULT res); -/* Haar Cascade */ +// Haar Cascade /////////////////////////////////////////////////////////////// + typedef struct _py_cascade_obj_t { mp_obj_base_t base; struct cascade _cobj; @@ -41,9 +40,9 @@ void *py_cascade_cobj(mp_obj_t cascade) static void py_cascade_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { py_cascade_obj_t *self = self_in; - /* print some info */ - mp_printf(print, "width:%d height:%d n_stages:%d n_features:%d n_rectangles:%d\n", self->_cobj.window.w, - self->_cobj.window.h, self->_cobj.n_stages, self->_cobj.n_features, self->_cobj.n_rectangles); + mp_printf(print, "width:%d height:%d n_stages:%d n_features:%d n_rectangles:%d\n", + self->_cobj.window.w, self->_cobj.window.h, self->_cobj.n_stages, + self->_cobj.n_features, self->_cobj.n_rectangles); } static const mp_obj_type_t py_cascade_type = { @@ -52,7 +51,8 @@ static const mp_obj_type_t py_cascade_type = { .print = py_cascade_print, }; -/* Keypoints object */ +// Keypoints object /////////////////////////////////////////////////////////// + typedef struct _py_kp_obj_t { mp_obj_base_t base; array_t *kpts; @@ -72,7 +72,8 @@ static const mp_obj_type_t py_kp_type = { .print = py_kp_print, }; -/* LBP descriptor */ +// LBP descriptor ///////////////////////////////////////////////////////////// + typedef struct _py_lbp_obj_t { mp_obj_base_t base; uint8_t *hist; @@ -89,16 +90,17 @@ static const mp_obj_type_t py_lbp_type = { .print = py_lbp_print, }; -/* Image */ +// Image ////////////////////////////////////////////////////////////////////// + typedef struct _py_image_obj_t { mp_obj_base_t base; - struct image _cobj; + image_t _cobj; } py_image_obj_t; -void *py_image_cobj(mp_obj_t image) +void *py_image_cobj(mp_obj_t img_obj) { - PY_ASSERT_TYPE(image, &py_image_type); - return &((py_image_obj_t *)image)->_cobj; + PY_ASSERT_TYPE(img_obj, &py_image_type); + return &((py_image_obj_t *)img_obj)->_cobj; } static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) @@ -107,20 +109,64 @@ static void py_image_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k mp_printf(print, "", self->_cobj.w, self->_cobj.h, self->_cobj.bpp); } -static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { - image_t *image = py_image_cobj(self_in); - - if (flags == MP_BUFFER_READ) { - bufinfo->buf = (void*)image->pixels; - if (image->bpp > 2) { //JPEG - bufinfo->len = image->bpp; +static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) +{ + py_image_obj_t *o = self_in; + image_t *arg_img = py_image_cobj(self_in); + if (value == MP_OBJ_NULL) { + // delete + // not supported + return MP_OBJ_NULL; + } else if (value == MP_OBJ_SENTINEL) { + // load + if (IM_IS_GS(arg_img)) { + int i = mp_get_index(o->base.type, arg_img->w*arg_img->h, index, false); + int x = (i % arg_img->w); + int y = (i / arg_img->w); + return mp_obj_new_int(IM_GET_GS_PIXEL(arg_img, x, y)); + } else if (IM_IS_RGB565(arg_img)) { + int i = mp_get_index(o->base.type, arg_img->w*arg_img->h, index, false); + int x = (i % arg_img->w); + int y = (i / arg_img->w); + return mp_obj_new_int(IM_GET_RGB565_PIXEL(arg_img, x, y)); } else { - bufinfo->len = image->w*image->h*image->bpp; + int i = mp_get_index(o->base.type, arg_img->bpp, index, false); + return mp_obj_new_int(arg_img->pixels[i]); // JPEG + } + } else { + // store + if (IM_IS_GS(arg_img)) { + int i = mp_get_index(o->base.type, arg_img->w*arg_img->h, index, false); + int x = (i % arg_img->w); + int y = (i / arg_img->w); + IM_SET_GS_PIXEL(arg_img, x, y, mp_obj_get_int(value)); + } else if (IM_IS_RGB565(arg_img)) { + int i = mp_get_index(o->base.type, arg_img->w*arg_img->h, index, false); + int x = (i % arg_img->w); + int y = (i / arg_img->w); + IM_SET_RGB565_PIXEL(arg_img, x, y, mp_obj_get_int(value)); + } else { + int i = mp_get_index(o->base.type, arg_img->bpp, index, false); + arg_img->pixels[i] = mp_obj_get_int(value); // JPEG + } + } + return mp_const_none; +} + +static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) +{ + image_t *arg_img = py_image_cobj(self_in); + if (flags == MP_BUFFER_READ) { + bufinfo->buf = arg_img->pixels; + if (IM_IS_JPEG(arg_img)) { + bufinfo->len = arg_img->bpp; + } else { + bufinfo->len = arg_img->w*arg_img->h*arg_img->bpp; } bufinfo->typecode = 'b'; return 0; } else { - // disable write for now + // not supported bufinfo->buf = NULL; bufinfo->len = 0; bufinfo->typecode = -1; @@ -128,34 +174,6 @@ static mp_int_t py_image_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, } } -static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { - py_image_obj_t *o = self_in; - image_t *image = py_image_cobj(self_in); - - if (value == MP_OBJ_NULL) { - // delete - return MP_OBJ_NULL; // op not supported - } else if (value == MP_OBJ_SENTINEL) { - // load - mp_uint_t pixel; - mp_uint_t index = mp_get_index(o->base.type, image->w*image->h, index_in, false); - switch (image->bpp) { - case 1: - pixel = image->pixels[index]; - break; - case 2: - pixel = image->pixels[index*2]<<8 | image->pixels[index*2+1]; - break; - default: - return MP_OBJ_NULL; // op not supported - } - return mp_obj_new_int(pixel); - } else { - // store - return mp_const_none; - } -} - static mp_obj_t py_image_copy(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { image_t *arg_img = py_image_cobj(args[0]); @@ -818,6 +836,16 @@ static mp_obj_t py_image_median(uint n_args, const mp_obj_t *args, mp_map_t *kw_ return mp_const_none; } +static mp_obj_t py_image_histeq(mp_obj_t img_obj) +{ + image_t *arg_img = py_image_cobj(img_obj); + PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img), + "Operation not supported on JPEG"); + + imlib_histeq(arg_img); + return mp_const_none; +} + static bool py_image_find_blobs_f_fun(void *fun_obj, void *img_obj, color_blob_t *cb) { mp_obj_t blob_obj[10] = { @@ -844,7 +872,7 @@ static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t mp_uint_t arg_t_len; mp_obj_t *arg_t; mp_obj_get_array(args[1], &arg_t_len, &arg_t); - if (!arg_t_len) return mp_const_none; + if (!arg_t_len) return mp_obj_new_list(0, NULL); // return an empty array to be iteratable simple_color_t l_t[arg_t_len], u_t[arg_t_len]; if (IM_IS_GS(arg_img)) { @@ -887,7 +915,7 @@ static mp_obj_t py_image_find_blobs(uint n_args, const mp_obj_t *args, mp_map_t array_t *blobs_list = imlib_find_blobs(arg_img, arg_t_len, l_t, u_t, arg_invert ? 1 : 0, &arg_r, py_image_find_blobs_f_fun, kw_val, args[0]); if (blobs_list == NULL) { - return mp_const_none; + return mp_obj_new_list(0, NULL); // return an empty array to be iteratable } mp_obj_t objects_list = mp_obj_new_list(0, NULL); for (int i=0, j=array_length(blobs_list); ibpp == 1, - "This function is only supported on GRAYSCALE images"); - - imlib_histeq(image); - return mp_const_none; -} - static mp_obj_t py_image_find_features(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - rectangle_t roi; - image_t *image = NULL; - cascade_t *cascade = NULL; - - // Sanity checks - PY_ASSERT_TRUE_MSG(sensor.pixformat == PIXFORMAT_GRAYSCALE, + image_t *arg_img = py_image_cobj(args[0]); + PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), "This function is only supported on GRAYSCALE images"); - PY_ASSERT_TRUE_MSG(sensor.framesize <= OMV_MAX_INT_FRAME, - "This function is only supported on "OMV_MAX_INT_FRAME_STR" and smaller frames"); - - // Read positional arguments - image = py_image_cobj(args[0]); - cascade = py_cascade_cobj(args[1]); - - // Read keyword arguments - py_helper_lookup_rectangle(kw_args, image, &roi); + cascade_t *cascade = py_cascade_cobj(args[1]); cascade->threshold = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0.5f); cascade->scale_factor = py_helper_lookup_float(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_scale), 1.5f); - // Make sure ROI is not negative - PY_ASSERT_FALSE_MSG((roi.x < 0) || (roi.y < 0) || (roi.w < 0) || (roi.h < 0), - "Region of interest is negative!"); + rectangle_t arg_r; + py_helper_lookup_rectangle(kw_args, arg_img, &arg_r); + + rectangle_t rect; + if (!rectangle_subimg(arg_img, &arg_r, &rect)) { + return mp_obj_new_list(0, NULL); + } // Make sure ROI is bigger than feature size - PY_ASSERT_TRUE_MSG((roi.w > cascade->window.w && roi.h > cascade->window.h), + PY_ASSERT_TRUE_MSG((rect.w > cascade->window.w && rect.h > cascade->window.h), "Region of interest is smaller than detector window!"); - // Make sure ROI is smaller than image size - PY_ASSERT_TRUE_MSG(((roi.x+roi.w) <= image->w && (roi.y+roi.h) <= image->h), - "Region of interest is bigger than frame size!"); - // Detect objects - array_t *objects_array = imlib_detect_objects(image, cascade, &roi); + array_t *objects_array = imlib_detect_objects(arg_img, cascade, &rect); - // Add detected objects to a new Python list + // Add detected objects to a new Python list... mp_obj_t objects_list = mp_obj_new_list(0, NULL); for (int i=0; i t) { - rec_obj[0] = mp_obj_new_int(r.x); - rec_obj[1] = mp_obj_new_int(r.y); - rec_obj[2] = mp_obj_new_int(r.w); - rec_obj[3] = mp_obj_new_int(r.h); - obj = mp_obj_new_tuple(4, rec_obj); + mp_obj_t rec_obj[4] = { + mp_obj_new_int(r.x), + mp_obj_new_int(r.y), + mp_obj_new_int(r.w), + mp_obj_new_int(r.h) + }; + return mp_obj_new_tuple(4, rec_obj); } - return obj; + return mp_const_none; +} + +static mp_obj_t py_image_find_lbp(mp_obj_t img_obj, mp_obj_t roi_obj) +{ + image_t *arg_img = py_image_cobj(img_obj); + PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), + "This function is only supported on GRAYSCALE images"); + + mp_obj_t *array; + mp_obj_get_array_fixed_n(roi_obj, 4, &array); + + rectangle_t roi = { + mp_obj_get_int(array[0]), + mp_obj_get_int(array[1]), + mp_obj_get_int(array[2]), + mp_obj_get_int(array[3]), + }; + + py_lbp_obj_t *lbp_obj = m_new_obj(py_lbp_obj_t); + lbp_obj->base.type = &py_lbp_type; + lbp_obj->hist = imlib_lbp_cascade(arg_img, &roi); + return lbp_obj; } static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - rectangle_t roi; - image_t *image = py_image_cobj(args[0]); - - // Sanity checks - PY_ASSERT_TRUE_MSG(sensor.pixformat == PIXFORMAT_GRAYSCALE, + image_t *arg_img = py_image_cobj(args[0]); + PY_ASSERT_TRUE_MSG(IM_IS_GS(arg_img), "This function is only supported on GRAYSCALE images"); - PY_ASSERT_TRUE_MSG(sensor.framesize <= OMV_MAX_INT_FRAME, - "This function is only supported on "OMV_MAX_INT_FRAME_STR" and smaller frames"); + rectangle_t arg_r; + py_helper_lookup_rectangle(kw_args, arg_img, &arg_r); + + rectangle_t rect; + if (!rectangle_subimg(arg_img, &arg_r, &rect)) { + return mp_const_none; + } - // Read keyword arguments - py_helper_lookup_rectangle(kw_args, image, &roi); int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 32); - bool normalized = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("normalized")), false); + bool normalized = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_normalized), false); - // Run keypoint descriptor on ROI - array_t *kpts= freak_find_keypoints(image, normalized, threshold, &roi); + array_t *kpts = freak_find_keypoints(arg_img, normalized, threshold, &rect); if (array_length(kpts)) { - // Return keypoints MP object py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t); kp_obj->base.type = &py_kp_type; kp_obj->kpts = kpts; @@ -1125,62 +1168,6 @@ static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_ma return mp_const_none; } -static mp_obj_t py_image_find_lbp(mp_obj_t image_obj, mp_obj_t roi_obj) -{ - image_t *image; - py_lbp_obj_t *lbp_obj; - - image = py_image_cobj(image_obj); - /* sanity checks */ - PY_ASSERT_TRUE_MSG(image->bpp == 1, - "This function is only supported on GRAYSCALE images"); - - mp_obj_t *array; - mp_obj_get_array_fixed_n(roi_obj, 4, &array); - - rectangle_t roi = { - mp_obj_get_int(array[0]), - mp_obj_get_int(array[1]), - mp_obj_get_int(array[2]), - mp_obj_get_int(array[3]), - }; - - lbp_obj = m_new_obj(py_lbp_obj_t); - lbp_obj->base.type = &py_lbp_type; - lbp_obj->hist = imlib_lbp_cascade(image, &roi); - return lbp_obj; -} - -static mp_obj_t py_image_find_eyes(mp_obj_t image_obj, mp_obj_t roi_obj) -{ - image_t *image; - - image = py_image_cobj(image_obj); - /* sanity checks */ - PY_ASSERT_TRUE_MSG(image->bpp == 1, - "This function is only supported on GRAYSCALE images"); - - mp_obj_t *array; - mp_obj_get_array_fixed_n(roi_obj, 4, &array); - - rectangle_t roi = { - mp_obj_get_int(array[0]), - mp_obj_get_int(array[1]), - mp_obj_get_int(array[2]), - mp_obj_get_int(array[3]), - }; - - point_t iris; - imlib_find_iris(image, &iris, &roi); - - mp_obj_t eyes_obj[2] = { - mp_obj_new_int(iris.x), - mp_obj_new_int(iris.y), - }; - - return mp_obj_new_tuple(2, eyes_obj); -} - /* Image file functions */ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_copy_obj, 1, py_image_copy); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save); @@ -1225,17 +1212,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_midpoint_obj, 2, py_image_midpoint); STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_mean_obj, py_image_mean); STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_mode_obj, py_image_mode); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 2, py_image_median); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq); /* Color Tracking */ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_blobs_obj, 2, py_image_find_blobs); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_markers_obj, 2, py_image_find_markers); - -STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_find_template_obj, py_image_find_template); +/* Feature Detection */ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_features_obj, 2, py_image_find_features); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_eye_obj, py_image_find_eye); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_find_template_obj, py_image_find_template); STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_lbp_obj, py_image_find_lbp); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_eyes_obj, py_image_find_eyes); - +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); static const mp_map_elem_t locals_dict_table[] = { /* Image file functions */ {MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&py_image_copy_obj}, @@ -1281,26 +1267,23 @@ static const mp_map_elem_t locals_dict_table[] = { {MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&py_image_mean_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_mode), (mp_obj_t)&py_image_mode_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj}, /* Color Tracking */ {MP_OBJ_NEW_QSTR(MP_QSTR_find_blobs), (mp_obj_t)&py_image_find_blobs_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_find_markers), (mp_obj_t)&py_image_find_markers_obj}, - - {MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj}, - /* objects/feature detection */ - {MP_OBJ_NEW_QSTR(MP_QSTR_find_template), (mp_obj_t)&py_image_find_template_obj}, + /* Feature Detection */ {MP_OBJ_NEW_QSTR(MP_QSTR_find_features), (mp_obj_t)&py_image_find_features_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_keypoints), (mp_obj_t)&py_image_find_keypoints_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_find_eye), (mp_obj_t)&py_image_find_eye_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_find_template), (mp_obj_t)&py_image_find_template_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_find_lbp), (mp_obj_t)&py_image_find_lbp_obj}, - {MP_OBJ_NEW_QSTR(MP_QSTR_find_eyes), (mp_obj_t)&py_image_find_eyes_obj}, - + {MP_OBJ_NEW_QSTR(MP_QSTR_find_keypoints), (mp_obj_t)&py_image_find_keypoints_obj}, { NULL, NULL }, }; - STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); static const mp_obj_type_t py_image_type = { { &mp_type_type }, - .name = MP_QSTR_image, + .name = MP_QSTR_Image, .print = py_image_print, .buffer_p = { .get_buffer = py_image_get_buffer }, .subscr = py_image_subscr, @@ -1311,45 +1294,21 @@ mp_obj_t py_image(int w, int h, int bpp, void *pixels) { py_image_obj_t *o = m_new_obj(py_image_obj_t); o->base.type = &py_image_type; - - o->_cobj.w =w; - o->_cobj.h =h; - o->_cobj.bpp =bpp; - o->_cobj.pixels =pixels; + o->_cobj.w = w; + o->_cobj.h = h; + o->_cobj.bpp = bpp; + o->_cobj.pixels = pixels; return o; } -mp_obj_t py_image_from_struct(image_t *image) +mp_obj_t py_image_from_struct(image_t *img) { py_image_obj_t *o = m_new_obj(py_image_obj_t); o->base.type = &py_image_type; - o->_cobj =*image; + o->_cobj = *img; return o; } -int py_image_descriptor_from_roi(image_t *image, const char *path, rectangle_t *roi) -{ - FIL fp; - FRESULT res = FR_OK; - - array_t *kpts = freak_find_keypoints(image, false, 10, roi); - printf("Save Descriptor: KPTS(%d)\n", array_length(kpts)); - printf("Save Descriptor: ROI(%d %d %d %d)\n", roi->x, roi->y, roi->w, roi->h); - - if (array_length(kpts)) { - if ((res = f_open(&fp, path, FA_WRITE|FA_CREATE_ALWAYS)) == FR_OK) { - res = freak_save_descriptor(&fp, kpts); - f_close(&fp); - } - - // File open/write error - if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res))); - } - } - return 0; -} - mp_obj_t py_image_rgb_to_lab(mp_obj_t tuple) { mp_obj_t *rgb; @@ -1410,19 +1369,10 @@ mp_obj_t py_image_grayscale_to_rgb(mp_obj_t not_tuple) mp_obj_new_int(rgb_color.blue)}); } -// The image module (it's different from the Image class!) mp_obj_t py_image_load_image(mp_obj_t path_obj) { - mp_obj_t image_obj =NULL; - struct image *image; - const char *path = mp_obj_str_get_str(path_obj); - image_obj = py_image(0, 0, 0, 0); - - /* get image pointer */ - image = py_image_cobj(image_obj); - - imlib_load_image(image, path); - + mp_obj_t image_obj = py_image(0, 0, 0, 0); + imlib_load_image(py_image_cobj(image_obj), mp_obj_str_get_str(path_obj)); return image_obj; } @@ -1595,21 +1545,41 @@ static mp_obj_t py_image_match_descriptor(uint n_args, const mp_obj_t *args, mp_ return match_obj; } +int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) +{ + FIL fp; + FRESULT res = FR_OK; + + printf("Save Descriptor: ROI(%d %d %d %d)\n", roi->x, roi->y, roi->w, roi->h); + array_t *kpts = freak_find_keypoints(img, false, 10, roi); + printf("Save Descriptor: KPTS(%d)\n", array_length(kpts)); + + if (array_length(kpts)) { + if ((res = f_open(&fp, path, FA_WRITE|FA_CREATE_ALWAYS)) == FR_OK) { + res = freak_save_descriptor(&fp, kpts); + f_close(&fp); + } + // File open/write error + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res))); + } + } + return 0; +} + /* Color space functions */ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_lab_obj, py_image_rgb_to_lab); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_lab_to_rgb_obj, py_image_lab_to_rgb); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rgb_to_grayscale_obj, py_image_rgb_to_grayscale); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_grayscale_to_rgb_obj, py_image_grayscale_to_rgb); - +/* Image Module Functions */ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_load_image_obj, py_image_load_image); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_cascade); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 2, py_image_load_descriptor); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_descriptor_obj, 3, py_image_save_descriptor); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 3, py_image_match_descriptor); - static const mp_map_elem_t globals_dict_table[] = { {MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_image)}, - /* Descriptor types */ {MP_OBJ_NEW_QSTR(MP_QSTR_LBP), MP_OBJ_NEW_SMALL_INT(DESC_LBP)}, {MP_OBJ_NEW_QSTR(MP_QSTR_FREAK), MP_OBJ_NEW_SMALL_INT(DESC_FREAK)}, /* Color space functions */ @@ -1617,17 +1587,14 @@ static const mp_map_elem_t globals_dict_table[] = { {MP_OBJ_NEW_QSTR(MP_QSTR_lab_to_rgb), (mp_obj_t)&py_image_lab_to_rgb_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_rgb_to_grayscale), (mp_obj_t)&py_image_rgb_to_grayscale_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_grayscale_to_rgb), (mp_obj_t)&py_image_grayscale_to_rgb_obj}, - - // Image module functions + /* Image Module Functions */ {MP_OBJ_NEW_QSTR(MP_QSTR_Image), (mp_obj_t)&py_image_load_image_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_HaarCascade), (mp_obj_t)&py_image_load_cascade_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_load_descriptor), (mp_obj_t)&py_image_load_descriptor_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_save_descriptor), (mp_obj_t)&py_image_save_descriptor_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_match_descriptor), (mp_obj_t)&py_image_match_descriptor_obj}, - { NULL, NULL } }; - STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); const mp_obj_module_t image_module = { diff --git a/src/omv/py/py_image.h b/src/omv/py/py_image.h index 3520d00cf..ca9e4e2ff 100644 --- a/src/omv/py/py_image.h +++ b/src/omv/py/py_image.h @@ -8,10 +8,10 @@ */ #ifndef __PY_IMAGE_H__ #define __PY_IMAGE_H__ +// DISABLED #include #include "imlib.h" mp_obj_t py_image(int width, int height, int bpp, void *pixels); -mp_obj_t py_image_from_struct(image_t *image); -void *py_image_cobj(mp_obj_t image); -int py_image_descriptor_from_roi(image_t *image, const char *path, rectangle_t *roi); +mp_obj_t py_image_from_struct(image_t *img); +void *py_image_cobj(mp_obj_t img_obj); +int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi); #endif // __PY_IMAGE_H__ - diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index a8e1a3228..670c61387 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -68,7 +68,7 @@ Q(find_template) Q(find_features) Q(find_keypoints) Q(find_lbp) -Q(find_eyes) +Q(find_eye) Q(cmp_lbp) Q(quality) Q(color) @@ -80,6 +80,7 @@ Q(bias) Q(percentile) Q(feature_filter) Q(margin) +Q(normalized) // Lcd Module Q(lcd) diff --git a/usr/examples/08-Eye-Tracking/iris_detection.py b/usr/examples/08-Eye-Tracking/iris_detection.py index dabafccad..aab96d18b 100644 --- a/usr/examples/08-Eye-Tracking/iris_detection.py +++ b/usr/examples/08-Eye-Tracking/iris_detection.py @@ -42,7 +42,7 @@ while (True): # Note: Use a higher threshold here (more detections) and lower scale (to find small objects) eyes = img.find_features(eyes_cascade, threshold=0.5, scale=1.2, roi=face) for e in eyes: - iris = img.find_eyes(e) + iris = img.find_eye(e) img.draw_rectangle(e) img.draw_cross(iris[0], iris[1])