aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <sevyves@users.sourceforge.net>2009-06-10 16:44:53 +0000
committerN.N. <sevyves@users.sourceforge.net>2009-06-10 16:44:53 +0000
commite7e2e222ffaabba154b88a9a7c03c73189d472bd (patch)
treedf15bd7b3f306a9fbb7f003627624ac8866a1d68
parent287ba47dad0782e9afb721366788cfe0448c3642 (diff)
mark and identify recognized objects
svn path=/trunk/externals/pix_opencv/; revision=11737
-rw-r--r--pix_opencv_haarcascade-help.pd155
-rw-r--r--pix_opencv_haarcascade.cc228
-rw-r--r--pix_opencv_haarcascade.h14
-rw-r--r--pix_opencv_haarcascade2-help.pd137
4 files changed, 301 insertions, 233 deletions
diff --git a/pix_opencv_haarcascade-help.pd b/pix_opencv_haarcascade-help.pd
index b01813d..1c46f66 100644
--- a/pix_opencv_haarcascade-help.pd
+++ b/pix_opencv_haarcascade-help.pd
@@ -1,7 +1,7 @@
-#N canvas 512 26 691 638 10;
+#N canvas 197 73 1091 744 10;
#X obj 266 -83 gemhead;
-#X obj 316 556 pix_texture;
-#X obj 316 584 square 2;
+#X obj 87 544 pix_texture;
+#X obj 87 577 square 2;
#X obj 9 -74 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
0;
#N canvas 0 22 454 304 gemwin 0;
@@ -33,10 +33,10 @@
#X restore 14 -30 pd gemwin;
#X msg 14 -54 destroy;
#X text 10 -74 Create window and render;
-#X obj 143 248 pix_texture;
-#X obj 143 276 square 2;
-#X obj 266 167 translateXYZ -2 0 0;
-#X obj 314 254 cnv 15 175 200 empty empty empty 20 12 0 14 -24198 -66577
+#X obj -86 241 pix_texture;
+#X obj -86 269 square 2;
+#X obj 37 160 translateXYZ -2 0 0;
+#X obj 85 247 cnv 15 650 250 empty empty empty 20 12 0 14 -24198 -66577
0;
#X obj 278 -56 bng 25 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
-1;
@@ -47,50 +47,65 @@
#X msg 278 -7 open \$1;
#X obj 266 102 pix_film;
#X msg 284 36 auto \$1;
-#X obj 284 18 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+#X obj 284 18 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
#X msg 295 60 colorspace Grey;
-#X obj 316 228 translateXYZ 4 0 0;
-#X floatatom 464 520 5 0 0 0 - - -;
-#X floatatom 499 520 5 0 0 0 - - -;
-#X floatatom 536 520 5 0 0 0 - - -;
-#X floatatom 493 569 5 0 0 0 - - -;
-#X floatatom 528 569 5 0 0 0 - - -;
-#X floatatom 565 569 5 0 0 0 - - -;
-#X floatatom 537 625 5 0 0 0 - - -;
-#X floatatom 572 625 5 0 0 0 - - -;
-#X obj 316 409 pix_opencv_haarcascade;
-#X obj 319 193 separator;
-#X obj 403 258 openpanel;
-#X obj 461 440 route 0 1 2 3 4;
-#X text 521 458 For each face detected;
-#X text 589 523 Xcenter Ycenter Radius;
-#X text 612 570 Xcenter Ycenter Radius;
-#X obj 461 491 unpack 0 0 0;
-#X obj 490 540 unpack 0 0 0;
-#X obj 534 596 unpack 0 0 0;
-#X floatatom 612 625 5 0 0 0 - - -;
-#X text 654 625 Xcenter Ycenter Radius;
-#X msg 343 259 load \$1;
-#X text 493 260 Load a trained cascade classifier from XML file;
-#X obj 473 258 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+#X obj 87 221 translateXYZ 4 0 0;
+#X floatatom 264 583 5 0 0 0 - - -;
+#X floatatom 299 583 5 0 0 0 - - -;
+#X floatatom 336 583 5 0 0 0 - - -;
+#X floatatom 407 583 5 0 0 0 - - -;
+#X floatatom 442 583 5 0 0 0 - - -;
+#X floatatom 479 583 5 0 0 0 - - -;
+#X floatatom 545 585 5 0 0 0 - - -;
+#X floatatom 580 585 5 0 0 0 - - -;
+#X obj 88 472 pix_opencv_haarcascade;
+#X obj 90 186 separator;
+#X obj 174 251 openpanel;
+#X obj 251 529 route 0 1 2 3 4;
+#X text 251 601 Xcenter Ycenter Radius;
+#X text 396 600 Xcenter Ycenter Radius;
+#X obj 261 554 unpack 0 0 0;
+#X obj 404 554 unpack 0 0 0;
+#X obj 542 556 unpack 0 0 0;
+#X floatatom 620 584 5 0 0 0 - - -;
+#X text 539 601 Xcenter Ycenter Radius;
+#X msg 114 252 load \$1;
+#X text 264 253 Load a trained cascade classifier from XML file;
+#X obj 244 251 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
-1 -1;
-#X floatatom 481 315 5 0 0 0 - - -;
-#X floatatom 453 380 5 0 0 0 - - -;
-#X msg 360 344 mode \$1;
-#X obj 421 344 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+#X floatatom 281 348 5 0 0 0 - - -;
+#X floatatom 235 319 5 0 0 0 - - -;
+#X msg 134 285 mode \$1;
+#X obj 195 285 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
-#X msg 362 379 min_size \$1;
-#X msg 358 312 min_neighbors \$1;
-#X text 520 314 Minimum number (minus 1) of neighbor rectangles that
+#X msg 144 318 min_size \$1;
+#X msg 158 345 min_neighbors \$1;
+#X text 319 337 Minimum number (minus 1) of neighbor rectangles that
makes up an object (default 2);
-#X text 493 380 Minimum window size (default 30);
-#X msg 357 285 scale_factor \$1;
-#X floatatom 475 285 5 0 0 0 - - -;
-#X text 519 284 The factor by which the search window is scaled between
+#X msg 187 378 scale_factor \$1;
+#X floatatom 305 378 5 0 0 0 - - -;
+#X text 349 377 The factor by which the search window is scaled between
the subsequent scans (default 1.1);
-#X text 446 346 Mode of operation. Currently the only flag that may
-be specified is CV_HAAR_DO_CANNY_PRUNING;
+#X text 351 529 For each object detected;
+#X floatatom 158 503 5 0 0 0 - - -;
+#X text 197 503 number of objects detected;
+#X text 399 -22 used for face detection by default;
+#X text 396 -10 ( load haarscascase_frontalface_alt.xml );
+#X text 401 -47 pix_opencv_haarscasccade : object recognition based
+on Haar's algorithm ( decision tree algorithm );
+#X text 400 6 Written by Lluis Gomez i Bigorda ( lluisgomez@hangar.org
+);
+#X text 399 18 and Yves Degoyon ( ydegoyon@gmail.com );
+#X text 276 320 Minimum size of object (default 30);
+#X msg 215 407 ftolerance \$1;
+#X floatatom 305 408 5 0 0 0 - - -;
+#X msg 220 431 clear;
+#X text 346 415 temporarily ( default 5 );
+#X text 346 403 number of frames where an object can disappear;
+#X text 265 432 clear markers history;
+#X text 217 282 Mode of operation. Currently the only flag that may
+be specified is CV_HAAR_DO_CANNY_PRUNING ( 0 );
#X connect 0 0 16 0;
#X connect 1 0 2 0;
#X connect 4 0 5 0;
@@ -110,28 +125,32 @@ be specified is CV_HAAR_DO_CANNY_PRUNING;
#X connect 19 0 16 0;
#X connect 20 0 29 0;
#X connect 29 0 1 0;
-#X connect 29 1 32 0;
+#X connect 29 1 54 0;
+#X connect 29 2 32 0;
#X connect 30 0 20 0;
-#X connect 31 0 41 0;
-#X connect 32 0 36 0;
-#X connect 32 1 37 0;
-#X connect 32 2 38 0;
-#X connect 36 0 21 0;
-#X connect 36 1 22 0;
-#X connect 36 2 23 0;
-#X connect 37 0 24 0;
-#X connect 37 1 25 0;
-#X connect 37 2 26 0;
-#X connect 38 0 27 0;
-#X connect 38 1 28 0;
-#X connect 38 2 39 0;
-#X connect 41 0 29 0;
-#X connect 43 0 31 0;
-#X connect 44 0 49 0;
-#X connect 45 0 48 0;
-#X connect 46 0 29 0;
-#X connect 47 0 46 0;
+#X connect 31 0 40 0;
+#X connect 32 0 35 0;
+#X connect 32 1 36 0;
+#X connect 32 2 37 0;
+#X connect 35 0 21 0;
+#X connect 35 1 22 0;
+#X connect 35 2 23 0;
+#X connect 36 0 24 0;
+#X connect 36 1 25 0;
+#X connect 36 2 26 0;
+#X connect 37 0 27 0;
+#X connect 37 1 28 0;
+#X connect 37 2 38 0;
+#X connect 40 0 29 0;
+#X connect 42 0 31 0;
+#X connect 43 0 48 0;
+#X connect 44 0 47 0;
+#X connect 45 0 29 0;
+#X connect 46 0 45 0;
+#X connect 47 0 29 0;
#X connect 48 0 29 0;
-#X connect 49 0 29 0;
-#X connect 52 0 29 0;
-#X connect 53 0 52 0;
+#X connect 50 0 29 0;
+#X connect 51 0 50 0;
+#X connect 62 0 29 0;
+#X connect 63 0 62 0;
+#X connect 64 0 29 0;
diff --git a/pix_opencv_haarcascade.cc b/pix_opencv_haarcascade.cc
index f446f5b..ada76c2 100644
--- a/pix_opencv_haarcascade.cc
+++ b/pix_opencv_haarcascade.cc
@@ -16,6 +16,8 @@
/////////////////////////////////////////////////////////
#include "pix_opencv_haarcascade.h"
+#include <stdio.h>
+#include <stdlib.h>
CPPEXTERN_NEW(pix_opencv_haarcascade)
@@ -29,6 +31,9 @@ CPPEXTERN_NEW(pix_opencv_haarcascade)
/////////////////////////////////////////////////////////
pix_opencv_haarcascade :: pix_opencv_haarcascade()
{
+ int i;
+
+ m_numout = outlet_new(this->x_obj, 0);
m_dataout = outlet_new(this->x_obj, 0);
scale_factor = 1.1;
@@ -41,13 +46,23 @@ pix_opencv_haarcascade :: pix_opencv_haarcascade()
rgba = NULL;
grey = NULL;
frame = NULL;
+ x_ftolerance = 5;
- cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
- if( !cascade )
- {
- post( "ERROR: Could not load classifier cascade\n" );
- }
- else post( "Loaded classifier cascade from %s", cascade_name );
+ for ( i=0; i<MAX_MARKERS; i++ )
+ {
+ x_xmark[i] = -1;
+ x_ymark[i] = -1;
+ }
+
+ // initialize font
+ cvInitFont( &font, CV_FONT_HERSHEY_PLAIN, 1.0, 1.0, 0, 1, 8 );
+
+ cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
+ if( !cascade )
+ {
+ post( "ERROR: Could not load classifier cascade\n" );
+ }
+ else post( "Loaded classifier cascade from %s", cascade_name );
}
@@ -69,7 +84,7 @@ pix_opencv_haarcascade :: ~pix_opencv_haarcascade()
/////////////////////////////////////////////////////////
void pix_opencv_haarcascade :: processRGBAImage(imageStruct &image)
{
- double scale = 1;
+ double scale = 1;
if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!rgba)) {
@@ -102,40 +117,89 @@ void pix_opencv_haarcascade :: processRGBAImage(imageStruct &image)
{{255,0,255}}
};
- int i;
+ int i, im;
if( cascade )
{
CvSeq* faces = cvHaarDetectObjects( rgba, cascade, storage,
scale_factor, min_neighbors, mode, cvSize(min_size, min_size) );
+
+ if ( faces && (faces->total > 0 ) )
+ outlet_float(this->m_numout, (float)faces->total);
+ else
+ outlet_float(this->m_numout, 0.0);
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( this->x_xmark[im] != -1.0 )
+ {
+ this->x_found[im]--;
+ }
+ }
+
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
+ int oi, found;
+
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
CvPoint center;
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale);
center.y = cvRound((r->y + r->height*0.5)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
- cvCircle( rgba, center, radius, colors[i%8], 3, 8, 0 );
- t_atom rlist[4];
- SETFLOAT(&rlist[0], i);
- SETFLOAT(&rlist[1], center.x);
- SETFLOAT(&rlist[2], center.y);
- SETFLOAT(&rlist[3], radius);
- outlet_list( m_dataout, 0, 4, rlist );
+ found = 0;
+ oi = -1;
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // check if the object is already known
+ if ( sqrt( pow(center.x - this->x_xmark[im], 2 ) + pow(center.y - this->x_ymark[im], 2 ) ) <= radius )
+ {
+ oi=im;
+ found=1;
+ this->x_found[im] = this->x_ftolerance;
+ this->x_xmark[im] = center.x;
+ this->x_ymark[im] = center.y;
+ break;
+ }
+ }
+ // new object detected
+ if ( !found )
+ {
+ oi = this->mark(center.x, center.y );
+ }
+
+ char tindex[4];
+ sprintf( tindex, "%d", oi );
+ cvCircle( rgba, center, radius, colors[oi%8], 3, 8, 0 );
+ cvPutText( rgba, tindex, center, &this->font, CV_RGB(255,255,255));
+
+ SETFLOAT(&this->rlist[0], oi);
+ SETFLOAT(&this->rlist[1], center.x);
+ SETFLOAT(&this->rlist[2], center.y);
+ SETFLOAT(&this->rlist[3], radius);
+ outlet_list( m_dataout, 0, 4, this->rlist );
+ }
+ // delete lost objects
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( this->x_found[im] < 0 )
+ {
+ this->x_xmark[im] = -1.0;
+ this->x_ymark[im] = -1,0;
+ this->x_found[im] = this->x_ftolerance;
+ }
}
+
}
-
cvReleaseMemStorage( &storage );
- //cvShowImage(wndname, cedge);
memcpy( image.data, rgba->imageData, image.xsize*image.ysize*4 );
}
void pix_opencv_haarcascade :: processRGBImage(imageStruct &image)
{
- double scale = 1;
+ double scale = 1;
if ((this->comp_xsize!=image.xsize)||(this->comp_ysize!=image.ysize)||(!frame)) {
@@ -168,34 +232,82 @@ void pix_opencv_haarcascade :: processRGBImage(imageStruct &image)
{{255,0,255}}
};
- int i;
+ int i, im;
if( cascade )
{
CvSeq* faces = cvHaarDetectObjects( frame, cascade, storage,
1.1, 2, 0, cvSize(30, 30) );
+
+ if ( faces && (faces->total > 0 ) )
+ outlet_float(this->m_numout, (float)faces->total);
+ else
+ outlet_float(this->m_numout, 0.0);
+
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( this->x_xmark[im] != -1.0 )
+ {
+ this->x_found[im]--;
+ }
+ }
+
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
+ int oi, found;
+
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
CvPoint center;
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale);
center.y = cvRound((r->y + r->height*0.5)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
- cvCircle( frame, center, radius, colors[i%8], 3, 8, 0 );
- t_atom rlist[4];
- SETFLOAT(&rlist[0], i);
- SETFLOAT(&rlist[1], center.x);
- SETFLOAT(&rlist[2], center.y);
- SETFLOAT(&rlist[3], radius);
- outlet_list( m_dataout, 0, 4, rlist );
+ found = 0;
+ oi = -1;
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ // check if the object is already known
+ if ( sqrt( pow(center.x - this->x_xmark[im], 2 ) + pow(center.y - this->x_ymark[im], 2 ) ) <= radius )
+ {
+ oi=im;
+ found=1;
+ this->x_found[im] = this->x_ftolerance;
+ this->x_xmark[im] = center.x;
+ this->x_ymark[im] = center.y;
+ break;
+ }
+ }
+ // new object detected
+ if ( !found )
+ {
+ oi = this->mark(center.x, center.y );
+ }
+
+ char tindex[4];
+ sprintf( tindex, "%d", oi );
+ cvCircle( frame, center, radius, colors[oi%8], 3, 8, 0 );
+ cvPutText( frame, tindex, center, &this->font, CV_RGB(255,255,255));
+
+ SETFLOAT(&this->rlist[0], oi);
+ SETFLOAT(&this->rlist[1], center.x);
+ SETFLOAT(&this->rlist[2], center.y);
+ SETFLOAT(&this->rlist[3], radius);
+ outlet_list( m_dataout, 0, 4, this->rlist );
+ }
+ // delete lost objects
+ for ( im=0; im<MAX_MARKERS; im++ )
+ {
+ if ( this->x_found[im] < 0 )
+ {
+ this->x_xmark[im] = -1.0;
+ this->x_ymark[im] = -1,0;
+ this->x_found[im] = this->x_ftolerance;
+ }
}
}
-
cvReleaseMemStorage( &storage );
- //cvShowImage(wndname, cedge);
memcpy( image.data, frame->imageData, image.xsize*image.ysize*3 );
}
@@ -306,6 +418,31 @@ void pix_opencv_haarcascade :: minSizeMess (float min_size)
}
/////////////////////////////////////////////////////////
+// fToleranceMess
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_haarcascade :: fToleranceMess (float ftolerance)
+{
+ this->x_ftolerance = (int)ftolerance;
+}
+
+/////////////////////////////////////////////////////////
+// clearMess
+//
+/////////////////////////////////////////////////////////
+void pix_opencv_haarcascade :: clearMess (void)
+{
+ int i;
+
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ this->x_xmark[i] = -1;
+ this->x_ymark[i] = -1;
+ this->x_found[i] = this->x_ftolerance;
+ }
+}
+
+/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
@@ -321,6 +458,10 @@ void pix_opencv_haarcascade :: obj_setupCallback(t_class *classPtr)
gensym("min_size"), A_FLOAT, A_NULL);
class_addmethod(classPtr, (t_method)&pix_opencv_haarcascade::loadCascadeMessCallback,
gensym("load"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_haarcascade::fToleranceMessCallback,
+ gensym("ftolerance"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)&pix_opencv_haarcascade::clearMessCallback,
+ gensym("clear"), A_NULL);
}
void pix_opencv_haarcascade :: scaleFactorMessCallback(void *data, t_floatarg scale_factor)
{
@@ -338,6 +479,14 @@ void pix_opencv_haarcascade :: minSizeMessCallback(void *data, t_floatarg min_si
{
if (min_size>1) GetMyClass(data)->minSizeMess((float)min_size);
}
+void pix_opencv_haarcascade :: fToleranceMessCallback(void *data, t_floatarg ftolerance)
+{
+ if (ftolerance>1) GetMyClass(data)->fToleranceMess((float)ftolerance);
+}
+void pix_opencv_haarcascade :: clearMessCallback(void *data)
+{
+ GetMyClass(data)->clearMess();
+}
void pix_opencv_haarcascade :: loadCascadeMessCallback(void *data, t_symbol* filename)
{
GetMyClass(data)->loadCascadeMess(filename);
@@ -351,3 +500,26 @@ void pix_opencv_haarcascade :: loadCascadeMess(t_symbol *filename)
}
else post( "Loaded classifier cascade from %s", filename->s_name );
}
+int pix_opencv_haarcascade :: mark(float fx, float fy )
+{
+ int i;
+
+ if ( ( fx < 0.0 ) || ( fx > this->rgba->width ) || ( fy < 0 ) || ( fy > this->rgba->height ) )
+ {
+ return -1;
+ }
+
+ for ( i=0; i<MAX_MARKERS; i++)
+ {
+ if ( this->x_xmark[i] == -1 )
+ {
+ this->x_xmark[i] = (int)fx;
+ this->x_ymark[i] = (int)fy;
+ this->x_found[i] = this->x_ftolerance;
+ return i;
+ }
+ }
+
+ post( "pix_opencv_haarcascade : max markers reached" );
+ return -1;
+}
diff --git a/pix_opencv_haarcascade.h b/pix_opencv_haarcascade.h
index eee3dc3..640a6b4 100644
--- a/pix_opencv_haarcascade.h
+++ b/pix_opencv_haarcascade.h
@@ -22,6 +22,7 @@ LOG
#include "cv.h"
#endif
+#define MAX_MARKERS 50
const char* cascade_name ="./haarcascade_frontalface_alt.xml";
@@ -68,6 +69,9 @@ class GEM_EXTERN pix_opencv_haarcascade : public GemPixObj
void modeMess(float mode);
void minSizeMess(float min_size);
void loadCascadeMess(t_symbol *filename);
+ void fToleranceMess(float ftolerance);
+ void clearMess(void);
+ int mark(float fx, float fy );
// The parameters for cvHaarDetectObjects function
float scale_factor;
int min_neighbors;
@@ -76,6 +80,12 @@ class GEM_EXTERN pix_opencv_haarcascade : public GemPixObj
// to detect changes in the image size
int comp_xsize;
int comp_ysize;
+ t_atom rlist[4];
+ // marked objects history
+ int x_xmark[MAX_MARKERS];
+ int x_ymark[MAX_MARKERS];
+ int x_found[MAX_MARKERS];
+ int x_ftolerance;
private:
@@ -86,12 +96,16 @@ class GEM_EXTERN pix_opencv_haarcascade : public GemPixObj
static void modeMessCallback(void *data, float mode);
static void minSizeMessCallback(void *data, float min_size);
static void loadCascadeMessCallback(void *data, t_symbol* filename);
+ static void fToleranceMessCallback(void *data, float ftolerance);
+ static void clearMessCallback(void *data);
CvHaarClassifierCascade* cascade;
+ CvFont font;
/////////
// IplImage needed
IplImage *rgba, *frame, *grey;
+ t_outlet *m_numout;
t_outlet *m_dataout;
};
diff --git a/pix_opencv_haarcascade2-help.pd b/pix_opencv_haarcascade2-help.pd
deleted file mode 100644
index 789cdc5..0000000
--- a/pix_opencv_haarcascade2-help.pd
+++ /dev/null
@@ -1,137 +0,0 @@
-#N canvas 512 26 691 638 10;
-#X obj 266 -83 gemhead;
-#X obj 316 556 pix_texture;
-#X obj 316 584 square 2;
-#X obj 9 -74 cnv 15 220 70 empty empty empty 20 12 0 14 -195568 -66577
-0;
-#N canvas 0 22 454 304 gemwin 0;
-#X obj 132 136 gemwin;
-#X obj 67 89 outlet;
-#X obj 67 10 inlet;
-#X obj 67 41 route create;
-#X msg 67 70 set destroy;
-#X msg 182 68 set create;
-#X msg 132 112 create \, 1;
-#X msg 238 112 destroy;
-#N canvas 87 154 247 179 Gem.init 0;
-#X obj 118 46 loadbang;
-#X msg 118 81 reset;
-#X obj 118 113 outlet;
-#X connect 0 0 1 0;
-#X connect 1 0 2 0;
-#X restore 289 80 pd Gem.init;
-#X connect 2 0 3 0;
-#X connect 3 0 4 0;
-#X connect 3 0 6 0;
-#X connect 3 1 5 0;
-#X connect 3 1 7 0;
-#X connect 4 0 1 0;
-#X connect 5 0 1 0;
-#X connect 6 0 0 0;
-#X connect 7 0 0 0;
-#X connect 8 0 0 0;
-#X restore 14 -30 pd gemwin;
-#X msg 14 -54 destroy;
-#X text 10 -74 Create window and render;
-#X obj 143 248 pix_texture;
-#X obj 143 276 square 2;
-#X obj 266 167 translateXYZ -2 0 0;
-#X obj 314 254 cnv 15 175 200 empty empty empty 20 12 0 14 -24198 -66577
-0;
-#X obj 278 -56 bng 25 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
--1;
-#X obj 335 119 bng 15 250 50 0 empty empty end_reached 20 7 0 10 -262144
--1 -1;
-#X floatatom 317 84 5 0 10000 1 frame# - -;
-#X obj 278 -27 openpanel;
-#X msg 278 -7 open \$1;
-#X obj 266 102 pix_film;
-#X msg 284 36 auto \$1;
-#X obj 284 18 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
-;
-#X msg 295 60 colorspace Grey;
-#X obj 316 228 translateXYZ 4 0 0;
-#X floatatom 464 520 5 0 0 0 - - -;
-#X floatatom 499 520 5 0 0 0 - - -;
-#X floatatom 536 520 5 0 0 0 - - -;
-#X floatatom 493 569 5 0 0 0 - - -;
-#X floatatom 528 569 5 0 0 0 - - -;
-#X floatatom 565 569 5 0 0 0 - - -;
-#X floatatom 537 625 5 0 0 0 - - -;
-#X floatatom 572 625 5 0 0 0 - - -;
-#X obj 316 409 pix_opencv_haarcascade;
-#X obj 319 193 separator;
-#X obj 403 258 openpanel;
-#X obj 461 440 route 0 1 2 3 4;
-#X text 521 458 For each face detected;
-#X text 589 523 Xcenter Ycenter Radius;
-#X text 612 570 Xcenter Ycenter Radius;
-#X obj 461 491 unpack 0 0 0;
-#X obj 490 540 unpack 0 0 0;
-#X obj 534 596 unpack 0 0 0;
-#X floatatom 612 625 5 0 0 0 - - -;
-#X text 654 625 Xcenter Ycenter Radius;
-#X msg 343 259 load \$1;
-#X text 493 260 Load a trained cascade classifier from XML file;
-#X obj 473 258 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
--1 -1;
-#X floatatom 481 315 5 0 0 0 - - -;
-#X floatatom 453 380 5 0 0 0 - - -;
-#X msg 360 344 mode \$1;
-#X obj 421 344 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
-1;
-#X msg 362 379 min_size \$1;
-#X msg 358 312 min_neighbors \$1;
-#X text 522 315 Minimum number (minus 1) of neighbor rectangles that
-makes up an object (default 2);
-#X text 493 380 Minimum window size (default 30);
-#X msg 357 285 scale_factor \$1;
-#X floatatom 475 285 5 0 0 0 - - -;
-#X text 519 284 The factor by which the search window is scaled between
-the subsequent scans (default 1.1);
-#X text 520 313;
-#X text 446 346 Mode of operation. Currently the only flag that may
-be specified is CV_HAAR_DO_CANNY_PRUNING;
-#X connect 0 0 16 0;
-#X connect 1 0 2 0;
-#X connect 4 0 5 0;
-#X connect 5 0 4 0;
-#X connect 7 0 8 0;
-#X connect 9 0 7 0;
-#X connect 9 0 30 0;
-#X connect 11 0 14 0;
-#X connect 12 0 13 0;
-#X connect 13 0 16 1;
-#X connect 14 0 15 0;
-#X connect 15 0 16 0;
-#X connect 16 0 9 0;
-#X connect 16 2 12 0;
-#X connect 17 0 16 0;
-#X connect 18 0 17 0;
-#X connect 19 0 16 0;
-#X connect 20 0 29 0;
-#X connect 29 0 1 0;
-#X connect 30 0 20 0;
-#X connect 31 0 41 0;
-#X connect 32 0 36 0;
-#X connect 32 1 37 0;
-#X connect 32 2 38 0;
-#X connect 36 0 21 0;
-#X connect 36 1 22 0;
-#X connect 36 2 23 0;
-#X connect 37 0 24 0;
-#X connect 37 1 25 0;
-#X connect 37 2 26 0;
-#X connect 38 0 27 0;
-#X connect 38 1 28 0;
-#X connect 38 2 39 0;
-#X connect 41 0 29 0;
-#X connect 43 0 31 0;
-#X connect 44 0 49 0;
-#X connect 45 0 48 0;
-#X connect 46 0 29 0;
-#X connect 47 0 46 0;
-#X connect 48 0 29 0;
-#X connect 49 0 29 0;
-#X connect 52 0 29 0;
-#X connect 53 0 52 0;