mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add support for loading haar cascade from file
This commit is contained in:
parent
156d194bf8
commit
492b1488e2
File diff suppressed because one or more lines are too long
174
src/imlib.c
174
src/imlib.c
@ -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;
|
||||
}
|
||||
|
||||
18
src/imlib.h
18
src/imlib.h
@ -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__
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user