diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/crazychat/camproc.c	Tue Aug 09 07:10:23 2005 +0000
@@ -0,0 +1,812 @@
+/*
+ *  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;
+}
+