diff --git a/src/Makefile b/src/Makefile index eeb872e46..74e4bc57d 100755 --- a/src/Makefile +++ b/src/Makefile @@ -168,6 +168,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\ hough.o \ sincos_tab.o \ edge.o \ + hog.o \ ) FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/py/, \ diff --git a/src/omv/Makefile b/src/omv/Makefile index afdae0410..f8a8eb281 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -55,6 +55,7 @@ SRCS += $(addprefix img/, \ hough.c \ sincos_tab.c \ edge.c \ + hog.c \ ) SRCS += $(addprefix py/, \ diff --git a/src/omv/img/hog.c b/src/omv/img/hog.c new file mode 100644 index 000000000..479480cd3 --- /dev/null +++ b/src/omv/img/hog.c @@ -0,0 +1,127 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * HoG. + * See Histograms of Oriented Gradients (Navneet Dalal and Bill Triggs) + */ +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#include "xalloc.h" + +#define N_BINS (9) +typedef struct bin { + int d; + int m; +} bin_t; + +int bin_array_comp(const void *obj0, const void *obj1) +{ + const bin_t *b0 = obj0; + const bin_t *b1 = obj1; + if (b0->m < b1->m) + return -1; + if (b0->m > b1->m) + return 1; + + return 0; +} + +void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size) +{ + int s = src->w; + int w = roi->x+roi->w-1; + int h = roi->y+roi->h-1; + + int block_size = cell_size * 2; + int x_cells = (roi->w/cell_size); + int y_cells = (roi->h/cell_size); + + // TODO: Assert row->w/h >= cell_size *2; + float *hog = fb_alloc0(x_cells * y_cells * N_BINS * sizeof*hog); + + //2. Finding Image Gradients + for (int y=roi->y, hog_index=0; yx; x 0 && (y+cy) < h && (x+cx) > 0 && (x+cx) < w) { + // Find horizontal/vertical direction + int vx = src->data[(y+cy+0)*s+(x+cx+1)] - src->data[(y+cy-0)*s+(x+cx-1)]; + int vy = src->data[(y+cy+1)*s+(x+cx+0)] - src->data[(y+cy-1)*s+(x+cx-0)]; + // Find magnitude + float m = fast_sqrtf(vx*vx + vy*vy); + if(((int) m) > 1) { + k += m*m; + // Find and quantize gradient degree + // TODO atan2f is swapped for visualization + int t = ((int) fast_fabsf((atan2f(vx, vy)*180.0f/M_PI))) / 20; + t = (t == 9)? 0 : t; + + // hog[((cy/cell_size) * x_cells + (cx/cell_size)) * N_BINS + t] += m; + hog[hog_index + (((cy/8)*2+(cx/8)) * N_BINS) + t] += m; + } + } + } + } + + // Normalize the last block + k = sqrtf(k); + for (int i=hog_index; i<(hog_index+(N_BINS*4)); i++) { + hog[i] = hog[i]/k; + } + + hog_index += (N_BINS*4); + } + } + + memset(src->pixels, 0, src->w*src->h); + + array_t *gds; + bin_t bins[9]; + array_alloc(&gds, NULL); + + for (int i=0; i 255) m = 255; if (m < 0) m = 0; + bin_t *bin = array_at(gds, (i%N_BINS)); + bin->m = m; + bin->d = ((i%N_BINS)*20); + } + + array_sort(gds, bin_array_comp); + + int x1 = (x+bx) * cell_size + l; + int y1 = (y+by) * cell_size + l; + for (int i=0; id]; + int y2 = l * sin_table[bin->d]; + imlib_draw_line(src, (x1 - x2), (y1 + y2), (x1 + x2), (y1 - y2), bin->m); + } + + hog_index += N_BINS; + } + } + } + } + + xfree(gds); + fb_free(); +} diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index e747d6256..5e53ca082 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -543,6 +543,9 @@ array_t *imlib_find_lines(image_t *src, rectangle_t *roi, int threshold); void imlib_edge_simple(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh); void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh); +// HoG +void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size); + // Lens correction void imlib_lens_corr(image_t *src, float strength); #endif //__IMLIB_H__ diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index 87e8b603c..7fc31f910 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -1424,6 +1424,26 @@ static mp_obj_t py_image_find_edges(uint n_args, const mp_obj_t *args, mp_map_t return mp_const_true; } + +static mp_obj_t py_image_find_hog(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) +{ + 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"); + + 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; + } + + int size = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_size), 8); + imlib_find_hog(arg_img, &rect, size); + + return mp_const_none; +} + /* 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_copy_to_fb_obj, 1, py_image_copy_to_fb); @@ -1490,6 +1510,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_find_lbp_obj, py_image_find_lbp); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_keypoints_obj, 1, py_image_find_keypoints); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_lines_obj, 1, py_image_find_lines); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_edges_obj, 2, py_image_find_edges); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_find_hog_obj, 1, py_image_find_hog); 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}, @@ -1557,6 +1578,7 @@ static const mp_map_elem_t locals_dict_table[] = { {MP_OBJ_NEW_QSTR(MP_QSTR_find_keypoints), (mp_obj_t)&py_image_find_keypoints_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_find_lines), (mp_obj_t)&py_image_find_lines_obj}, {MP_OBJ_NEW_QSTR(MP_QSTR_find_edges), (mp_obj_t)&py_image_find_edges_obj}, + {MP_OBJ_NEW_QSTR(MP_QSTR_find_hog), (mp_obj_t)&py_image_find_hog_obj}, { NULL, NULL }, }; STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table); diff --git a/src/omv/py/qstrdefsomv.h b/src/omv/py/qstrdefsomv.h index e9263b3e6..a44035831 100644 --- a/src/omv/py/qstrdefsomv.h +++ b/src/omv/py/qstrdefsomv.h @@ -84,6 +84,7 @@ Q(find_lbp) Q(find_eye) Q(find_lines) Q(find_edges) +Q(find_hog) Q(cmp_lbp) Q(quality) Q(color) diff --git a/usr/examples/09-Feature-Detection/hog.py b/usr/examples/09-Feature-Detection/hog.py new file mode 100644 index 000000000..b3359e5c6 --- /dev/null +++ b/usr/examples/09-Feature-Detection/hog.py @@ -0,0 +1,28 @@ +# Histogram of Oriented Gradients (HoG) Example +# +# This example demonstrates HoG visualization. +# +# Note: Due to JPEG artifacts, the HoG visualization looks blurry. To see the +# image without JPEG artifacts, uncomment the lines that save the image to uSD. + +import sensor, image, time + +sensor.reset() +# Set sensor settings +sensor.set_contrast(1) +sensor.set_gainceiling(8) +sensor.set_framesize(sensor.QVGA) +sensor.skip_frames(30) +sensor.set_pixformat(sensor.GRAYSCALE) + +clock = time.clock() # Tracks FPS. +while (True): + clock.tick() + img = sensor.snapshot() + img.find_hog() + + # Uncomment to save raw FB to file and exit the loop + #img.save("/hog.pgm") + #break + + print(clock.fps()) \ No newline at end of file