Mercurial > pidgin
comparison plugins/crazychat/camproc.c @ 11218:ed017b9c532d
[gaim-migrate @ 13350]
crazychat commit, first one.
committer: Tailor Script <tailor@pidgin.im>
author | Charlie Stockman <chuckleberry> |
---|---|
date | Tue, 09 Aug 2005 07:10:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
11217:f854402837ba | 11218:ed017b9c532d |
---|---|
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 |