* Created by CS194 on Mon Apr 26 2004. * Copyright (c) 2004 __MyCompanyName__. All rights reserved. #include "cc_interface.h" extern int detection_mode; extern mungDataPtr myMungData; #define kMinimumIdleDurationInMillis kEventDurationMillisecond #define BailErr(x) {if (x != noErr) goto bail;} #define PRE_CALIBRATE_MODE 0 #define NUM_FRAMES_EYE_SEARCH 50 #define EYE_UNCONFIDENCE_LIMIT 7 #define BLINK_THRESHOLD 75 #define WHITE_COUNT_MAX 200 struct input_instance* instance; int eye_search_frame_count=0; int last_eye_count_left=0; int last_eye_count_right=0; int mouth_size, mouth_left, mouth_right, mouth_top, mouth_bottom; int left_eye_blink_count; int right_eye_blink_count; int left_eye_top, left_eye_bottom, left_eye_right, left_eye_left; int right_eye_top, right_eye_bottom, right_eye_right, right_eye_left; static SeqGrabComponent mSeqGrab = NULL; static SGChannel mSGChanVideo = NULL; static SGDataUPP mMyDataProcPtr = NULL; static EventLoopTimerRef mSGTimerRef = 0; static ImageSequence mDecomSeq = 0; static EventLoopTimerUPP mSGTimerUPP = nil; static Rect mMungRect = {0, 0, 480, 640}; int lower_left_corner_x = 200; int lower_left_corner_y = 200; int upper_right_corner_x = 210; int upper_right_corner_y = 190; static pascal OSErr MiniMungDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon); static pascal void SGIdlingTimer(EventLoopTimerRef inTimer, void *inUserData); static void DetectLobster(GWorldPtr mungDataOffscreen); int SkinDetect(double Y, double E, double S); void ScanSkin(PixMapHandle p); void drawbox(int top, int bottom, int left, int right, int color); void SkinStats (PixMapHandle p, int top, int bottom, int left, int right); void SetEyeSearchRegions(void); typedef enum {RED, GREEN, BLUE} color; OSErr CamProc(struct input_instance *inst, filter_bank *f) BailErr(err = InitializeMungData(mMungRect)); mMyDataProcPtr = NewSGDataUPP(MiniMungDataProc); mSeqGrab = OpenDefaultComponent(SeqGrabComponentType, 0); BailErr((err = CreateNewSGChannelForRecording( mSeqGrab, GetMungDataOffscreen(), // drawing destination static pascal void SGIdlingTimer(EventLoopTimerRef inTimer, void *inUserData) #pragma unused(inUserData) // Reschedule the event loop timer SetEventLoopTimerNextFireTime(inTimer, kMinimumIdleDurationInMillis); static pascal OSErr MiniMungDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon) #pragma unused(offset,chRefCon,time,writeType,refCon) ComponentResult err = noErr; if (!myMungData) goto bail; gWorld = GetMungDataOffscreen(); if (mDecomSeq == 0) // init a decompression sequence GetMungDataBoundsRect(&bounds); BailErr( CreateDecompSeqForSGChannelData(c, &bounds, gWorld, &mDecomSeq)); //if ((!mUseOverlay) && (GetCurrentClamp() == -1) && (!mUseEffect)) err = CreateDecompSeqForGWorldData( gWorld, SetMungDataDrawSeq(drawSeq); // decompress data to our offscreen gworld BailErr(DecompressSequenceFrameS(mDecomSeq,p,len,0,&ignore,nil)); // image is now in the GWorld - manipulate it at will! //if ((mUseOverlay) || (GetCurrentClamp() != -1) || (mUseEffect)) // use our custom decompressor to "decompress" the data // to the screen with overlays or color clamping // BlitOneMungData(myMungData); // we are doing a motion detect grab, so // search for lobsters in our image data //RemoveEventLoopTimer(mSGTimerRef); // DisposeEventLoopTimerUPP(mSGTimerUPP); DoCloseSG(mSeqGrab, mSGChanVideo, mMyDataProcPtr); float Y_dev,E_mean,E_dev,S_mean,S_dev; extern colorBuf[480][640]; extern unsigned int (*colorBuf)[644]; extern struct input_instance input_data; static void DetectLobster(GWorldPtr mungDataOffscreen) PixMapHandle pix = GetGWorldPixMap(mungDataOffscreen); int minX = 10000, maxX = -10000; int minY = 10000, maxY = -10000; //fprintf(stderr, "Starting to find some lobsters...\n"); GetPortBounds(mungDataOffscreen, &bounds); OffsetRect(&bounds, -bounds.left, -bounds.top); colorBuf = GetPixBaseAddr(pix); switch (detection_mode) { //drawbox(CALIB_TOP, CALIB_BOTTOM, CALIB_LEFT, CALIB_RIGHT); SkinStats(pix, y_click-CALIB_RADIUS, y_click+CALIB_RADIUS, x_click-CALIB_RADIUS, x_click+CALIB_RADIUS); scan_region_left=x_click-CALIB_RADIUS;//10; scan_region_right=x_click+CALIB_RADIUS;//630; scan_region_top=y_click-CALIB_RADIUS;//10; scan_region_bottom=y_click+CALIB_RADIUS;//470; detection_mode=SCAN_MODE; //fprintf(stderr, "scan left: %d scan right: %d \n",scan_region_left,scan_region_right); drawbox(face_top, face_bottom, face_left, face_right,1); //drawbox(scan_region_top, scan_region_bottom, scan_region_left, scan_region_right); drawbox((left_eye_y-5),(left_eye_y+5),(left_eye_x-5),(left_eye_x+5),0); drawbox((right_eye_y-5),(right_eye_y+5),(right_eye_x-5),(right_eye_x+5),0); int face_scale=instance->face.head_size; int mouth_width=face_scale; int mouth_height=face_scale; // 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)); filter(&instance->face, bank); //fprintf(stderr, "Lobsters found...\n"); void ScanSkin(PixMapHandle p) 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; 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; double min_lum_mouth=766; double min_lum_right=766; memset(horz_count,0,480*sizeof(int)); memset(vert_count,0,640*sizeof(int)); if (eye_search_frame_count<NUM_FRAMES_EYE_SEARCH) eye_search_frame_count++; else if (eye_search_frame_count==NUM_FRAMES_EYE_SEARCH && bozo_bit==0) //fprintf(stderr, "GOOD You flipped the bozo bit (to good)\n"); for (y = scan_region_top; y < scan_region_bottom; y++) // change this to only calculate in bounding box baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x = scan_region_left; x < scan_region_right; x++) R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; if (y>left_eye_top && y<left_eye_bottom) if (x > left_eye_left && x<left_eye_right) //colorBuf[y][x]=0x0000FF00; if (y>right_eye_top && y<right_eye_bottom) if (x > right_eye_left && x < right_eye_right) //colorBuf[y][x]=0x0000FF00; if (horz_count[y]>max_horz) max_horz=horz_count[y]; if (vert_count[x]>max_vert) max_vert=vert_count[x]; //colorBuf[y][x]=0x00FF0000; left_eye_x=left_eye_x_sum/left_eye_pt_count; left_eye_y=left_eye_y_sum/left_eye_pt_count; right_eye_x=right_eye_x_sum/right_eye_pt_count; right_eye_y=right_eye_y_sum/right_eye_pt_count; int width=right_eye_x-left_eye_x; int height=right_eye_y-left_eye_y; if (width!=0) face_ang=atan((double)height/width); face_ang=face_ang*180/pi; //fprintf(stderr,"face angle: %f \n",face_ang); if ((left_eye_pt_count<5 || right_eye_pt_count<5 || width==0 || face_ang > 30 || face_ang < -30 || left_eye_y < (face_top+.15*(face_bottom-face_top)) || right_eye_y < (face_top+.15*(face_bottom-face_top))) left_eye_x=old_left_eye_x; left_eye_y=old_left_eye_y; right_eye_x=old_right_eye_x; right_eye_y=old_right_eye_y; old_left_eye_x=left_eye_x; old_left_eye_y=left_eye_y; old_right_eye_x=right_eye_x; old_right_eye_y=right_eye_y; if (eye_unconfidence==EYE_UNCONFIDENCE_LIMIT){ eye_search_frame_count=0; //fprintf(stderr, "Recalibrating eyes\n"); if ((last_eye_count_left-left_eye_pt_count> BLINK_THRESHOLD) && eye_unconfidence==0) left_eye_blink_count=BLINK_LENGTH; if (left_eye_blink_count>0){ instance->face.left_eye_open=0; else instance->face.left_eye_open=1; if ((last_eye_count_right-right_eye_pt_count> BLINK_THRESHOLD) && eye_unconfidence==0) right_eye_blink_count=BLINK_LENGTH; if (right_eye_blink_count>0){ instance->face.right_eye_open=0; else instance->face.right_eye_open=1; if (instance->face.right_eye_open==0) instance->face.left_eye_open=0; if (instance->face.left_eye_open==0) instance->face.right_eye_open=0; last_eye_count_left=left_eye_pt_count; last_eye_count_right=right_eye_pt_count; if (width!=0) x_shift= (float)height/(float)width; // --> note dependence on earlier data here int mouth_search_start_y=face_top+(.6*(face_bottom-face_top)); int mouth_search_end_y=face_bottom; 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))) ; for (y=mouth_search_start_y; y < mouth_search_end_y; y++) x=mouth_search_start_x+((y - mouth_search_start_y)*(-x_shift)); baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); //colorBuf[y][x] = 0x0000FF00; R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; mouth_size=(face_right-face_left)*100/640; mouth_left=mouth_ctr_x-mouth_size; if (mouth_left < face_left) mouth_left=face_left; mouth_right=mouth_ctr_x+mouth_size; if (mouth_right > face_right) mouth_right=face_right; mouth_top=mouth_ctr_y-mouth_size; if (mouth_top < face_top) mouth_top=face_top; mouth_bottom=mouth_ctr_y+mouth_size; if (mouth_bottom > face_bottom) mouth_bottom=face_bottom; for (y=mouth_top; y< mouth_bottom; y++){ baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=mouth_left; x< mouth_right; x++){ R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; if ((abs(R-G) < WHITE_THRESH) && (abs(G-B) < WHITE_THRESH) && (abs(R-B) < WHITE_THRESH)) //colorBuf[y][x]=0x0000FF00; // This next section finds the face region and sets the face_* parameters. //fprintf(stderr,"threshold value: %d boxtop value: %d \n", (max_horz), horz_count[scan_region_top]); if (vert_count[scan]>=(thresh*max_vert)) scan=scan_region_right-1; if (vert_count[scan]>=(thresh*max_vert)) if (horz_count[scan]>=(thresh*max_horz)) scan=scan_region_bottom-1; if (horz_count[scan]>=(thresh*max_horz)) // Base scan region on face region here scan_region_left=face_left-10; if (scan_region_left <= 0) scan_region_left=1; scan_region_right=face_right+10; if (scan_region_right >= 640) scan_region_right=639; scan_region_top=face_top-10; if (scan_region_top <= 0) scan_region_top=1; scan_region_bottom=face_bottom+10; if (scan_region_bottom >= 480) scan_region_bottom=479; width=face_right-face_left; guint8 temp=width*100/640; instance->face.head_size=temp; temp=((double)100/(double)640)*(double)(face_right+face_left)/2; temp=((double)100/(double)480)*(double)(face_top+face_bottom)/2; instance->face.head_z_rot=face_ang+50; int center=(face_right+face_left)/2; int right_eye_strad=right_eye_x-center; int left_eye_strad=center-left_eye_x; if (right_eye_strad > left_eye_strad) y_ang= (double)right_eye_strad/(double)left_eye_strad; else y_ang=(double)left_eye_strad/(double)right_eye_strad; if (y_ang >= 10) y_ang=30; if (right_eye_strad > left_eye_strad) y_ang=-y_ang; temp = (guint8) 50 + y_ang; instance->face.head_y_rot=temp; if (abs (temp-50) > 15) instance->face.head_size=head_size_old; else head_size_old=instance->face.head_size; temp = (guint8) 100 * white_count / WHITE_COUNT_MAX; if (temp > 100) temp=100; instance->face.mouth_open = temp; // draw bounding box for either calibration or face void SetEyeSearchRegions(void) left_eye_top=face_top+(.25*(face_bottom-face_top)); left_eye_bottom=face_top+(.6*(face_bottom-face_top)); left_eye_right=((face_left+face_right)/2); left_eye_left=face_left+.15*(face_right-face_left); right_eye_top=face_top+(.25*(face_bottom-face_top)); right_eye_bottom=face_top+(.6*(face_bottom-face_top)); right_eye_right=face_right-.15*(face_right-face_left); right_eye_left=((face_left+face_right)/2); left_eye_top=left_eye_y-20; left_eye_bottom=left_eye_y+20; left_eye_left=left_eye_x-20; left_eye_right=left_eye_x+20; right_eye_top=right_eye_y-20; right_eye_bottom=right_eye_y+20; right_eye_left=right_eye_x-20; right_eye_right=right_eye_x+20; void drawbox(int top, int bottom, int left, int right, int color) if (bottom>=480) bottom=479; if (right>=640) right=639; for (y=top; y<bottom; y++) colorBuf[y][left+j] = col; colorBuf[y][right-j] = col; for (x=left; x<right; x++) colorBuf[bottom-j][x] = col; colorBuf[top+j][x] = col; for (y=top; y<bottom; y++) for (x=left;x<right;x++){ void SkinStats (PixMapHandle p, int top, int bottom, int left, int right) double Y_sum,E_sum,S_sum; for (y=top; y<bottom; y++) baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=left; x<right; x++) R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; for (y=top; y<bottom; y++) baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=left; x<right; x++) R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; Y_sum+=(Y-Y_mean)*(Y-Y_mean); E_sum+=(E-E_mean)*(E-E_mean); S_sum+=(S-S_mean)*(S-S_mean); Y_dev=sqrt(Y_sum/(count-1)); E_dev=sqrt(E_sum/(count-1)); S_dev=sqrt(S_sum/(count-1)); //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); int SkinDetect(double Y, double E, double S) if (E>(E_mean-(2*E_dev)) && E<(E_mean+(2*E_dev))) return 1;