Add Eye Detector

This commit is contained in:
iabdalkader 2014-10-25 15:33:02 +02:00
parent c15fc85786
commit ef9bf26981
7 changed files with 226 additions and 19 deletions

View File

@ -137,6 +137,7 @@ OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
font.o \
jpeg.o \
lbp.o \
eye.o \
)
OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/py/, \

@ -1 +1 @@
Subproject commit b38d4d13fca7ff52e440dca36227937e96bd2a62
Subproject commit 47172811746c93e848bc4f943b983d15e22952df

View File

@ -46,6 +46,7 @@ SRCS += $(addprefix img/, \
font.c \
jpeg.c \
lbp.c \
eye.c \
)
SRCS += $(addprefix py/, \

146
src/omv/img/eye.c Normal file
View File

@ -0,0 +1,146 @@
/*
* This file is part of the OpenMV project.
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Pupil localization using image gradients.
* See Fabian Timm's paper.
*
*/
#include "imlib.h"
#include "xalloc.h"
#include "fmath.h"
static void imlib_find_gradients(image_t *src, array_t *gradients, int x_off, int y_off, int box_w, int box_h)
{
for (int y=y_off; y<y_off+box_h-3; y++) {
for (int x=x_off; x<x_off+box_w-3; x++) {
int vx=0, vy=0, w=src->w;
// sobel_kernel
vx = src->data[(y+0)*w+x+0]
- src->data[(y+0)*w+x+2]
+ (src->data[(y+1)*w+x+0]<<1)
- (src->data[(y+1)*w+x+2]<<1)
+ src->data[(y+2)*w+x+0]
- src->data[(y+2)*w+x+2];
// sobel_kernel
vy = src->data[(y+0)*w+x+0]
+ (src->data[(y+0)*w+x+1]<<1)
+ src->data[(y+0)*w+x+2]
- src->data[(y+2)*w+x+0]
- (src->data[(y+2)*w+x+1]<<1)
- src->data[(y+2)*w+x+2];
float m = fast_sqrtf(vx*vx+vy*vy);
if (m>200) {
vec_t *v = xalloc(sizeof(vec_t));
v->m = m;
v->x = vx/m;
v->y = vy/m;
v->cx = x+1;
v->cy = y+1;
array_push_back(gradients, v);
}
}
}
}
static void imlib_find_pupil(image_t *src, array_t *gradients, int x_off, int y_off, int box_w, int box_h, point_t *e)
{
int max_x=0;
int max_y=0;
float max_dot = 0.0f;
// rectangle_t r = {x_off, y_off, box_w, box_h};
// imlib_draw_rectangle(src, &r);
for (int y=y_off; y<y_off+box_h; y++) {
for (int x=x_off; x<x_off+box_w; x++) {
float sum_dot=0.0f;
for (int i=0; i<array_length(gradients); i++) {
// get gradient vector g
vec_t *v = (vec_t *) array_at(gradients, i);
// get vector from gradient to centor d
vec_t d ={x-v->cx, y-v->cy};
// normalize d vector
float m = fast_sqrtf(d.x*d.x+d.y*d.y);
d.x = d.x/m;
d.y = d.y/m;
// compute the dot product d.g
float t = (d.x*v->x)+(d.y*v->y);
// d,g should point the same direction
if (t>0.0) {
// dark centres are more likely to be pupils than
// bright centres, so we use the grayscale value as weight.
sum_dot += t*t*(255-src->data[y*src->w+x]);
}
}
sum_dot=sum_dot/array_length(gradients);
if (sum_dot > max_dot) {
max_dot = sum_dot;
max_x = x;
max_y = y;
}
}
}
e->x = max_x;
e->y = max_y;
}
// TODO use the gradients median not average
static void imlib_filter_gradients(array_t *gradients)
{
float total_m=0.0f;
for (int i=0; i<array_length(gradients); i++) {
vec_t *v = (vec_t *) array_at(gradients, i);
total_m += v->m;
}
float avg_m = total_m/array_length(gradients);
for (int i=0; i<array_length(gradients); i++) {
vec_t *v = (vec_t *) array_at(gradients, i);
float diff =(v->m-avg_m) * (v->m-avg_m);
if (fast_sqrtf(diff)>100) {
array_erase(gradients, i);
}
}
}
void imlib_find_eyes(image_t *src, point_t *left, point_t *right, rectangle_t *roi)
{
array_t *left_gradients, *right_gradients;
array_alloc(&left_gradients, xfree);
array_alloc(&right_gradients, xfree);
int box_w = roi->w/3;
int box_h = roi->h/4;
int l_x_off = roi->x+((int)(0.15f*roi->w));
int l_y_off = roi->y+((int)(0.30f*roi->h));
int r_x_off = roi->x+((int)(0.55f*roi->w));
int r_y_off = roi->y+((int)(0.30f*roi->h));
// find gradients with strong magnitudes
imlib_find_gradients(src, left_gradients, l_x_off, l_y_off, box_w, box_h);
imlib_find_gradients(src, right_gradients, r_x_off, r_y_off, box_w, box_h);
// filter gradients
imlib_filter_gradients(left_gradients);
imlib_filter_gradients(right_gradients);
// search for pupils
imlib_find_pupil(src, left_gradients, l_x_off, l_y_off, box_w, box_h, left);
imlib_find_pupil(src, right_gradients, r_x_off, r_y_off, box_w, box_h, right);
array_free(left_gradients);
array_free(right_gradients);
}

View File

@ -80,24 +80,12 @@ typedef struct integral_image {
uint32_t *data;
} i_image_t;
typedef struct {
union {
struct {
uint8_t c0;
uint8_t c1;
uint8_t c2;
uint8_t c3;
};
struct {
uint16_t s0;
uint16_t s1;
};
struct {
uint32_t i;
};
};
}vec_t;
typedef struct _vector {
float x;
float y;
float m;
uint16_t cx,cy;
} vec_t;
typedef struct cluster {
array_t *points;
@ -216,6 +204,9 @@ uint8_t *imlib_lbp_cascade(image_t *image, rectangle_t *roi);
int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1);
int imlib_lbp_desc_load(const char *path, uint8_t **desc);
/* Eye detector */
void imlib_find_eyes(image_t *src, point_t *left, point_t *right, rectangle_t *roi);
/* Drawing functions */
void imlib_draw_rectangle(struct image *image, struct rectangle *r);
void imlib_draw_circle(struct image *image, int cx, int cy, int r, color_t *c);

View File

@ -777,6 +777,36 @@ static mp_obj_t py_image_find_lbp(mp_obj_t image_obj, mp_obj_t roi_obj)
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);
PY_ASSERT_TRUE(image->bpp == 1);
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 l={0}, r={0};
imlib_find_eyes(image, &l, &r, &roi);
mp_obj_t eyes_obj[4] = {
mp_obj_new_int(l.x),
mp_obj_new_int(l.y),
mp_obj_new_int(r.x),
mp_obj_new_int(r.y),
};
return mp_obj_new_tuple(4, eyes_obj);
}
static mp_obj_t py_image_match_keypoints(uint n_args, const mp_obj_t *args)
{
image_t *image = py_image_cobj(args[0]);
@ -939,6 +969,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_find_template_obj, py_image_find_templ
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_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_VAR_BETWEEN(py_image_match_keypoints_obj, 4, 4, py_image_match_keypoints);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_image_match_lbp_obj, py_image_match_lbp);
@ -976,6 +1007,7 @@ static const mp_map_elem_t locals_dict_table[] = {
{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_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_match_keypoints), (mp_obj_t)&py_image_match_keypoints_obj},
{MP_OBJ_NEW_QSTR(MP_QSTR_match_lbp), (mp_obj_t)&py_image_match_lbp_obj},

View File

@ -0,0 +1,36 @@
import sensor, time
#sensor.reset()
# Set framesize
sensor.set_framesize(sensor.QCIF)
# Set sensor to grayscale
sensor.set_pixformat(sensor.GRAYSCALE)
# Set sensor contrast
sensor.set_contrast(1)
# Set sensor gainceiling
sensor.set_gainceiling(16)
face_cascade = HaarCascade("/frontalface.cascade")
while (True):
image = sensor.snapshot()
objects = image.find_features(face_cascade, threshold=0.45, scale=1.25)
if (len(objects)==0):
continue
roi = objects[0]
image.draw_rectangle(roi)
image.histeq()
eyes = image.find_eyes(roi)
l = 5
c = (eyes[0], eyes[1])
image.draw_line((c[0]-l, c[1], c[0]+l, c[1]))
image.draw_line((c[0], c[1]-l, c[0], c[1]+l))
c = (eyes[2], eyes[3])
image.draw_line((c[0]-l, c[1], c[0]+l, c[1]))
image.draw_line((c[0], c[1]-l, c[0], c[1]+l))
time.sleep(500)