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