From 7a01a9bedeb967426743a7a25e2b59f3bb178e4f Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Mon, 25 Apr 2016 21:55:30 -0400 Subject: [PATCH] Final Imlib Cleanup Finished going through imlib.c. -> Histeq uses fb_alloc now and has hook for RGB histeq when reserve YUV LUT is added (coming soon in next PR). Cleanuped py_helper.c/h -> No functional changes. Just added some header info. Finished going through py_image.c * 1 - Finished general code cleanup and updating everything to using new library functions. In particular, I updated the remaining find_* functions with the new roi clipping code when they accept rois. * 2 - Made blob stuff return a list when nothing is found so you don't have to do an if on the returned value anymore. * 3 - img subscr is more powerful now allowing image reading and writing. I updated this because I had to use it to find a previous bug with socket.send() for the WINC driver. * 4 - Renamed find_eyes to find_eye. Because it just finds one eye. * 5 - Other than that just general code cleanup to make functions look consistent. And yes, changes have been test. Face tracking, eye tracking, keypoints, etc. all work still. Future things todo before release: 1 - Change all LAB stuff to YUV. 2 - Add in reverse YUV->RGB LUT and update functions like Mode() to use this so they don't generate messed up outputs, also histeq() too. 3 - Add any remaining sensor control functions like agc control. --- src/omv/img/imlib.c | 96 ++-- src/omv/img/imlib.h | 52 +- src/omv/py/py_helper.c | 10 +- src/omv/py/py_helper.h | 2 + src/omv/py/py_image.c | 475 ++++++++---------- src/omv/py/py_image.h | 8 +- src/omv/py/qstrdefsomv.h | 3 +- .../08-Eye-Tracking/iris_detection.py | 2 +- 8 files changed, 296 insertions(+), 352 deletions(-) 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])