| 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 |
|