Add support for loading haar cascade from file

This commit is contained in:
iabdalkader 2014-02-14 15:40:14 +02:00
parent 156d194bf8
commit 492b1488e2
4 changed files with 233 additions and 90 deletions

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
#include <stm32f4xx.h>
#include "array.h"
#include "imlib.h"
#include "cascade.h"
#include "ff.h"
#define MIN(a,b) \
({ __typeof__ (a) _a = (a); \
@ -270,47 +270,33 @@ void imlib_histeq(struct image *src)
/* Viola-Jones face detector implementation
* Original Author: Francesco Comaschi (f.comaschi@tue.nl)
*/
static int evalWeakClassifier(struct integral_image *sum, int std, int p_offset, int tree_index, int w_index, int r_index )
static int evalWeakClassifier(struct cascade *cascade, int std, int p_offset, int tree_index, int w_index, int r_index )
{
int i, sumw=0;
struct rectangle tr;
struct integral_image *sum = &cascade->sum;
/* the node threshold is multiplied by the standard deviation of the image */
int t = tree_thresh_array[tree_index] * std;
int t = cascade->tree_thresh_array[tree_index] * std;
/* this is just a hack will be removed when
we add the number of rects to the classifier */
tr.x = rectangles_array[r_index + 8];
tr.y = rectangles_array[r_index + 9];
tr.w = rectangles_array[r_index + 10];
tr.h = rectangles_array[r_index + 11];
int i,k, sumw=0;
if ((tr.x)&& (tr.y) &&(tr.w) &&(tr.h)) {
k = 3;
} else {
k = 2;
}
for (i=0; i<k; i++) {
tr.x = rectangles_array[r_index + i*4 + 0];
tr.y = rectangles_array[r_index + i*4 + 1];
tr.w = rectangles_array[r_index + i*4 + 2];
tr.h = rectangles_array[r_index + i*4 + 3];
for (i=0; i<cascade->num_rectangles_array[tree_index]; i++) {
tr.x = cascade->rectangles_array[r_index + i*4 + 0];
tr.y = cascade->rectangles_array[r_index + i*4 + 1];
tr.w = cascade->rectangles_array[r_index + i*4 + 2];
tr.h = cascade->rectangles_array[r_index + i*4 + 3];
sumw += (
*((sum->data + sum->w*(tr.y ) + (tr.x )) + p_offset)
- *((sum->data + sum->w*(tr.y ) + (tr.x + tr.w)) + p_offset)
- *((sum->data + sum->w*(tr.y + tr.h) + (tr.x )) + p_offset)
+ *((sum->data + sum->w*(tr.y + tr.h) + (tr.x + tr.w)) + p_offset))
* weights_array[w_index + i];
* cascade->weights_array[w_index + i]*4096;
}
if (sumw >= t) {
return alpha2_array[tree_index];
return cascade->alpha2_array[tree_index];
}
return alpha1_array[tree_index];
return cascade->alpha1_array[tree_index];
}
static int runCascadeClassifier(struct cascade* cascade, struct point pt, int start_stage)
@ -329,8 +315,8 @@ static int runCascadeClassifier(struct cascade* cascade, struct point pt, int st
uint32_t sumsq=0;
vec_t v0, v1;
for (y=pt.y; y<24; y++) {
for (x=pt.x; x<24; x+=2) {
for (y=pt.y; y<cascade->window.w; y++) {
for (x=pt.x; x<cascade->window.w; x+=2) {
offset = y*cascade->img->w+x;
v0.s0 = cascade->img->pixels[offset+0];
v0.s1 = cascade->img->pixels[offset+1];
@ -356,13 +342,15 @@ static int runCascadeClassifier(struct cascade* cascade, struct point pt, int st
for (i=start_stage; i<cascade->n_stages; i++) {
stage_sum = 0;
for (j=0; j<stages_array[i]; j++, tree_index++, w_index+=3, r_index+=12) {
for (j=0; j<cascade->stages_array[i]; j++, tree_index++) {
/* send the shifted window to a haar filter */
stage_sum += evalWeakClassifier(&cascade->sum, std, p_offset, tree_index, w_index, r_index);
stage_sum += evalWeakClassifier(cascade, std, p_offset, tree_index, w_index, r_index);
w_index+=cascade->num_rectangles_array[tree_index];
r_index+=4 * cascade->num_rectangles_array[tree_index];
}
/* If the sum is below the stage threshold, no faces are detected */
if (stage_sum < 0.4*stages_thresh_array[i]) {
if (stage_sum < 0.4*cascade->stages_thresh_array[i]) {
return -i;
}
}
@ -549,10 +537,130 @@ struct array *imlib_detect_objects(struct image *image, struct cascade *cascade)
/* process the current scale with the cascaded fitler. */
ScaleImageInvoker(cascade, factor, sum.h, sum.w, objects);
}
}
//free(sum.data);
objects = imlib_merge_detections(objects);
return objects;
}
int imlib_load_cascade(struct cascade* cascade, const char *path)
{
int i;
UINT n_out;
FIL fp;
FRESULT res=FR_OK;
res = f_open(&fp, path, FA_READ|FA_OPEN_EXISTING);
if (res != FR_OK) {
return res;
}
/* read detection window size */
res = f_read(&fp, &cascade->window, sizeof(cascade->window), &n_out);
if (res != FR_OK || n_out != sizeof(cascade->window)) {
goto error;
}
/* read num stages */
res = f_read(&fp, &cascade->n_stages, sizeof(cascade->n_stages), &n_out);
if (res != FR_OK || n_out != sizeof(cascade->n_stages)) {
goto error;
}
cascade->stages_array = malloc (sizeof(*cascade->stages_array) * cascade->n_stages);
cascade->stages_thresh_array = malloc (sizeof(*cascade->stages_thresh_array) * cascade->n_stages);
if (cascade->stages_array == NULL ||
cascade->stages_thresh_array == NULL) {
res = 20;
goto error;
}
/* read num features in each stages */
res = f_read(&fp, cascade->stages_array, sizeof(uint8_t) * cascade->n_stages, &n_out);
if (res != FR_OK || n_out != sizeof(uint8_t) * cascade->n_stages) {
goto error;
}
/* sum num of features in each stages*/
for (i=0, cascade->n_features=0; i<cascade->n_stages; i++) {
cascade->n_features += cascade->stages_array[i];
}
/* alloc features thresh array, alpha1, alpha 2,rects weights and rects*/
cascade->tree_thresh_array = malloc (sizeof(*cascade->tree_thresh_array) * cascade->n_features);
cascade->alpha1_array = malloc (sizeof(*cascade->alpha1_array) * cascade->n_features);
cascade->alpha2_array = malloc (sizeof(*cascade->alpha2_array) * cascade->n_features);
cascade->num_rectangles_array = malloc (sizeof(*cascade->num_rectangles_array) * cascade->n_features);
if (cascade->tree_thresh_array == NULL ||
cascade->alpha1_array == NULL ||
cascade->alpha2_array == NULL ||
cascade->num_rectangles_array == NULL) {
res = 20;
goto error;
}
/* read stages thresholds */
res = f_read(&fp, cascade->stages_thresh_array, sizeof(int16_t)*cascade->n_stages, &n_out);
if (res != FR_OK || n_out != sizeof(int16_t)*cascade->n_stages) {
goto error;
}
/* read features thresholds */
res = f_read(&fp, cascade->tree_thresh_array, sizeof(*cascade->tree_thresh_array)*cascade->n_features, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->tree_thresh_array)*cascade->n_features) {
goto error;
}
/* read alpha 1 */
res = f_read(&fp, cascade->alpha1_array, sizeof(*cascade->alpha1_array)*cascade->n_features, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->alpha1_array)*cascade->n_features) {
goto error;
}
/* read alpha 2 */
res = f_read(&fp, cascade->alpha2_array, sizeof(*cascade->alpha2_array)*cascade->n_features, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->alpha2_array)*cascade->n_features) {
goto error;
}
/* read num rectangles per feature*/
res = f_read(&fp, cascade->num_rectangles_array, sizeof(*cascade->num_rectangles_array)*cascade->n_features, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->num_rectangles_array)*cascade->n_features) {
goto error;
}
/* sum num of recatngles per feature*/
for (i=0, cascade->n_rectangles=0; i<cascade->n_features; i++) {
cascade->n_rectangles += cascade->num_rectangles_array[i];
}
cascade->weights_array = malloc (sizeof(*cascade->weights_array) * cascade->n_rectangles);
cascade->rectangles_array = malloc (sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4);
if (cascade->weights_array == NULL ||
cascade->rectangles_array == NULL) {
res = 20;
goto error;
}
/* read rectangles weights */
res =f_read(&fp, cascade->weights_array, sizeof(*cascade->weights_array)*cascade->n_rectangles, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->weights_array)*cascade->n_rectangles) {
goto error;
}
/* read rectangles num rectangles * 4 points */
res = f_read(&fp, cascade->rectangles_array, sizeof(*cascade->rectangles_array)*cascade->n_rectangles *4, &n_out);
if (res != FR_OK || n_out != sizeof(*cascade->rectangles_array)*cascade->n_rectangles *4) {
goto error;
}
error:
f_close(&fp);
return res;
}

View File

@ -72,12 +72,25 @@ struct cascade {
float scale_factor;
/* number of stages in the cascade */
int n_stages;
/* number of features in the cascade */
int n_features;
/* number of rectangles in the cascade */
int n_rectangles;
/* size of the window used in the training set */
struct size window;
/* pointer to current integral image */
struct integral_image sum;
/* pointer to current scaled image in the pyramid */
struct image *img;
/* pointer to current integral image */
struct integral_image sum;
/* haar cascade arrays */
uint8_t *stages_array;
int16_t *stages_thresh_array;
int16_t *tree_thresh_array;
int16_t *alpha1_array;
int16_t *alpha2_array;
int8_t *num_rectangles_array;
int8_t *weights_array;
int8_t *rectangles_array;
};
float imlib_distance(struct color *c0, struct color *c1);
@ -90,4 +103,5 @@ void imlib_integral_image(struct image *src, struct integral_image *sum);
void imlib_draw_rectangle(struct image *image, struct rectangle *r);
void imlib_histeq(struct image *src);
struct array *imlib_detect_objects(struct image *image, struct cascade* cascade);
int imlib_load_cascade(struct cascade* cascade, const char *path);
#endif //__IMLIB_H__

View File

@ -5,9 +5,40 @@
#include "py_image.h"
#include "py_imlib.h"
#include "py_assert.h"
#include "py_file.h"
typedef struct _py_cascade_obj_t {
mp_obj_base_t base;
struct cascade _cobj;
} py_cascade_obj_t;
extern struct sensor_dev sensor;
static void py_cascade_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind)
{
py_cascade_obj_t *self = self_in;
/* print some info */
print(env, "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 = {
{ &mp_const_type },
"Cascade",
.print = py_cascade_print,
};
void *py_cascade_cobj(mp_obj_t cascade)
{
PY_ASSERT_TYPE(cascade, &py_cascade_type);
return &((py_cascade_obj_t *)cascade)->_cobj;
}
mp_obj_t py_imlib_histeq(mp_obj_t image_obj)
{
struct image *image;
@ -69,49 +100,66 @@ mp_obj_t py_imlib_detect_color(mp_obj_t image_obj, mp_obj_t color_obj, mp_obj_t
return rt_build_tuple(4, rec_obj);
}
mp_obj_t py_imlib_detect_objects(mp_obj_t image_obj)
mp_obj_t py_imlib_detect_objects(mp_obj_t image_obj, mp_obj_t cascade_obj)
{
struct image *image = NULL;
struct array *objects=NULL;
mp_obj_t mp_objects = mp_const_none;
struct cascade *cascade = NULL;
/* detection parameters */
struct cascade cascade = {
.step = 2,
.n_stages = 12,
.window = {24, 24},
.scale_factor = 1.25f,
};
struct array *objects_array=NULL;
mp_obj_t objects_list = mp_const_none;
/* sanity checks */
PY_ASSERT_TRUE(sensor.framesize <= FRAMESIZE_QQVGA);
PY_ASSERT_TRUE(sensor.pixformat == PIXFORMAT_GRAYSCALE);
/* get image pointer */
image = (struct image*) py_image_cobj(image_obj);
/* get C image pointer */
image = py_image_cobj(image_obj);
/* get C cascade pointer */
cascade = py_cascade_cobj(cascade_obj);
objects = imlib_detect_objects(image, &cascade);
int size = array_length(objects);
/* detect objects */
objects_array = imlib_detect_objects(image, cascade);
int size = array_length(objects_array);
if (size) {
int i;
objects_list = rt_build_list(0, NULL);
for (i=0; i<size; i++) {
imlib_draw_rectangle(image, array_at(objects, i));
struct rectangle *r = array_at(objects_array, 0);
mp_obj_t rec_obj[4];
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);
rt_list_append(objects_list, rt_build_tuple(4, rec_obj));
}
struct rectangle *r = array_at(objects, 0);
mp_obj_t rec_obj[4];
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);
mp_objects = rt_build_tuple(4, rec_obj);
}
/* free objects array */
array_free(objects);
array_free(objects_array);
return mp_objects;
return objects_list;
}
mp_obj_t py_imlib_load_cascade(mp_obj_t path_obj)
{
py_cascade_obj_t *o =NULL;
/* detection parameters */
struct cascade cascade = {
.step = 2,
.scale_factor = 1.25f,
};
const char *path = mp_obj_str_get_str(path_obj);
int res = imlib_load_cascade(&cascade, path);
if (res != FR_OK) {
nlr_jump(mp_obj_new_exception_msg(qstr_from_str("Imlib"), ffs_strerror(res)));
}
o = m_new_obj(py_cascade_obj_t);
o->base.type = &py_cascade_type;
o->_cobj = cascade;
return o;
}
void py_imlib_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind)
@ -128,7 +176,8 @@ mp_obj_t py_imlib_init()
rt_store_attr(m, qstr_from_str("histeq"), rt_make_function_n(1, py_imlib_histeq));
rt_store_attr(m, qstr_from_str("draw_rectangle"), rt_make_function_n(2, py_imlib_draw_rectangle));
rt_store_attr(m, qstr_from_str("detect_color"), rt_make_function_n(3, py_imlib_detect_color));
rt_store_attr(m, qstr_from_str("detect_objects"), rt_make_function_n(1, py_imlib_detect_objects));
rt_store_attr(m, qstr_from_str("detect_objects"), rt_make_function_n(2, py_imlib_detect_objects));
rt_store_attr(m, qstr_from_str("load_cascade"), rt_make_function_n(1, py_imlib_load_cascade));
return m;
}