mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add Eye Detector
This commit is contained in:
parent
c15fc85786
commit
ef9bf26981
@ -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
|
||||
@ -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
146
src/omv/img/eye.c
Normal 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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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},
|
||||
|
||||
|
||||
36
usr/examples/eye_detection.py
Normal file
36
usr/examples/eye_detection.py
Normal 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)
|
||||
Loading…
Reference in New Issue
Block a user