Mercurial > pidgin.yaz
view plugins/crazychat/camproc.c @ 11977:0ea9a52fd333
[gaim-migrate @ 14270]
"Clean up on idle 7!"
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Fri, 04 Nov 2005 23:16:44 +0000 |
parents | ed017b9c532d |
children |
line wrap: on
line source
/* * camproc.c * basecame * * Created by CS194 on Mon Apr 26 2004. * Copyright (c) 2004 __MyCompanyName__. All rights reserved. * */ #include "camdata.h" #include "Utilities.h" #include "QTUtilities.h" #include "stdio.h" #include "math.h" #include <gtk/gtk.h> #include "cc_interface.h" #include "filter.h" extern int detection_mode; extern mungDataPtr myMungData; extern int x_click; extern int y_click; #define kMinimumIdleDurationInMillis kEventDurationMillisecond #define BailErr(x) {if (x != noErr) goto bail;} #define PRE_CALIBRATE_MODE 0 #define CALIBRATE_MODE 1 #define SCAN_MODE 2 #define CALIB_TOP 190 #define CALIB_BOTTOM 200 #define CALIB_LEFT 200 #define CALIB_RIGHT 210 #define CALIB_RADIUS 5 #define NUM_FRAMES_EYE_SEARCH 50 #define EYE_UNCONFIDENCE_LIMIT 7 #define BLINK_THRESHOLD 75 #define BLINK_LENGTH 10 #define WHITE_THRESH 25 #define WHITE_COUNT_MAX 200 struct input_instance* instance; int scan_region_left; int scan_region_right; int scan_region_top; int scan_region_bottom; int lum_thresh=150; int face_left; int face_right; int face_top; int face_bottom; int old_left_eye_x=50; int old_left_eye_y=50; int old_right_eye_x=50; int old_right_eye_y=50; int left_eye_x; int left_eye_y; int right_eye_x; int right_eye_y; int eye_search_frame_count=0; int bozo_bit=0; int eye_unconfidence=0; int last_eye_count_left=0; int last_eye_count_right=0; int mouth_ctr_x; int mouth_ctr_y; int mouth_size, mouth_left, mouth_right, mouth_top, mouth_bottom; int white_count; guint8 head_size_old; 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; filter_bank *bank; 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; color saved_best=-1; int filenum=0; OSErr CamProc(struct input_instance *inst, filter_bank *f) { OSStatus error; OSErr err = noErr; BailErr(err = InitializeMungData(mMungRect)); bank = f; instance=inst; mMyDataProcPtr = NewSGDataUPP(MiniMungDataProc); mSeqGrab = OpenDefaultComponent(SeqGrabComponentType, 0); BailErr((err = CreateNewSGChannelForRecording( mSeqGrab, mMyDataProcPtr, GetMungDataOffscreen(), // drawing destination &mMungRect, &mSGChanVideo, NULL))); bail: return err; } void QueryCam (void) { SGIdle(mSeqGrab); } static pascal void SGIdlingTimer(EventLoopTimerRef inTimer, void *inUserData) { #pragma unused(inUserData) if (mSeqGrab) { SGIdle(mSeqGrab); } // 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; CodecFlags ignore; GWorldPtr gWorld; if (!myMungData) goto bail; gWorld = GetMungDataOffscreen(); if(gWorld) { if (mDecomSeq == 0) // init a decompression sequence { Rect bounds; GetMungDataBoundsRect(&bounds); BailErr( CreateDecompSeqForSGChannelData(c, &bounds, gWorld, &mDecomSeq)); if(1) //if ((!mUseOverlay) && (GetCurrentClamp() == -1) && (!mUseEffect)) { ImageSequence drawSeq; err = CreateDecompSeqForGWorldData( gWorld, &bounds, nil, GetMungDataWindowPort(), &drawSeq); 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); //} //else //{ // we are doing a motion detect grab, so // search for lobsters in our image data DetectLobster(gWorld); //} } bail: return err; } void Die() { //RemoveEventLoopTimer(mSGTimerRef); // mSGTimerRef = nil; // DisposeEventLoopTimerUPP(mSGTimerUPP); DoCloseSG(mSeqGrab, mSGChanVideo, mMyDataProcPtr); } float Y_mean=-1; 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) { CGrafPtr oldPort; GDHandle oldDevice; int x, y; Rect bounds; PixMapHandle pix = GetGWorldPixMap(mungDataOffscreen); UInt32 * baseAddr; UInt32 reds = 0; Str255 tempString; int minX = 10000, maxX = -10000; int minY = 10000, maxY = -10000; Rect tempRect; float percent; OSErr err; CodecFlags ignore; color best; long R_total=0; long G_total=0; long B_total=0; //fprintf(stderr, "Starting to find some lobsters...\n"); GetPortBounds(mungDataOffscreen, &bounds); OffsetRect(&bounds, -bounds.left, -bounds.top); UInt32 color; int sum_x,sum_y=0; int count=0; int k,j; long R; long G; long B; int search_width=200; int search_height=200; colorBuf = GetPixBaseAddr(pix); switch (detection_mode) { case PRE_CALIBRATE_MODE: //drawbox(CALIB_TOP, CALIB_BOTTOM, CALIB_LEFT, CALIB_RIGHT); break; case CALIBRATE_MODE: 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; ScanSkin(pix); detection_mode=SCAN_MODE; //fprintf(stderr, "scan left: %d scan right: %d \n",scan_region_left,scan_region_right); head_size_old=50; break; case SCAN_MODE: ScanSkin(pix); 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); break; } //fprintf(stderr, "Lobsters found...\n"); } void ScanSkin(PixMapHandle p) { int y,x,j,k; 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; long R,G,B,sum_x,sum_y; int count; double Y,E,S,lum; double min_lum_mouth=766; double min_lum_left=766; double min_lum_right=766; UInt32 color; UInt32 * baseAddr; int max_horz=0; int max_vert=0; sum_x=sum_y=count=0; int horz_count[480]; int vert_count[640]; 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) { bozo_bit=1; //fprintf(stderr, "GOOD You flipped the bozo bit (to good)\n"); } SetEyeSearchRegions(); 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++) { color=baseAddr[x]; R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; Y=.253*R+.684*G+.063*B; E=.5*R-.5*G; S=.25*R+.25*G-.5*B; lum=R+G+B; if (y>left_eye_top && y<left_eye_bottom) { if (x > left_eye_left && x<left_eye_right) { if (lum < lum_thresh) { left_eye_x_sum+=x; left_eye_y_sum+=y; left_eye_pt_count++; //colorBuf[y][x]=0x0000FF00; } } } if (y>right_eye_top && y<right_eye_bottom) { if (x > right_eye_left && x < right_eye_right) { if (lum < lum_thresh) { right_eye_x_sum+=x; right_eye_y_sum+=y; right_eye_pt_count++; //colorBuf[y][x]=0x0000FF00; } } } if(SkinDetect(Y,E,S)) { sum_x+=x; sum_y+=y; count++; ++horz_count[y]; ++vert_count[x]; 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; double face_ang; if (width!=0) face_ang=atan((double)height/width); else face_ang=0; 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))) && bozo_bit==1){ eye_unconfidence++; 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; } else { eye_unconfidence=0; 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){ bozo_bit=0; 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; left_eye_blink_count--; } 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; right_eye_blink_count--; } 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; float x_shift=0; if (width!=0) x_shift= (float)height/(float)width; // --> note dependence on earlier data here if (bozo_bit==1){ 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; color=baseAddr[x]; R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; lum=R+G+B; if (lum<min_lum_mouth) { min_lum_mouth=lum; mouth_ctr_x=x; mouth_ctr_y=y; } } 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; white_count=0; for (y=mouth_top; y< mouth_bottom; y++){ baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=mouth_left; x< mouth_right; x++){ color=baseAddr[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)) { white_count++; //colorBuf[y][x]=0x0000FF00; } } } } else white_count=10; // This next section finds the face region and sets the face_* parameters. int scan; float thresh=.3; scan=scan_region_left+1; if (scan<0) scan=0; //fprintf(stderr,"threshold value: %d boxtop value: %d \n", (max_horz), horz_count[scan_region_top]); while(1) { if (vert_count[scan]>=(thresh*max_vert)) { face_left=scan; break; } scan++; } scan=scan_region_right-1; if (scan>=640) scan=639; while(1) { if (vert_count[scan]>=(thresh*max_vert)) { face_right=scan; break; } scan--; } scan=scan_region_top+1; if (scan<0) scan=0; while(1) { if (horz_count[scan]>=(thresh*max_horz)) { face_top=scan; break; } scan++; } scan=scan_region_bottom-1; if (scan>=480) scan=479; while(1) { if (horz_count[scan]>=(thresh*max_horz)) { face_bottom=scan; break; } scan--; } // 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; // Calculate some stats // face size width=face_right-face_left; guint8 temp=width*100/640; instance->face.head_size=temp; // face location temp=((double)100/(double)640)*(double)(face_right+face_left)/2; instance->face.x=temp; temp=((double)100/(double)480)*(double)(face_top+face_bottom)/2; instance->face.y=temp; // face angle-Z instance->face.head_z_rot=face_ang+50; // face angle-Y int center=(face_right+face_left)/2; int right_eye_strad=right_eye_x-center; int left_eye_strad=center-left_eye_x; double y_ang; 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; y_ang=y_ang*5; if (y_ang >= 10) y_ang=30; if (y_ang <= 1) y_ang=1; 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) { if (bozo_bit==0) { 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); } if (bozo_bit==1) { 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) { int y, x, j; unsigned int col; if (color==1) col=0x00FFFF00; else col=0x00FF00FF; if (top<0) top =0; if (top>=480) top=479; if (bottom<0) bottom =0; if (bottom>=480) bottom=479; if (left<0) left =0; if (left>=640) left=639; if (right<0) right =0; if (right>=640) right=639; if (color==1){ for (y=top; y<bottom; y++) { for (j=0;j<5;j++){ colorBuf[y][left+j] = col; colorBuf[y][right-j] = col; } } for (x=left; x<right; x++) { for (j=0;j<5;j++){ colorBuf[bottom-j][x] = col; colorBuf[top+j][x] = col; } } } else { for (y=top; y<bottom; y++) { for (x=left;x<right;x++){ colorBuf[y][x] = col; colorBuf[y][x] = col; } } } } void SkinStats (PixMapHandle p, int top, int bottom, int left, int right) { double Y_sum,E_sum,S_sum; int R,G,B; int count=0; Y_sum=E_sum=S_sum=0; double Y,E,S; UInt32 color; int x, y; UInt32 * baseAddr; for (y=top; y<bottom; y++) { baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=left; x<right; x++) { count++; color=baseAddr[x]; R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; Y=.253*R+.684*G+.063*B; E=.5*R-.5*G; S=.25*R+.25*G-.5*B; Y_sum+=Y; E_sum+=E; S_sum+=S; } } Y_mean=Y_sum/count; E_mean=E_sum/count; S_mean=S_sum/count; Y_sum=E_sum=S_sum=0; for (y=top; y<bottom; y++) { baseAddr = (UInt32*)(GetPixBaseAddr(p) + y * GetPixRowBytes(p)); for (x=left; x<right; x++) { color=baseAddr[x]; R = (color & 0x00FF0000) >> 16; G = (color & 0x0000FF00) >> 8; B = (color & 0x000000FF) >> 0; Y=.253*R+.684*G+.063*B; E=.5*R-.5*G; S=.25*R+.25*G-.5*B; 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; else return 0; }