view plugins/crazychat/camproc.c @ 12278:25d7ef365dbf

[gaim-migrate @ 14582] sf patch #1370473, from Sadrul Habib Chowdhury "This patch fixes the idle time tracking for systems that don't use xscreensaver." Seems like it would just get rid of some warnings? But whatever, definitely an improvement committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 01 Dec 2005 01:01:26 +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;
}