11218
|
1 /*
|
|
2 * camproc.c
|
|
3 * basecame
|
|
4 *
|
|
5 * Created by CS194 on Mon Apr 26 2004.
|
|
6 * Copyright (c) 2004 __MyCompanyName__. All rights reserved.
|
|
7 *
|
|
8 */
|
|
9
|
|
10
|
|
11 #include "camdata.h"
|
|
12 #include "Utilities.h"
|
|
13 #include "QTUtilities.h"
|
|
14 #include "stdio.h"
|
|
15 #include "math.h"
|
|
16 #include <gtk/gtk.h>
|
|
17 #include "cc_interface.h"
|
|
18 #include "filter.h"
|
|
19
|
|
20
|
|
21 extern int detection_mode;
|
|
22 extern mungDataPtr myMungData;
|
|
23 extern int x_click;
|
|
24 extern int y_click;
|
|
25
|
|
26
|
|
27 #define kMinimumIdleDurationInMillis kEventDurationMillisecond
|
|
28 #define BailErr(x) {if (x != noErr) goto bail;}
|
|
29 #define PRE_CALIBRATE_MODE 0
|
|
30 #define CALIBRATE_MODE 1
|
|
31 #define SCAN_MODE 2
|
|
32
|
|
33 #define CALIB_TOP 190
|
|
34 #define CALIB_BOTTOM 200
|
|
35 #define CALIB_LEFT 200
|
|
36 #define CALIB_RIGHT 210
|
|
37
|
|
38 #define CALIB_RADIUS 5
|
|
39
|
|
40 #define NUM_FRAMES_EYE_SEARCH 50
|
|
41 #define EYE_UNCONFIDENCE_LIMIT 7
|
|
42
|
|
43 #define BLINK_THRESHOLD 75
|
|
44 #define BLINK_LENGTH 10
|
|
45 #define WHITE_THRESH 25
|
|
46 #define WHITE_COUNT_MAX 200
|
|
47
|
|
48
|
|
49 struct input_instance* instance;
|
|
50 int scan_region_left;
|
|
51 int scan_region_right;
|
|
52 int scan_region_top;
|
|
53 int scan_region_bottom;
|
|
54
|
|
55 int lum_thresh=150;
|
|
56 int face_left;
|
|
57 int face_right;
|
|
58 int face_top;
|
|
59 int face_bottom;
|
|
60 int old_left_eye_x=50;
|
|
61 int old_left_eye_y=50;
|
|
62 int old_right_eye_x=50;
|
|
63 int old_right_eye_y=50;
|
|
64 int left_eye_x;
|
|
65 int left_eye_y;
|
|
66 int right_eye_x;
|
|
67 int right_eye_y;
|
|
68 int eye_search_frame_count=0;
|
|
69 int bozo_bit=0;
|
|
70 int eye_unconfidence=0;
|
|
71 int last_eye_count_left=0;
|
|
72 int last_eye_count_right=0;
|
|
73 int mouth_ctr_x;
|
|
74 int mouth_ctr_y;
|
|
75 int mouth_size, mouth_left, mouth_right, mouth_top, mouth_bottom;
|
|
76 int white_count;
|
|
77 guint8 head_size_old;
|
|
78 int left_eye_blink_count;
|
|
79 int right_eye_blink_count;
|
|
80
|
|
81 int left_eye_top, left_eye_bottom, left_eye_right, left_eye_left;
|
|
82 int right_eye_top, right_eye_bottom, right_eye_right, right_eye_left;
|
|
83
|
|
84 filter_bank *bank;
|
|
85
|
|
86 static SeqGrabComponent mSeqGrab = NULL;
|
|
87 static SGChannel mSGChanVideo = NULL;
|
|
88 static SGDataUPP mMyDataProcPtr = NULL;
|
|
89 static EventLoopTimerRef mSGTimerRef = 0;
|
|
90 static ImageSequence mDecomSeq = 0;
|
|
91 static EventLoopTimerUPP mSGTimerUPP = nil;
|
|
92 static Rect mMungRect = {0, 0, 480, 640};
|
|
93 int lower_left_corner_x = 200;
|
|
94 int lower_left_corner_y = 200;
|
|
95 int upper_right_corner_x = 210;
|
|
96 int upper_right_corner_y = 190;
|
|
97
|
|
98
|
|
99 static pascal OSErr MiniMungDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon);
|
|
100 static pascal void SGIdlingTimer(EventLoopTimerRef inTimer, void *inUserData);
|
|
101 static void DetectLobster(GWorldPtr mungDataOffscreen);
|
|
102 int SkinDetect(double Y, double E, double S);
|
|
103 void ScanSkin(PixMapHandle p);
|
|
104 void drawbox(int top, int bottom, int left, int right, int color);
|
|
105 void SkinStats (PixMapHandle p, int top, int bottom, int left, int right);
|
|
106 void SetEyeSearchRegions(void);
|
|
107
|
|
108
|
|
109 typedef enum {RED, GREEN, BLUE} color;
|
|
110 color saved_best=-1;
|
|
111
|
|
112 int filenum=0;
|
|
113
|
|
114
|
|
115 OSErr CamProc(struct input_instance *inst, filter_bank *f)
|
|
116 {
|
|
117 OSStatus error;
|
|
118 OSErr err = noErr;
|
|
119
|
|
120 BailErr(err = InitializeMungData(mMungRect));
|
|
121
|
|
122 bank = f;
|
|
123
|
|
124 instance=inst;
|
|
125 mMyDataProcPtr = NewSGDataUPP(MiniMungDataProc);
|
|
126 mSeqGrab = OpenDefaultComponent(SeqGrabComponentType, 0);
|
|
127 BailErr((err = CreateNewSGChannelForRecording( mSeqGrab,
|
|
128 mMyDataProcPtr,
|
|
129 GetMungDataOffscreen(), // drawing destination
|
|
130 &mMungRect,
|
|
131 &mSGChanVideo,
|
|
132 NULL)));
|
|
133
|
|
134 bail:
|
|
135 return err;
|
|
136 }
|
|
137
|
|
138 void QueryCam (void)
|
|
139 {
|
|
140 SGIdle(mSeqGrab);
|
|
141 }
|
|
142
|
|
143 static pascal void SGIdlingTimer(EventLoopTimerRef inTimer, void *inUserData)
|
|
144 {
|
|
145 #pragma unused(inUserData)
|
|
146
|
|
147 if (mSeqGrab)
|
|
148 {
|
|
149 SGIdle(mSeqGrab);
|
|
150 }
|
|
151
|
|
152 // Reschedule the event loop timer
|
|
153 SetEventLoopTimerNextFireTime(inTimer, kMinimumIdleDurationInMillis);
|
|
154 }
|
|
155
|
|
156 static pascal OSErr MiniMungDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon)
|
|
157 {
|
|
158
|
|
159
|
|
160 #pragma unused(offset,chRefCon,time,writeType,refCon)
|
|
161 ComponentResult err = noErr;
|
|
162 CodecFlags ignore;
|
|
163 GWorldPtr gWorld;
|
|
164
|
|
165
|
|
166
|
|
167
|
|
168 if (!myMungData) goto bail;
|
|
169
|
|
170 gWorld = GetMungDataOffscreen();
|
|
171 if(gWorld)
|
|
172 {
|
|
173 if (mDecomSeq == 0) // init a decompression sequence
|
|
174 {
|
|
175 Rect bounds;
|
|
176
|
|
177 GetMungDataBoundsRect(&bounds);
|
|
178
|
|
179 BailErr( CreateDecompSeqForSGChannelData(c, &bounds, gWorld, &mDecomSeq));
|
|
180
|
|
181 if(1)
|
|
182 //if ((!mUseOverlay) && (GetCurrentClamp() == -1) && (!mUseEffect))
|
|
183 {
|
|
184 ImageSequence drawSeq;
|
|
185
|
|
186 err = CreateDecompSeqForGWorldData( gWorld,
|
|
187 &bounds,
|
|
188 nil,
|
|
189 GetMungDataWindowPort(),
|
|
190 &drawSeq);
|
|
191 SetMungDataDrawSeq(drawSeq);
|
|
192 }
|
|
193 }
|
|
194
|
|
195 // decompress data to our offscreen gworld
|
|
196 BailErr(DecompressSequenceFrameS(mDecomSeq,p,len,0,&ignore,nil));
|
|
197
|
|
198 // image is now in the GWorld - manipulate it at will!
|
|
199 //if ((mUseOverlay) || (GetCurrentClamp() != -1) || (mUseEffect))
|
|
200 //{
|
|
201 // use our custom decompressor to "decompress" the data
|
|
202 // to the screen with overlays or color clamping
|
|
203 // BlitOneMungData(myMungData);
|
|
204 //}
|
|
205 //else
|
|
206 //{
|
|
207 // we are doing a motion detect grab, so
|
|
208 // search for lobsters in our image data
|
|
209 DetectLobster(gWorld);
|
|
210 //}
|
|
211
|
|
212 }
|
|
213
|
|
214 bail:
|
|
215 return err;
|
|
216 }
|
|
217
|
|
218 void Die()
|
|
219 {
|
|
220 //RemoveEventLoopTimer(mSGTimerRef);
|
|
221 // mSGTimerRef = nil;
|
|
222 // DisposeEventLoopTimerUPP(mSGTimerUPP);
|
|
223 DoCloseSG(mSeqGrab, mSGChanVideo, mMyDataProcPtr);
|
|
224
|
|
225 }
|
|
226
|
|
227
|
|
228 float Y_mean=-1;
|
|
229 float Y_dev,E_mean,E_dev,S_mean,S_dev;
|
|
230 /*
|
|
231 extern colorBuf[480][640];
|
|
232 */
|
|
233 extern unsigned int (*colorBuf)[644];
|
|
234 extern struct input_instance input_data;
|
|
235
|
|
236 static void DetectLobster(GWorldPtr mungDataOffscreen)
|
|
237 {
|
|
238 CGrafPtr oldPort;
|
|
239 GDHandle oldDevice;
|
|
240 int x, y;
|
|
241 Rect bounds;
|
|
242 PixMapHandle pix = GetGWorldPixMap(mungDataOffscreen);
|
|
243 UInt32 * baseAddr;
|
|
244 UInt32 reds = 0;
|
|
245 Str255 tempString;
|
|
246 int minX = 10000, maxX = -10000;
|
|
247 int minY = 10000, maxY = -10000;
|
|
248 Rect tempRect;
|
|
249 float percent;
|
|
250 OSErr err;
|
|
251 CodecFlags ignore;
|
|
252 color best;
|
|
253 long R_total=0;
|
|
254 long G_total=0;
|
|
255 long B_total=0;
|
|
256
|
|
257
|
|
258
|
|
259 //fprintf(stderr, "Starting to find some lobsters...\n");
|
|
260
|
|
261
|
|
262 GetPortBounds(mungDataOffscreen, &bounds);
|
|
263 OffsetRect(&bounds, -bounds.left, -bounds.top);
|
|
264
|
|
265
|
|
266 UInt32 color;
|
|
267
|
|
268
|
|
269 int sum_x,sum_y=0;
|
|
270 int count=0;
|
|
271 int k,j;
|
|
272 long R;
|
|
273 long G;
|
|
274 long B;
|
|
275 int search_width=200;
|
|
276 int search_height=200;
|
|
277
|
|
278
|
|
279 colorBuf = GetPixBaseAddr(pix);
|
|
280
|
|
281 switch (detection_mode) {
|
|
282
|
|
283 case PRE_CALIBRATE_MODE:
|
|
284 //drawbox(CALIB_TOP, CALIB_BOTTOM, CALIB_LEFT, CALIB_RIGHT);
|
|
285 break;
|
|
286
|
|
287 case CALIBRATE_MODE:
|
|
288 SkinStats(pix, y_click-CALIB_RADIUS, y_click+CALIB_RADIUS, x_click-CALIB_RADIUS, x_click+CALIB_RADIUS);
|
|
289 scan_region_left=x_click-CALIB_RADIUS;//10;
|
|
290 scan_region_right=x_click+CALIB_RADIUS;//630;
|
|
291 scan_region_top=y_click-CALIB_RADIUS;//10;
|
|
292 scan_region_bottom=y_click+CALIB_RADIUS;//470;
|
|
293 ScanSkin(pix);
|
|
294 detection_mode=SCAN_MODE;
|
|
295 //fprintf(stderr, "scan left: %d scan right: %d \n",scan_region_left,scan_region_right);
|
|
296 head_size_old=50;
|
|
297 break;
|
|
298
|
|
299 case SCAN_MODE:
|
|
300 ScanSkin(pix);
|
|
301 drawbox(face_top, face_bottom, face_left, face_right,1);
|
|
302 //drawbox(scan_region_top, scan_region_bottom, scan_region_left, scan_region_right);
|
|
303 drawbox((left_eye_y-5),(left_eye_y+5),(left_eye_x-5),(left_eye_x+5),0);
|
|
304 drawbox((right_eye_y-5),(right_eye_y+5),(right_eye_x-5),(right_eye_x+5),0);
|
|
305 int face_scale=instance->face.head_size;
|
|
306 int mouth_width=face_scale;
|
|
307 int mouth_height=face_scale;
|
|
308 // if (bozo_bit==1) drawbax((mouth_ctr_y-mouth_height),(mouth_ctr_y+mouth_height),(mouth_ctr_x-mouth_width),(mouth_ctr_x+mouth_width));
|
|
309 filter(&instance->face, bank);
|
|
310 break;
|
|
311 }
|
|
312
|
|
313 //fprintf(stderr, "Lobsters found...\n");
|
|
314
|
|
315
|
|
316 }
|
|
317
|
|
318
|
|
319
|
|
320
|
|
321 void ScanSkin(PixMapHandle p)
|
|
322 {
|
|
323 int y,x,j,k;
|
|
324 int right_eye_x_sum,right_eye_y_sum,left_eye_x_sum,left_eye_y_sum,right_eye_pt_count,left_eye_pt_count;
|
|
325 right_eye_x_sum=right_eye_y_sum=left_eye_x_sum=left_eye_y_sum=right_eye_pt_count=left_eye_pt_count=0;
|
|
326 long R,G,B,sum_x,sum_y;
|
|
327 int count;
|
|
328 double Y,E,S,lum;
|
|
329 double min_lum_mouth=766;
|
|
330 double min_lum_left=766;
|
|
331 double min_lum_right=766;
|
|
332 UInt32 color;
|
|
333 UInt32 * baseAddr;
|
|
334 int max_horz=0;
|
|
335 int max_vert=0;
|
|
336 sum_x=sum_y=count=0;
|
|
337 int horz_count[480];
|
|
338 int vert_count[640];
|
|
339
|
|
340
|
|
341
|
|
342 memset(horz_count,0,480*sizeof(int));
|
|
343 memset(vert_count,0,640*sizeof(int));
|
|
344
|
|
345 if (eye_search_frame_count<NUM_FRAMES_EYE_SEARCH) eye_search_frame_count++;
|
|
346 else if (eye_search_frame_count==NUM_FRAMES_EYE_SEARCH && bozo_bit==0)
|
|
347 {
|
|
348 bozo_bit=1;
|
|
349 //fprintf(stderr, "GOOD You flipped the bozo bit (to good)\n");
|
|
350 }
|
|
351
|
|
352 SetEyeSearchRegions();
|
|
353
|
|
354
|
|
355 for (y = scan_region_top; y < scan_region_bottom; y++) // change this to only calculate in bounding box
|
|
356 {
|
|
357 baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p));
|
|
358 for (x = scan_region_left; x < scan_region_right; x++)
|
|
359 {
|
|
360 color=baseAddr[x];
|
|
361 R = (color & 0x00FF0000) >> 16;
|
|
362 G = (color & 0x0000FF00) >> 8;
|
|
363 B = (color & 0x000000FF) >> 0;
|
|
364 Y=.253*R+.684*G+.063*B;
|
|
365 E=.5*R-.5*G;
|
|
366 S=.25*R+.25*G-.5*B;
|
|
367 lum=R+G+B;
|
|
368
|
|
369 if (y>left_eye_top && y<left_eye_bottom)
|
|
370 {
|
|
371 if (x > left_eye_left && x<left_eye_right)
|
|
372 {
|
|
373 if (lum < lum_thresh) {
|
|
374 left_eye_x_sum+=x;
|
|
375 left_eye_y_sum+=y;
|
|
376 left_eye_pt_count++;
|
|
377 //colorBuf[y][x]=0x0000FF00;
|
|
378 }
|
|
379 }
|
|
380 }
|
|
381 if (y>right_eye_top && y<right_eye_bottom)
|
|
382 {
|
|
383 if (x > right_eye_left && x < right_eye_right)
|
|
384 {
|
|
385 if (lum < lum_thresh) {
|
|
386 right_eye_x_sum+=x;
|
|
387 right_eye_y_sum+=y;
|
|
388 right_eye_pt_count++;
|
|
389 //colorBuf[y][x]=0x0000FF00;
|
|
390 }
|
|
391 }
|
|
392 }
|
|
393
|
|
394 if(SkinDetect(Y,E,S))
|
|
395 {
|
|
396 sum_x+=x;
|
|
397 sum_y+=y;
|
|
398 count++;
|
|
399
|
|
400 ++horz_count[y];
|
|
401 ++vert_count[x];
|
|
402
|
|
403 if (horz_count[y]>max_horz) max_horz=horz_count[y];
|
|
404 if (vert_count[x]>max_vert) max_vert=vert_count[x];
|
|
405
|
|
406 //colorBuf[y][x]=0x00FF0000;
|
|
407 }
|
|
408
|
|
409 }
|
|
410 }
|
|
411
|
|
412
|
|
413 left_eye_x=left_eye_x_sum/left_eye_pt_count;
|
|
414 left_eye_y=left_eye_y_sum/left_eye_pt_count;
|
|
415 right_eye_x=right_eye_x_sum/right_eye_pt_count;
|
|
416 right_eye_y=right_eye_y_sum/right_eye_pt_count;
|
|
417
|
|
418
|
|
419
|
|
420 int width=right_eye_x-left_eye_x;
|
|
421 int height=right_eye_y-left_eye_y;
|
|
422 double face_ang;
|
|
423 if (width!=0) face_ang=atan((double)height/width);
|
|
424 else face_ang=0;
|
|
425 face_ang=face_ang*180/pi;
|
|
426 //fprintf(stderr,"face angle: %f \n",face_ang);
|
|
427
|
|
428 if ((left_eye_pt_count<5 || right_eye_pt_count<5 || width==0 || face_ang > 30 || face_ang < -30
|
|
429 || left_eye_y < (face_top+.15*(face_bottom-face_top))
|
|
430 || right_eye_y < (face_top+.15*(face_bottom-face_top)))
|
|
431 && bozo_bit==1){
|
|
432 eye_unconfidence++;
|
|
433 left_eye_x=old_left_eye_x;
|
|
434 left_eye_y=old_left_eye_y;
|
|
435 right_eye_x=old_right_eye_x;
|
|
436 right_eye_y=old_right_eye_y;
|
|
437 }
|
|
438 else {
|
|
439 eye_unconfidence=0;
|
|
440 old_left_eye_x=left_eye_x;
|
|
441 old_left_eye_y=left_eye_y;
|
|
442 old_right_eye_x=right_eye_x;
|
|
443 old_right_eye_y=right_eye_y;
|
|
444 }
|
|
445
|
|
446
|
|
447 if (eye_unconfidence==EYE_UNCONFIDENCE_LIMIT){
|
|
448 bozo_bit=0;
|
|
449 eye_search_frame_count=0;
|
|
450 //fprintf(stderr, "Recalibrating eyes\n");
|
|
451 }
|
|
452
|
|
453 if ((last_eye_count_left-left_eye_pt_count> BLINK_THRESHOLD) && eye_unconfidence==0)
|
|
454 {
|
|
455 left_eye_blink_count=BLINK_LENGTH;
|
|
456 }
|
|
457 if (left_eye_blink_count>0){
|
|
458 instance->face.left_eye_open=0;
|
|
459 left_eye_blink_count--;
|
|
460 }
|
|
461 else instance->face.left_eye_open=1;
|
|
462
|
|
463 if ((last_eye_count_right-right_eye_pt_count> BLINK_THRESHOLD) && eye_unconfidence==0)
|
|
464 {
|
|
465 right_eye_blink_count=BLINK_LENGTH;
|
|
466 }
|
|
467 if (right_eye_blink_count>0){
|
|
468 instance->face.right_eye_open=0;
|
|
469 right_eye_blink_count--;
|
|
470 }
|
|
471 else instance->face.right_eye_open=1;
|
|
472
|
|
473 if (instance->face.right_eye_open==0) instance->face.left_eye_open=0;
|
|
474 if (instance->face.left_eye_open==0) instance->face.right_eye_open=0;
|
|
475
|
|
476 last_eye_count_left=left_eye_pt_count;
|
|
477 last_eye_count_right=right_eye_pt_count;
|
|
478
|
|
479 float x_shift=0;
|
|
480 if (width!=0) x_shift= (float)height/(float)width; // --> note dependence on earlier data here
|
|
481
|
|
482
|
|
483 if (bozo_bit==1){
|
|
484 int mouth_search_start_y=face_top+(.6*(face_bottom-face_top));
|
|
485 int mouth_search_end_y=face_bottom;
|
|
486 int mouth_search_start_x=(left_eye_x+right_eye_x)/2 + (-x_shift*(mouth_search_start_y-((right_eye_y+left_eye_y)/2))) ;
|
|
487
|
|
488 for (y=mouth_search_start_y; y < mouth_search_end_y; y++)
|
|
489 {
|
|
490 x=mouth_search_start_x+((y - mouth_search_start_y)*(-x_shift));
|
|
491 baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p));
|
|
492 //colorBuf[y][x] = 0x0000FF00;
|
|
493 color=baseAddr[x];
|
|
494 R = (color & 0x00FF0000) >> 16;
|
|
495 G = (color & 0x0000FF00) >> 8;
|
|
496 B = (color & 0x000000FF) >> 0;
|
|
497 lum=R+G+B;
|
|
498
|
|
499 if (lum<min_lum_mouth) {
|
|
500 min_lum_mouth=lum;
|
|
501 mouth_ctr_x=x;
|
|
502 mouth_ctr_y=y;
|
|
503 }
|
|
504 }
|
|
505
|
|
506 mouth_size=(face_right-face_left)*100/640;
|
|
507 mouth_left=mouth_ctr_x-mouth_size;
|
|
508 if (mouth_left < face_left) mouth_left=face_left;
|
|
509 mouth_right=mouth_ctr_x+mouth_size;
|
|
510 if (mouth_right > face_right) mouth_right=face_right;
|
|
511 mouth_top=mouth_ctr_y-mouth_size;
|
|
512 if (mouth_top < face_top) mouth_top=face_top;
|
|
513 mouth_bottom=mouth_ctr_y+mouth_size;
|
|
514 if (mouth_bottom > face_bottom) mouth_bottom=face_bottom;
|
|
515
|
|
516 white_count=0;
|
|
517
|
|
518 for (y=mouth_top; y< mouth_bottom; y++){
|
|
519 baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p));
|
|
520 for (x=mouth_left; x< mouth_right; x++){
|
|
521 color=baseAddr[x];
|
|
522 R = (color & 0x00FF0000) >> 16;
|
|
523 G = (color & 0x0000FF00) >> 8;
|
|
524 B = (color & 0x000000FF) >> 0;
|
|
525 if ((abs(R-G) < WHITE_THRESH) && (abs(G-B) < WHITE_THRESH) && (abs(R-B) < WHITE_THRESH))
|
|
526 {
|
|
527 white_count++;
|
|
528 //colorBuf[y][x]=0x0000FF00;
|
|
529 }
|
|
530 }
|
|
531 }
|
|
532
|
|
533 }
|
|
534 else white_count=10;
|
|
535
|
|
536 // This next section finds the face region and sets the face_* parameters.
|
|
537
|
|
538 int scan;
|
|
539 float thresh=.3;
|
|
540 scan=scan_region_left+1;
|
|
541 if (scan<0) scan=0;
|
|
542 //fprintf(stderr,"threshold value: %d boxtop value: %d \n", (max_horz), horz_count[scan_region_top]);
|
|
543 while(1)
|
|
544 {
|
|
545 if (vert_count[scan]>=(thresh*max_vert))
|
|
546 {
|
|
547 face_left=scan;
|
|
548 break;
|
|
549 }
|
|
550 scan++;
|
|
551 }
|
|
552
|
|
553 scan=scan_region_right-1;
|
|
554 if (scan>=640) scan=639;
|
|
555 while(1)
|
|
556 {
|
|
557 if (vert_count[scan]>=(thresh*max_vert))
|
|
558 {
|
|
559 face_right=scan;
|
|
560 break;
|
|
561 }
|
|
562 scan--;
|
|
563 }
|
|
564
|
|
565 scan=scan_region_top+1;
|
|
566 if (scan<0) scan=0;
|
|
567 while(1)
|
|
568 {
|
|
569 if (horz_count[scan]>=(thresh*max_horz))
|
|
570 {
|
|
571 face_top=scan;
|
|
572 break;
|
|
573 }
|
|
574 scan++;
|
|
575 }
|
|
576
|
|
577
|
|
578 scan=scan_region_bottom-1;
|
|
579 if (scan>=480) scan=479;
|
|
580 while(1)
|
|
581 {
|
|
582 if (horz_count[scan]>=(thresh*max_horz))
|
|
583 {
|
|
584 face_bottom=scan;
|
|
585 break;
|
|
586 }
|
|
587 scan--;
|
|
588 }
|
|
589
|
|
590 // Base scan region on face region here
|
|
591 scan_region_left=face_left-10;
|
|
592 if (scan_region_left <= 0) scan_region_left=1;
|
|
593 scan_region_right=face_right+10;
|
|
594 if (scan_region_right >= 640) scan_region_right=639;
|
|
595 scan_region_top=face_top-10;
|
|
596 if (scan_region_top <= 0) scan_region_top=1;
|
|
597 scan_region_bottom=face_bottom+10;
|
|
598 if (scan_region_bottom >= 480) scan_region_bottom=479;
|
|
599
|
|
600
|
|
601 // Calculate some stats
|
|
602
|
|
603 // face size
|
|
604 width=face_right-face_left;
|
|
605 guint8 temp=width*100/640;
|
|
606 instance->face.head_size=temp;
|
|
607
|
|
608 // face location
|
|
609 temp=((double)100/(double)640)*(double)(face_right+face_left)/2;
|
|
610 instance->face.x=temp;
|
|
611 temp=((double)100/(double)480)*(double)(face_top+face_bottom)/2;
|
|
612 instance->face.y=temp;
|
|
613
|
|
614 // face angle-Z
|
|
615 instance->face.head_z_rot=face_ang+50;
|
|
616
|
|
617 // face angle-Y
|
|
618 int center=(face_right+face_left)/2;
|
|
619 int right_eye_strad=right_eye_x-center;
|
|
620 int left_eye_strad=center-left_eye_x;
|
|
621 double y_ang;
|
|
622 if (right_eye_strad > left_eye_strad) y_ang= (double)right_eye_strad/(double)left_eye_strad;
|
|
623 else y_ang=(double)left_eye_strad/(double)right_eye_strad;
|
|
624 y_ang=y_ang*5;
|
|
625 if (y_ang >= 10) y_ang=30;
|
|
626 if (y_ang <= 1) y_ang=1;
|
|
627
|
|
628 if (right_eye_strad > left_eye_strad) y_ang=-y_ang;
|
|
629 temp = (guint8) 50 + y_ang;
|
|
630 instance->face.head_y_rot=temp;
|
|
631
|
|
632 if (abs (temp-50) > 15) instance->face.head_size=head_size_old;
|
|
633 else head_size_old=instance->face.head_size;
|
|
634
|
|
635 temp = (guint8) 100 * white_count / WHITE_COUNT_MAX;
|
|
636 if (temp > 100) temp=100;
|
|
637 instance->face.mouth_open = temp;
|
|
638
|
|
639 }
|
|
640
|
|
641
|
|
642
|
|
643
|
|
644
|
|
645
|
|
646 // draw bounding box for either calibration or face
|
|
647
|
|
648
|
|
649 void SetEyeSearchRegions(void)
|
|
650 {
|
|
651 if (bozo_bit==0)
|
|
652 {
|
|
653 left_eye_top=face_top+(.25*(face_bottom-face_top));
|
|
654 left_eye_bottom=face_top+(.6*(face_bottom-face_top));
|
|
655 left_eye_right=((face_left+face_right)/2);
|
|
656 left_eye_left=face_left+.15*(face_right-face_left);
|
|
657
|
|
658 right_eye_top=face_top+(.25*(face_bottom-face_top));
|
|
659 right_eye_bottom=face_top+(.6*(face_bottom-face_top));
|
|
660 right_eye_right=face_right-.15*(face_right-face_left);
|
|
661 right_eye_left=((face_left+face_right)/2);
|
|
662 }
|
|
663
|
|
664 if (bozo_bit==1)
|
|
665 {
|
|
666 left_eye_top=left_eye_y-20;
|
|
667 left_eye_bottom=left_eye_y+20;
|
|
668 left_eye_left=left_eye_x-20;
|
|
669 left_eye_right=left_eye_x+20;
|
|
670
|
|
671 right_eye_top=right_eye_y-20;
|
|
672 right_eye_bottom=right_eye_y+20;
|
|
673 right_eye_left=right_eye_x-20;
|
|
674 right_eye_right=right_eye_x+20;
|
|
675 }
|
|
676 }
|
|
677
|
|
678
|
|
679 void drawbox(int top, int bottom, int left, int right, int color)
|
|
680 {
|
|
681 int y, x, j;
|
|
682
|
|
683 unsigned int col;
|
|
684
|
|
685
|
|
686 if (color==1)
|
|
687 col=0x00FFFF00;
|
|
688 else
|
|
689 col=0x00FF00FF;
|
|
690
|
|
691 if (top<0) top =0;
|
|
692 if (top>=480) top=479;
|
|
693 if (bottom<0) bottom =0;
|
|
694 if (bottom>=480) bottom=479;
|
|
695 if (left<0) left =0;
|
|
696 if (left>=640) left=639;
|
|
697 if (right<0) right =0;
|
|
698 if (right>=640) right=639;
|
|
699
|
|
700 if (color==1){
|
|
701
|
|
702 for (y=top; y<bottom; y++)
|
|
703 {
|
|
704 for (j=0;j<5;j++){
|
|
705 colorBuf[y][left+j] = col;
|
|
706 colorBuf[y][right-j] = col;
|
|
707 }
|
|
708
|
|
709 }
|
|
710
|
|
711 for (x=left; x<right; x++)
|
|
712 {
|
|
713
|
|
714 for (j=0;j<5;j++){
|
|
715
|
|
716 colorBuf[bottom-j][x] = col;
|
|
717 colorBuf[top+j][x] = col;
|
|
718
|
|
719 }
|
|
720
|
|
721 }
|
|
722
|
|
723
|
|
724 } else {
|
|
725
|
|
726
|
|
727
|
|
728 for (y=top; y<bottom; y++)
|
|
729 {
|
|
730 for (x=left;x<right;x++){
|
|
731 colorBuf[y][x] = col;
|
|
732 colorBuf[y][x] = col;
|
|
733 }
|
|
734
|
|
735 }
|
|
736
|
|
737 }
|
|
738 }
|
|
739
|
|
740
|
|
741
|
|
742 void SkinStats (PixMapHandle p, int top, int bottom, int left, int right)
|
|
743 {
|
|
744 double Y_sum,E_sum,S_sum;
|
|
745 int R,G,B;
|
|
746 int count=0;
|
|
747 Y_sum=E_sum=S_sum=0;
|
|
748 double Y,E,S;
|
|
749 UInt32 color;
|
|
750 int x, y;
|
|
751 UInt32 * baseAddr;
|
|
752
|
|
753 for (y=top; y<bottom; y++)
|
|
754 {
|
|
755 baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p));
|
|
756 for (x=left; x<right; x++)
|
|
757 {
|
|
758 count++;
|
|
759 color=baseAddr[x];
|
|
760
|
|
761 R = (color & 0x00FF0000) >> 16;
|
|
762 G = (color & 0x0000FF00) >> 8;
|
|
763 B = (color & 0x000000FF) >> 0;
|
|
764 Y=.253*R+.684*G+.063*B;
|
|
765 E=.5*R-.5*G;
|
|
766 S=.25*R+.25*G-.5*B;
|
|
767 Y_sum+=Y;
|
|
768 E_sum+=E;
|
|
769 S_sum+=S;
|
|
770 }
|
|
771 }
|
|
772
|
|
773 Y_mean=Y_sum/count;
|
|
774 E_mean=E_sum/count;
|
|
775 S_mean=S_sum/count;
|
|
776
|
|
777 Y_sum=E_sum=S_sum=0;
|
|
778
|
|
779 for (y=top; y<bottom; y++)
|
|
780 {
|
|
781 baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p));
|
|
782 for (x=left; x<right; x++)
|
|
783 {
|
|
784 color=baseAddr[x];
|
|
785 R = (color & 0x00FF0000) >> 16;
|
|
786 G = (color & 0x0000FF00) >> 8;
|
|
787 B = (color & 0x000000FF) >> 0;
|
|
788 Y=.253*R+.684*G+.063*B;
|
|
789 E=.5*R-.5*G;
|
|
790 S=.25*R+.25*G-.5*B;
|
|
791
|
|
792 Y_sum+=(Y-Y_mean)*(Y-Y_mean);
|
|
793 E_sum+=(E-E_mean)*(E-E_mean);
|
|
794 S_sum+=(S-S_mean)*(S-S_mean);
|
|
795
|
|
796 }
|
|
797 }
|
|
798
|
|
799 Y_dev=sqrt(Y_sum/(count-1));
|
|
800 E_dev=sqrt(E_sum/(count-1));
|
|
801 S_dev=sqrt(S_sum/(count-1));
|
|
802
|
|
803 //fprintf(stderr,"Y: %f, %f\n E: %f, %f\nS: %f, %f\n",Y_mean,E_mean,S_mean,Y_dev,E_dev,S_dev);
|
|
804
|
|
805 }
|
|
806
|
|
807 int SkinDetect(double Y, double E, double S)
|
|
808 {
|
|
809 if (E>(E_mean-(2*E_dev)) && E<(E_mean+(2*E_dev))) return 1;
|
|
810 else return 0;
|
|
811 }
|
|
812
|