From 29202f1f999980efcb1929d9390e4f2cc746336f Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 1 Sep 2014 16:49:02 +0200 Subject: [PATCH] Add morphological operations, fix threshold --- src/micropython | 2 +- src/omv/img/imlib.c | 145 +++++++++++++++++++++++++++++++----------- src/omv/img/imlib.h | 18 ++++-- src/omv/py/py_image.c | 144 ++++++++++++++++++++++++++++++++--------- 4 files changed, 237 insertions(+), 72 deletions(-) diff --git a/src/micropython b/src/micropython index 71ecc7ae7..84078f85a 160000 --- a/src/micropython +++ b/src/micropython @@ -1 +1 @@ -Subproject commit 71ecc7ae7ce8faa6a0a7224961c7b3c49bc7f114 +Subproject commit 84078f85a5135bf83d6bdd655740ac89a97145fd diff --git a/src/omv/img/imlib.c b/src/omv/img/imlib.c index bc9569273..b09c1478d 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -203,46 +203,89 @@ void imlib_grayscale_to_rgb565(struct image *image) #endif } -void imlib_erosion_filter(struct image *src, uint8_t *kernel, int k_size) +void imlib_erode(image_t *src, int ksize) { - int x, y, j, k; - int w = src->w; - int h = src->h; - /* TODO */ - uint8_t *dst = xalloc0(w*h); + int c = ksize/2;// center pixel + int k_rows = (ksize+1)*2; + uint8_t *dst = xalloc0(src->w * k_rows); - for (y=0; ypixels[w*(y+j)+x+k] != (kernel[j*k_size+k]*255)) { - dst[w*(y+1)+x+1] = 0; - j=k_size; - break; - } + for (int y=1; yh-ksize; y++) { + for (int x=1; xw-ksize; x++) { + int i = y*src->w+x; + int di = (y%k_rows)*src->w+x; + if ((dst[di] = src->pixels[i])==0) { + continue; + } + + for (int j=-c; jpixels[(y+j)*src->w+x+k]==0) { + dst[di]=0; + goto done; + } } } + done:; + } + + if ((y+1)%k_rows==0) { + memcpy(src->pixels+((y/k_rows)*k_rows*src->w), dst, src->w*k_rows); } } - memcpy(src->pixels, dst, w*h); xfree(dst); } -void imlib_threshold(image_t *src, image_t *dst, struct color *color, int threshold) +void imlib_dilate(image_t *src, int ksize) { - /* Extract reference RGB */ - uint16_t r = color->r*31/255; - uint16_t g = color->g*63/255; - uint16_t b = color->b*31/255; - uint32_t rgb = SWAP((r << 11) | (g << 5) | b) * 3; + int c = ksize/2;// center pixel + int k_rows = (ksize+1)*2; + uint8_t *dst = xalloc0(src->w * k_rows); - /* Convert reference RGB to LAB */ - uint32_t L = lab_table[rgb]; - uint32_t A = lab_table[rgb+1]; - uint32_t B = lab_table[rgb+2]; + for (int y=1; yh-ksize; y++) { + for (int x=1; xw-ksize; x++) { + int i = y*src->w+x; + int di = (y%k_rows)*src->w+x; + if ((dst[di] = src->pixels[i])) { + continue; + } + for (int j=-c; jpixels[(y+j)*src->w+x+k]) { + dst[di]=src->pixels[(y+j)*src->w+x+k]; + goto done; + } + } + } + done:; + } + + if ((y+1)%k_rows==0) { + memcpy(src->pixels+((y/k_rows)*k_rows*src->w), dst, src->w*k_rows); + } + } + xfree(dst); +} + +void imlib_morph(struct image *src, uint8_t *kernel, int ksize) +{ + +} + + +void imlib_threshold(image_t *src, image_t *dst, color_t *color, int color_size, int threshold) +{ +// /* Extract reference RGB */ +// uint16_t r = color->r*31/255; +// uint16_t g = color->g*63/255; +// uint16_t b = color->b*31/255; +// uint32_t rgb = SWAP((r << 11) | (g << 5) | b) * 3; +// +// /* Convert reference RGB to LAB */ +// uint32_t L = lab_table[rgb]; +// uint32_t A = lab_table[rgb+1]; +// uint32_t B = lab_table[rgb+2]; +// /* Square threshold */ threshold *= threshold; @@ -251,12 +294,19 @@ void imlib_threshold(image_t *src, image_t *dst, struct color *color, int thresh for (int y=0; yh; y++) { int i=y*src->w; for (int x=0; xw; x++) { - rgb = pixels[i+x]*3; - uint32_t sum =(L-lab_table[rgb]) * (L-lab_table[rgb]) + - (A-lab_table[rgb+1]) * (A-lab_table[rgb+1]) + - (B-lab_table[rgb+2]) * (B-lab_table[rgb+2]); - /* add pixel if within threshold */ - dst->pixels[i+x] = (sumpixels[i+x] = 0; + for (int c=0; cpixels[i+x] = c+1; //sets color label c+1 + break; + } + } } } } @@ -300,10 +350,24 @@ void imlib_subimage(struct image *src_img, struct image *dst_img, int x_off, int } } -void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off) +void imlib_blit_gs(struct image *src, struct image *dst, int x_off, int y_off) { int x, y; - typeof(*src->data) *srcp = src->data; + uint8_t *srcp = src->data; + uint16_t *dstp = (uint16_t*) dst->data; + + for (y=y_off; yh+y_off; y++) { + for (x=x_off; xw+x_off; x++) { + uint8_t p =*srcp++; + dstp[y*dst->w+x]= ((uint16_t)p<<8)|p; + } + } +} + +void imlib_blit_rgb(struct image *src, struct image *dst, int x_off, int y_off) +{ + int x, y; + typeof(*src->data) *srcp = src->data; //TODO typeof(*dst->data) *dstp = dst->data; for (y=y_off; yh+y_off; y++) { @@ -313,6 +377,15 @@ void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off) } } +void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off) +{ + if (src->bpp == 1) { + imlib_blit_gs(src, dst, x_off, y_off); + } else { + imlib_blit_rgb(src, dst, x_off, y_off); + } +} + void imlib_blend(struct image *src, struct image *dst, int x_off, int y_off, uint8_t alpha) { uint16_t i,r, g, b; diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index f9e8654e2..c2d8c3cf6 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -21,6 +21,15 @@ typedef struct rectangle { int h; } rectangle_t; +typedef struct blob { + int x; + int y; + int w; + int h; + int c; + int id; +} blob_t; + typedef struct color { union { uint8_t vec[3]; @@ -159,9 +168,11 @@ void imlib_rgb_to_hsv(struct color *rgb, struct color *hsv); int imlib_image_mean(struct image *src); void imlib_histeq(struct image *src); void imlib_median_filter(image_t *src, int r); -void imlib_erosion_filter(struct image *src, uint8_t *kernel, int k_size); -void imlib_threshold(struct image *src, struct image *dst, struct color *color, int threshold); -void imlib_rainbow(struct image *src, struct image *dst); +void imlib_erode(image_t *src, int ksize); +void imlib_dilate(image_t *src, int ksize); +void imlib_morph(image_t *src, uint8_t *kernel, int k_size); +void imlib_threshold(image_t *src, image_t *dst, color_t *color, int color_size, int threshold); +void imlib_rainbow(image_t *src, struct image *dst); array_t *imlib_count_blobs(struct image *image); /* Integral image functions */ @@ -198,5 +209,4 @@ int ppm_write(image_t *img, const char *path); int ppm_write_subimg(image_t *img, const char *path, rectangle_t *r); int imlib_load_image(image_t *image, const char *path); int imlib_save_image(image_t *image, const char *path, rectangle_t *r); -void imlib_blit(struct image *src, struct image *dst, int x_off, int y_off); #endif //__IMLIB_H__ diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index dd7d7a45e..896707eb9 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -270,33 +270,46 @@ 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_threshold(mp_obj_t image_obj, mp_obj_t color_obj, mp_obj_t threshold) +static mp_obj_t py_image_threshold(mp_obj_t image_obj, mp_obj_t color_list_obj, mp_obj_t threshold) { - /* C stuff */ - struct color color; - struct image *image; - mp_obj_t bimage_obj; + color_t *color; + image_t *image; /* sanity checks */ PY_ASSERT_TRUE(sensor.pixformat == PIXFORMAT_RGB565); PY_ASSERT_TRUE(sensor.framesize <= FRAMESIZE_QQVGA); - mp_obj_t *col_obj; - mp_obj_get_array_fixed_n(color_obj, 3, &col_obj); - color.r = mp_obj_get_int(col_obj[0]); - color.g = mp_obj_get_int(col_obj[1]); - color.b = mp_obj_get_int(col_obj[2]); - - /* get image pointer */ + /* read arguments */ image = py_image_cobj(image_obj); + int thresh = mp_obj_get_int(threshold); /* returned image */ - bimage_obj = py_image(image->w, image->h, 1, image->data+(image->w*image->h*image->bpp)); + image_t bimage = { + .w=image->w, + .h=image->h, + .bpp=1, + .pixels=image->data+(image->w*image->h*image->bpp) + }; + + /* copy color list */ + uint len; + mp_obj_t *color_arr; + mp_obj_get_array(color_list_obj, &len, &color_arr); + + color = xalloc(len*sizeof*color); + + for (int i=0; ibpp==1); + + imlib_erode(image, mp_obj_get_int(ksize_obj)); + return mp_const_none; +} + +static mp_obj_t py_image_dilate(mp_obj_t image_obj, mp_obj_t ksize_obj) +{ + image_t *image = NULL; + image = py_image_cobj(image_obj); + + /* sanity checks */ + PY_ASSERT_TRUE(image->bpp==1); + + imlib_dilate(image, mp_obj_get_int(ksize_obj)); + return mp_const_none; +} + +static mp_obj_t py_image_morph(mp_obj_t image_obj, mp_obj_t ksize_obj) +{ + image_t *image = NULL; + image = py_image_cobj(image_obj); + + /* sanity checks */ + PY_ASSERT_TRUE(image->bpp==1); + + imlib_morph(image, NULL, mp_obj_get_int(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; @@ -389,7 +439,7 @@ static mp_obj_t py_image_find_blobs(mp_obj_t image_obj) /* C stuff */ array_t *blobs; struct image *image; - mp_obj_t rec_obj[4]; + mp_obj_t blob_obj[6]; /* MP List */ mp_obj_t objects_list = mp_const_none; @@ -408,12 +458,14 @@ static mp_obj_t py_image_find_blobs(mp_obj_t image_obj) if (array_length(blobs)) { for (int j=0; jx); - 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); - mp_obj_list_append(objects_list, mp_obj_new_tuple(4, rec_obj)); + blob_t *r = array_at(blobs, j); + blob_obj[0] = mp_obj_new_int(r->x); + blob_obj[1] = mp_obj_new_int(r->y); + blob_obj[2] = mp_obj_new_int(r->w); + blob_obj[3] = mp_obj_new_int(r->h); + blob_obj[4] = mp_obj_new_int(r->c); + blob_obj[5] = mp_obj_new_int(r->id); + mp_obj_list_append(objects_list, mp_obj_new_tuple(6, blob_obj)); } } array_free(blobs); @@ -490,6 +542,10 @@ static mp_obj_t py_image_find_template(mp_obj_t image_obj, mp_obj_t template_obj } return obj; } +//#define get_kw_arg(kw_map, kw_val, kw_def) +// ({ mp_map_elem_t *kw_arg = mp_map_lookup(kw_map, +// MP_OBJ_NEW_QSTR(qstr_from_str(kw_val)), MP_MAP_LOOKUP); +// _a < _b ? _a : _b; }) static mp_obj_t py_image_find_keypoints(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { @@ -564,19 +620,39 @@ static mp_obj_t py_image_match_keypoints(mp_obj_t image_obj, mp_obj_t kpts_obj, // match the keypoint sets int16_t *kpts_match = freak_match_keypoints(kpts1, kpts1_size, kpts2, kpts2_size, m_thresh); +// // do something with the match +// for (int i=0; ix, kp1->y, kp2->x, kp2->y); +// //int r = 4; +// // if (((kp->x+r) < image->w) && ((kp->y+r) < image->h)) { +// // imlib_draw_circle(image, kp->x, kp->y, r); +// // } +// } +// } + // do something with the match + int cx=0, cy=0, match=0; for (int i=0; ix, kp1->y, kp2->x, kp2->y); - //int r = 4; - // if (((kp->x+r) < image->w) && ((kp->y+r) < image->h)) { - // imlib_draw_circle(image, kp->x, kp->y, r); - // } + cx += kp2->x; + cy += kp2->y; + match ++; } } - + if (match ==0) { + match++; + } + cx /= match; + cy /= match; + int r = 5; + if (((cx+r) < image->w) && ((cy+r) < image->h)) { + imlib_draw_line(image, image->w/2, image->h/2, cx, cy); + imlib_draw_circle(image, cx, cy, r); + } return mp_const_none; } @@ -630,6 +706,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_histeq_obj, py_image_histeq); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_median_obj, 1, py_image_median); STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_threshold_obj, py_image_threshold); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_rainbow_obj, py_image_rainbow); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_erode_obj, py_image_erode); +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_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); @@ -647,13 +726,16 @@ static const mp_map_elem_t locals_dict_table[] = { /* 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}, - {MP_OBJ_NEW_QSTR(MP_QSTR_scaled), (mp_obj_t)&py_image_scaled_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_scaled), (mp_obj_t)&py_image_scaled_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_blit), (mp_obj_t)&py_image_blit_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_blend), (mp_obj_t)&py_image_blend_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_histeq), (mp_obj_t)&py_image_histeq_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&py_image_median_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_threshold), (mp_obj_t)&py_image_threshold_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_rainbow), (mp_obj_t)&py_image_rainbow_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_erode), (mp_obj_t)&py_image_erode_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_dilate), (mp_obj_t)&py_image_dilate_obj}, +// {MP_OBJ_NEW_QSTR(MP_QSTR_morph), (mp_obj_t)&py_image_morph_obj}, /* drawing functions */ {MP_OBJ_NEW_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&py_image_draw_circle_obj}, @@ -686,7 +768,7 @@ mp_obj_t py_image(int w, int h, int bpp, void *pixels) o->base.type = &py_image_type; o->_cobj.w =w; - o->_cobj.h =w; + o->_cobj.h =h; o->_cobj.bpp =bpp; o->_cobj.pixels =pixels; return o;