#from .imgproc import *
import gentimedist as gen
import cv2, time, sys, cPickle, zmq, os, copy, psutil, io
from math import log
from IPython.parallel import Client
from scipy import stats
import numpy as np
from picamera import PiCamera
from picamera.array import PiRGBArray

os.chdir("/home/pi")

def picamtrigger(profile='picluster',threshold=15,n=100,serial='no',show=False,width=720,height=480,scale=1.1,cascade="haarcascade_frontalface_alt2.xml"):
	import sys, cPickle, os,cv2,time,math,signal
	pidfile=open('mypythonpid','w')
	cPickle.dump(os.getpid(),pidfile)
	pidfile.close()
	runstate=open('runstate','w')
	cPickle.dump(0,runstate)
	runstate.close()
	print os.getpid()

	c=Client(profile=profile)
	dview=c[:]
	numnodes=len(c.ids)
	dview.block=False
	def getmypid():
		import cPickle, os
		try:
			file=open('mypythonpid','r')
			mypid=cPickle.load(file)
			file.close()
			try:
				os.kill(mypid,0)
			except:
				mypid=False
		except:
			mypid=False
		return mypid
	def getrunstate():
		import cPickle
		try:
			file=open('runstate','r')
			state=cPickle.load(file)
			file.close()
		except:
			state=0
		return state
	dview["getrunstate"]=getrunstate
	dview["getmypid"]=getmypid
	dview.execute("mypid=getmypid()")
	myippid=-1
	for proc in psutil.process_iter():
		if proc.name()=='ipengine':
			myippid=proc.pid
	ippids=[]
	dview.execute("import os;enginepid=os.getpid()")
	for i in range(numnodes):
		if not myippid==c[c.ids[i]]['enginepid']:
			ippids.append(c.ids[i])
	dview=c.activate(ippids)
	dview.execute('import cv2,sys,time,math,cPickle,signal')
	
	print dview
	numnodes=len(dview)
	rejects=len(c.ids)-numnodes
	print "configured for this pi by rejecting a certain engine"
	#print sys.platform
	if sys.platform=='darwin':
		facedetector=cv2.CascadeClassifier("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/haarcascades/"+cascade)
	elif sys.platform=='linux2':
		facedetector=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/"+cascade)
	else: 
		print "something went wrong detecting the system"

	stream=io.BytesIO()	
	with PiCamera() as cam:
		cam.resolution=(width,height)
		cam.start_preview()
		time.sleep(2)
		cam.capture(stream,"rgb")
		cam.stop_preview()
	stream.seek(0)
	fwidth = (width + 31) // 32 * 32
	fheight = (height + 15) // 16 * 16
	img=np.fromstring(stream.getvalue(), dtype=np.uint8).reshape((fheight, fwidth, 3))[:height, :width, :]
	print "got first image"
	print "generating time distribution for image"
	gen.dumptimes(img,scale=scale)
	times=gen.loadtimes()

	#scale=1.1
	dview["scale"]=scale
	for i in ippids:
		c[i].execute('if sys.platform=="darwin": haarface=cv2.CascadeClassifier("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml")')
		c[i].execute('if sys.platform=="linux2": haarface=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")')
	
	numsizes=len(times)
	trans=[None]*numsizes
	for i in range(numsizes):
		trans[i]=int(20*(scale**i))
	
	mintime=min(times)
	times=[thistime-mintime for thistime in times]

	print "predicting even distribution..."
	def predictdist(numnodes,times,numsizes,c):
		timepernode=sum(times)/numnodes
		thresholds=[None]*(numnodes+1)
		thresholds[0]=0
		for i in range(1,numnodes+1):
			j=thresholds[i-1]+1
			while sum(times[thresholds[i-1]:j])<timepernode and j<numsizes:
				j=j+1
				#print j
				#time.sleep(3)
			if sum(times[thresholds[i-1]:j])-timepernode>timepernode-sum(times[thresholds[i-1]:j-1]):
				j=j-1 #makes more even, but last few take longest...otherwise even but last is really short
			thresholds[i]=j
		thresholds[numnodes]=numsizes-1
		for i in range(numnodes):
			c[ippids[i]]['thismin']=tuple([trans[thresholds[i]]-1]*2)
			c[ippids[i]]['thismax']=tuple([trans[thresholds[i+1]]+1]*2)
	predictdist(numnodes,times,numsizes,c)
	
	def findfaces(img,scale,serial):
		starttime=time.time()
		numnodes=len(ippids)
		img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
		dview['img']=img
		dview.execute('img=img.copy();mypid=getmypid()')
		#dview.execute("mypid=getmypid()")
		runstate=open('runstate','w')
		cPickle.dump(1,runstate)
		runstate.close()
		dview.execute("state=getrunstate()") #may be redundant but avoids a lock
		#for i in range(numnodes):
		#	print c[c.ids[i]]["state"]
		dview.execute("if mypid and not state: os.kill(mypid,signal.SIGTSTP)")
		dview.execute("exectime=time.time();myfaces=haarface.detectMultiScale(img,scale,4,1,thismin,thismax);exectime=time.time()-exectime;endtime=time.time()",block=False)
		faces=set()
		thistimes=[None]*numnodes
		thistimesremote=[None]*numnodes
		for i in range(numnodes):
			thistimes[i]=time.time()
			print "checking engine "+str(ippids[i])
			thisfaces=c[ippids[i]]["myfaces"]
			thistimesremote[i]=c[ippids[i]]["exectime"]
			print len(thisfaces)
			if len(thisfaces)>0:
				for face in thisfaces:
					faces.add(tuple(face))
			thistimes[i]=time.time()-thistimes[i]
		print thistimes
		print thistimesremote

		duptime=time.time()
		facelist=list(faces)
		donttest=[]
		finallist=[]
		testlen=len(facelist)
		origlist=facelist
		testlennew=0
		print "faces found: "
		print len(origlist)
		while not testlennew==testlen:
			testlen=len(facelist)
			for first in range(len(facelist)):
				if first not in donttest:
					for second in range(first+1,len(facelist)):
						sub=facelist[first]
						j=facelist[second]
						var=abs(j[3]-sub[3])/2
						if ((j[0]+j[3]/2-var<sub[0]+sub[3]/2) and (j[0]+j[3]/2+var>sub[0]+sub[3]/2)) and ((j[1]+j[2]/2-var<sub[1]+sub[2]/2) and (j[1]+j[2]/2+var>sub[1]+sub[2]/2)) and min([float(j[3])/sub[3],float(sub[3])/j[3]])>1.0/2.0:
							donttest.append(first)
							donttest.append(second)
							#facelist.append(tuple([(j[0]+sub[0])/2,(j[1]+sub[1])/2,(j[2]+sub[2])/2,(j[3]+sub[3])/2]))
							inter=tuple([(j[0]+sub[0])/2,(j[1]+sub[1])/2,(j[2]+sub[2])/2,(j[3]+sub[3])/2])
							finallist.append(inter)
							break
					if first not in donttest:
						finallist.append(facelist[first])
			testlennew=len(finallist)
			facelist=finallist
			finallist=[]
			donttest=[]
		finallist=facelist
		duptime=time.time()-duptime
		print "faces found after removing likely duplicates: "
		print len(finallist)
		starttime=time.time()-starttime
		print "min/avg/max/regtime/tottime: "+str(min(thistimesremote))+"/"+str(sum(thistimesremote)/numnodes)+"/"+str(max(thistimesremote))+"/"+str(starttime)+"/"+str(sum(thistimesremote))

		if serial=='yes':
			serialtime=time.time()
			facedetector.detectMultiScale(img,scale,4,1)
			serialtime=time.time()-serialtime
			print serialtime
		
		dview.execute("if mypid: os.kill(mypid,signal.SIGCONT)")
		#for i in range(numnodes):
		#	print c[c.ids[i]]['mypid']
		runstate=open('runstate','w')
		cPickle.dump(0,runstate)
		runstate.close()
		return finallist
		
	def stdtrigger(img,framenum=1,threshold=threshold,message=False):
		try:
			global avg
			global std
			global xstart
			xstart=width/4
			global ystart
			ystart=height/4
			global sumlist
		except:
			sys.exit("error getting globals in stdtrigger")
		if message:
			if message=="update":
				sumlist[0]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
                                std=stats.tstd(sumlist)
                                avg=sum(sumlist)/n
				return
			sumlist=[None]*n
			def calibcam(n,sumlist):
				stream=io.BytesIO()
				for i in range(n):
					yield stream
					stream.seek(0)
					fwidth = (width + 31) // 32 * 32
				        fheight = (height + 15) // 16 * 16
					#starttime=time.time()
					img=np.fromstring(stream.getvalue(), dtype=np.uint8).reshape((fheight, fwidth, 3))[:height, :width, :]
					#print str((time.time()-starttime)*1000)+" ms for reading the image"
					#xstart=img.shape[0]/4
					#ystart=img.shape[1]/4
					#starttime=time.time()
					sumlist[i]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
					#print str((time.time()-starttime)*1000)+" ms"
					stream.seek(0)
					stream.truncate()
					sys.stdout.write("\r"+str(float(i+1)*100/n)+"%        ")
					sys.stdout.flush()
	
			print "calibrating stdtrigger"
			with PiCamera() as cam:
				cam.resolution=(width,height)
				cam.framerate=80
				time.sleep(.3)
				cam.capture_sequence(calibcam(n,sumlist),"rgb",use_video_port=True)
			std=stats.tstd(sumlist)
			avg=sum(sumlist)/n
			return
		thisz=(img[xstart:(xstart*3),ystart:(ystart*3),:].sum()-avg)/std
		#print thisz
		if abs(thisz)>threshold:
			print "\nsomething weird, zscore="+str(thisz)+" at "+time.strftime("%a, %d %b %H:%M:%S", time.localtime())
			return True

                if framenum%10==0:
                        sumlist[0]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
                        std=stats.tstd(sumlist)
                        avg=sum(sumlist)/n

		return False
	
	framenum=0
	oldids=ippids
	
	print "calibrating chosen trigger..."

	stdtrigger(None,message="init")

	print "\nstarting detection"
	
	with PiCamera() as cam:
		cam.resolution=(width,height)
		cam.framerate=80
		time.sleep(.3)
		print "creating stream"
		stream=io.BytesIO()
		print "created stream, entering loop"
		imgstarttime=time.time()
		for foo in cam.capture_continuous(stream,"rgb",use_video_port=True):
			#print str((time.time()-imgstarttime)*1000)+" ms to get image"
			imgtotaltime=(time.time()-imgstarttime)*1000
			loopstarttime=time.time()
			stream.seek(0)
			fwidth = (width + 31) // 32 * 32
			fheight = (height + 15) // 16 * 16
			#print "getting image"
			img = np.fromstring(stream.getvalue(), dtype=np.uint8).reshape((fheight, fwidth, 3))[:height, :width, :]
			#print "got the image, analyzing it"
			if stdtrigger(img,framenum,threshold):
				print "searching for faces..."
				newimg=img.copy()
				faces=findfaces(newimg,scale,serial)
				if len(faces)>0:
					print "FOUND A FACEZ!!!!!11!"
					if show==True:
						for (x,y,h,w) in faces:
							cv2.rectangle(newimg,(x,y),(x+w,y+h),(0,255,255),1)
						cv2.imshow("obj found",newimg)
				else:
					print "no facez :("
					if show==True:
						cv2.imshow("obj not found",newimg)
				if show==True:
					cv2.waitKey(1)
				stdtrigger(img,message="update")
			framenum=framenum+1
			
			if framenum%(10*numnodes)==0:
				if not len(c.ids)-len(oldids)==rejects:
					print "cluster changed"
					numnodes=len(oldids)
					dview=c[:]
					print "repredicting even distribution..."
					for id in c.ids:
						if id not in oldids:
							c[id].execute('import cv2,sys,time,math,os,cPickle,signal;myfaces=[]')
							c[id]['getrunstate']=getrunstate
							c[id]['getmypid']=getmypid
							c[id]['scale']=scale
							c[id].execute('haarface=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")')
						#else:
						#	c[id].execute('myfaces=[]')
					#oldids=c.ids
					#c.spin()
					#trying reseting the client
					c=Client(profile=profile)
					dview=c[:]
					myippid=-1
					for proc in psutil.process_iter():
						if proc.name()=='ipengine':
							myippid=proc.pid
					ippids=[]
					dview.execute("import os;enginepid=os.getpid()")
					for i in range(len(c.ids)):
						if not myippid==c[c.ids[i]]['enginepid']:
							ippids.append(c.ids[i])
					dview=c.activate(ippids)
					numnodes=len(ippids)
					oldids=ippids
					rejects=len(c.ids)-numnodes
					predictdist(numnodes,times,numsizes,c)
			stream.seek(0)
			stream.truncate(0)
			looptotaltime=(time.time()-loopstarttime)*1000
			detectfreq=round(1000/(looptotaltime+imgtotaltime),2)
			sys.stdout.write("\r"+str(int(looptotaltime))+" ms for detection, "+str(int(imgtotaltime))+" ms for image, running at "+str(detectfreq)+" hz              ")
			sys.stdout.flush()
			imgstarttime=time.time()	

        #with PiCamera() as cam:
         #       cam.resolution=(width,height)
          #      cam.framerate=80
           #     time.sleep(2)
	#	print "got the camera going again, trying to actually run"
	#	cam.capture_sequence(dodetection(),"rgb",use_video_ports=True)
		

def findfaceswithtrigger(profile='picluster',threshold=15,n=100,serial='no',show=False):
	import sys, cPickle, os,cv2,time,math,signal
	pidfile=open('mypythonpid','w')
	cPickle.dump(os.getpid(),pidfile)
	pidfile.close()
	runstate=open('runstate','w')
	cPickle.dump(0,runstate)
	runstate.close()
	print os.getpid()
	#context=zmq.Context()
	#pubsocket=context.socket(zmq.PUB)
	#port=5556
	#pubsocket.bind("tcp://*:%s"%port)
	#subsocket=context.socket(zmq.SUB)
	#if sys.platform=='darwin':
	#	ips=open("/Users/isaac/Code/parastuff/ipaddresses").read()
	#if sys.platform=='linux2':
	#	ips=open("/home/pi/ipaddresses").read()
	#splitips=ips.split("\n")
	#print splitips
	#for ip in splitips:
	#	if ip:
	#		subsocket.connect("tcp://%s:%s"%(ip,port))
	#subsocket.setsockopt(zmq.SUBSCRIBE,"need quiet?")

	c=Client(profile=profile)
	dview=c[:]
	numnodes=len(c.ids)
	dview.block=False
	#dview.execute('import cv2,sys,time,math,os,cPickle,signal')
	#dview.execute("mypid=os.getpid()")
	def getmypid():
		import cPickle, os
		try:
			file=open('mypythonpid','r')
			mypid=cPickle.load(file)
			file.close()
			try:
				os.kill(mypid,0)
			except:
				mypid=False
		except:
			mypid=False
		return mypid
	def getrunstate():
		import cPickle
		try:
			file=open('runstate','r')
			state=cPickle.load(file)
			file.close()
		except:
			state=0
		return state
	dview["getrunstate"]=getrunstate
	dview["getmypid"]=getmypid
	dview.execute("mypid=getmypid()")
	myippid=-1
	for proc in psutil.process_iter():
		if proc.name()=='ipengine':
			myippid=proc.pid
	ippids=[]
	dview.execute("import os;enginepid=os.getpid()")
	for i in range(numnodes):
		if not myippid==c[c.ids[i]]['enginepid']:
			ippids.append(c.ids[i])
	dview=c.activate(ippids)
	dview.execute('import cv2,sys,time,math,cPickle,signal')
	
	print dview
	numnodes=len(dview)
	rejects=len(c.ids)-numnodes
	print "configured for this pi by rejecting a certain engine"
	print sys.platform
	if sys.platform=='darwin':
		facedetector=cv2.CascadeClassifier("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml")
	elif sys.platform=='linux2':
		facedetector=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")
	else: 
		print "something went wrong detecting the system"
	
	cam=cv2.VideoCapture(0)
	
	retval,img=cam.read()
	gen.dumptimes(img,scale=1.1)
	times=gen.loadtimes()

	scale=1.1
	dview["scale"]=scale
	for i in ippids:
		c[i].execute('if sys.platform=="darwin": haarface=cv2.CascadeClassifier("/usr/local/Cellar/opencv/2.4.9/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml")')
		c[i].execute('if sys.platform=="linux2": haarface=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")')
	
	numsizes=len(times)
	trans=[None]*numsizes
	for i in range(numsizes):
		trans[i]=int(20*(scale**i))
	
	mintime=min(times)
	times=[thistime-mintime for thistime in times]

	print "predicting even distribution..."
	def predictdist(numnodes,times,numsizes,c):
		timepernode=sum(times)/numnodes
		thresholds=[None]*(numnodes+1)
		thresholds[0]=0
		for i in range(1,numnodes+1):
			j=thresholds[i-1]+1
			while sum(times[thresholds[i-1]:j])<timepernode and j<numsizes:
				j=j+1
				#print j
				#time.sleep(3)
			if sum(times[thresholds[i-1]:j])-timepernode>timepernode-sum(times[thresholds[i-1]:j-1]):
				j=j-1 #makes more even, but last few take longest...otherwise even but last is really short
			thresholds[i]=j
		thresholds[numnodes]=numsizes-1
		for i in range(numnodes):
			c[ippids[i]]['thismin']=tuple([trans[thresholds[i]]-1]*2)
			c[ippids[i]]['thismax']=tuple([trans[thresholds[i+1]]+1]*2)
	predictdist(numnodes,times,numsizes,c)
	
	def findfaces(img,scale,serial):
		starttime=time.time()
		numnodes=len(ippids)
		img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
		dview['img']=img
		dview.execute('img=img.copy();mypid=getmypid()')
		#dview.execute("mypid=getmypid()")
		runstate=open('runstate','w')
		cPickle.dump(1,runstate)
		runstate.close()
		dview.execute("state=getrunstate()") #may be redundant but avoids a lock
		#for i in range(numnodes):
		#	print c[c.ids[i]]["state"]
		dview.execute("if mypid and not state: os.kill(mypid,signal.SIGTSTP)")
		dview.execute("exectime=time.time();myfaces=haarface.detectMultiScale(img,scale,4,1,thismin,thismax);exectime=time.time()-exectime;endtime=time.time()",block=False)
		faces=set()
		thistimes=[None]*numnodes
		thistimesremote=[None]*numnodes
		for i in range(numnodes):
			thistimes[i]=time.time()
			print "checking engine "+str(ippids[i])
			thisfaces=c[ippids[i]]["myfaces"]
			thistimesremote[i]=c[ippids[i]]["exectime"]
			print len(thisfaces)
			if len(thisfaces)>0:
				for face in thisfaces:
					faces.add(tuple(face))
			thistimes[i]=time.time()-thistimes[i]
		print thistimes
		print thistimesremote

		duptime=time.time()
		facelist=list(faces)
		donttest=[]
		finallist=[]
		testlen=len(facelist)
		origlist=facelist
		testlennew=0
		print len(origlist)
		while not testlennew==testlen:
			testlen=len(facelist)
			for first in range(len(facelist)):
				if first not in donttest:
					for second in range(first+1,len(facelist)):
						sub=facelist[first]
						j=facelist[second]
						var=abs(j[3]-sub[3])/2
						if ((j[0]+j[3]/2-var<sub[0]+sub[3]/2) and (j[0]+j[3]/2+var>sub[0]+sub[3]/2)) and ((j[1]+j[2]/2-var<sub[1]+sub[2]/2) and (j[1]+j[2]/2+var>sub[1]+sub[2]/2)) and min([float(j[3])/sub[3],float(sub[3])/j[3]])>1.0/2.0:
							donttest.append(first)
							donttest.append(second)
							#facelist.append(tuple([(j[0]+sub[0])/2,(j[1]+sub[1])/2,(j[2]+sub[2])/2,(j[3]+sub[3])/2]))
							inter=tuple([(j[0]+sub[0])/2,(j[1]+sub[1])/2,(j[2]+sub[2])/2,(j[3]+sub[3])/2])
							finallist.append(inter)
							break
					if first not in donttest:
						finallist.append(facelist[first])
			testlennew=len(finallist)
			facelist=finallist
			finallist=[]
			donttest=[]
		finallist=facelist
		duptime=time.time()-duptime
		print len(finallist)
		starttime=time.time()-starttime
		print "min/avg/max/regtime/tottime: "+str(min(thistimesremote))+"/"+str(sum(thistimesremote)/numnodes)+"/"+str(max(thistimesremote))+"/"+str(starttime)+"/"+str(sum(thistimesremote))

		if serial=='yes':
			serialtime=time.time()
			facedetector.detectMultiScale(img,scale,4,1)
			serialtime=time.time()-serialtime
			print serialtime
		
		dview.execute("if mypid: os.kill(mypid,signal.SIGCONT)")
		#for i in range(numnodes):
		#	print c[c.ids[i]]['mypid']
		runstate=open('runstate','w')
		cPickle.dump(0,runstate)
		runstate.close()
		return finallist
	
	def calibcam(n,cam):
		sumlist=[None]*n
		for i in range(n):
			retval,img=cam.read()
			xstart=img.shape[0]/4
			ystart=img.shape[1]/4
			sumlist[i]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
		return sumlist
	
	sumlist=calibcam(n,cam)
	std=stats.tstd(sumlist)
	avg=sum(sumlist)/n
	framenum=0
	oldids=ippids
	
	print "starting detection"
	
	while True:
		retval,img=cam.read()
		xstart=img.shape[0]/4
		ystart=img.shape[1]/4
		thisz=(img[xstart:(xstart*3),ystart:(ystart*3),:].sum()-avg)/std
		#while True:
		#	print "testing for sleep needed"
		#	try:
		#		if subsocket.recv(flags=zmq.NOBLOCK)=="need quite? yes":
		#			print "need sleep"
		#			while True:
		#				try:
		#					if subsocket.recv(flags=zmq.NOBLOCK)=="need quite? not anymore":
		#						break
		#				except:
		#					pass
		#				time.sleep(.5)
		#	except:
		#		break
		if abs(thisz)>threshold:
			print "something weird, zscore="+str(thisz)
			time.sleep(.5)
		#	pubsocket.send("need quiet? yes")
			retval,newimg=cam.read() #works well on mac, maybe not pis...
			#if not len(c.ids)==len(oldids): #done periodically, not ideal to update here...
			#	print "cluster changed"
			#	numnodes=len(c.ids)
			#	dview=c[:]
			#	print "repredicting even distribution..."
			#	predictdist(numnodes,times,numsizes,c)
			#	for id in c.ids:
			#		if id not in oldids:
			#			c[id].execute('import cv2,sys,time,math,os,cPickle,signal;myfaces=[]')
			#			c[id]['getrunstate']=getrunstate
			#			c[id]['getmypid']=getmypid
			#			c[id]['scale']=scale
			#			c[id].execute('haarface=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")')
					#else:
					#	c[id].execute('myfaces=[]')
			#	oldids=c.ids
			print "searching for faces..."
			faces=findfaces(newimg,scale,serial)
		#	pubsocket.send("need quiet? not anymore")
			if len(faces)>0:
				print "FOUND A FACEZ!!!!!11!"
				if show==True:
					for (x,y,h,w) in faces:
						cv2.rectangle(newimg,(x,y),(x+w,y+h),(0,255,255),1)
					#cv2.imshow("obj num "+str(i),newimg)
					cv2.imshow("obj found",newimg)
			else:
				print "no facez :("
				if show==True:
					cv2.imshow("obj not found",newimg)
			if show==True:
				cv2.waitKey(1)
			sumlist[0]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
			std=stats.tstd(sumlist)
			avg=sum(sumlist)/n
		#else:
		#	pubsocket.send("need quiet? no")
		framenum=framenum+1
		if framenum%10==0:
			sumlist[0]=img[xstart:(xstart*3),ystart:(ystart*3),:].sum()
			std=stats.tstd(sumlist)
			avg=sum(sumlist)/n
		#if framenum%100==0:
		#	print framenum
		if framenum%(10*numnodes)==0:
			if not len(c.ids)-len(oldids)==rejects:
				print "cluster changed"
				numnodes=len(oldids)
				dview=c[:]
				print "repredicting even distribution..."
				#predictdist(numnodes,times,numsizes,c)
				for id in c.ids:
					if id not in oldids:
						c[id].execute('import cv2,sys,time,math,os,cPickle,signal;myfaces=[]')
						c[id]['getrunstate']=getrunstate
						c[id]['getmypid']=getmypid
						c[id]['scale']=scale
						c[id].execute('haarface=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")')
					#else:
					#	c[id].execute('myfaces=[]')
				#oldids=c.ids
				#c.spin()
				#trying reseting the client
				c=Client(profile=profile)
				dview=c[:]
				myippid=-1
				for proc in psutil.process_iter():
					if proc.name()=='ipengine':
						myippid=proc.pid
				ippids=[]
				dview.execute("import os;enginepid=os.getpid()")
				for i in range(len(c.ids)):
					if not myippid==c[c.ids[i]]['enginepid']:
						ippids.append(c.ids[i])
				dview=c.activate(ippids)
				numnodes=len(ippids)
				oldids=ippids
				rejects=len(c.ids)-numnodes
				predictdist(numnodes,times,numsizes,c)


def getalignface(facefinder,eyefinder,nosefinder,cam):
	cv2.destroyAllWindows()
	print "finding faces..."
	retval,img=cam.read()
	if not retval:
		print "could not read image"
	cv2.imshow("img",img)
	#cv2.imshow("img",img)
	dims=facefinder.detectMultiScale(img,1.02,20,1,(20,20),img.shape[:2]) #for some reason, not consistant. fix
	print dims
	if len(dims)>0:
		sizelist=[w for (x,y,h,w) in dims]
		maxsize=max(sizelist)
		biggestface=[[x,y,h,w] for (x,y,h,w) in dims if w==maxsize and w>60]
		print biggestface
		if len(biggestface)>0:
			print "finding facial features..."
			for (x,y,h,w) in biggestface:
				thisface=img[x:(x+w),y:(y+h),:]
				cleanface=copy.deepcopy(thisface)
			cv2.imshow("thisface",thisface)
			cv2.waitKey(35)
			eyes=eyefinder.detectMultiScale(thisface,1.1,30,1)
			noses=nosefinder.detectMultiScale(thisface,1.1,20,1)
			print "eyes: "+str(eyes)
			print "noses: "+str(noses)
			if len(noses)>0:
                        	maxnosesize=max([w for (x,y,h,w) in noses])
                        	biggestnose=[[x,y,h,w] for (x,y,h,w) in noses if w==maxnosesize][0]
			if len(noses)>0 and len(eyes)>1:
				finaleyes=[]
				print "filtering out nostrils from the eyes..."
				for eye in eyes:
					if not (eye[0]>(biggestnose[0]-5) and eye[0]<(biggestnose[0]+biggestnose[3]+5) and eye[1]>(biggestnose[1]-5) and eye[1]<(biggestnose[1]+biggestnose[2]+5)):
						finaleyes.append(eye)
				print "eyes: "+str(finaleyes)
				print "noses: "+str(noses)
				for (x,y,h,w) in finaleyes:
					cv2.rectangle(thisface,(x,y),(x+w,y+h),(0,255,255),1)
				for (x,y,h,w) in [biggestnose]:
					cv2.rectangle(thisface,(x,y),(x+w,y+h),(255,255,0),1)
				#print biggestnose
			elif len(eyes)==2:
				print "could not find a nose, found 2 eyes. working with them"
				for (x,y,h,w) in eyes:
					cv2.rectangle(thisface,(x,y),(x+w,y+h),(0,255,255),1)
				cv2.imshow("thisface",thisface)
				finaleyes=eyes
			elif len(eyes)==1 and len(noses)==1:
				print "only found an eye and a nose, working with them"
				eye=eyes[0]
				nose=noses[0]
				print eye, nose
				eyenosedist=np.sqrt((eye[0]-nose[0])**2 + (eye[1]-nose[1])**2)
				if nose[1]<eye[1]:
					"apparently the only nose is above the only eye, aborting"
					return []
				print "expanding face"
				expandedface=biggestface[0]
				expandedface[0]=expandedface[0]-eyenosedist/2
				expandedface[2]=expandedface[2]+eyenosedist   
				expandedface[3]=expandedface[3]+eyenosedist 				
				if eye[0]>nose[0]:
					expandedface[1]=expandedface[1]-eyenosedist
				for x,y,h,w in [expandedface]:
					thisface=img[x:(x+w),y:(y+h),:]
					cleanface=copy.deepcopy(thisface)
				cv2.imshow("expandedface",thisface)
				cv2.waitKey(35)
				#time.sleep(5)
				eyes=eyefinder.detectMultiScale(thisface,1.1,30)
				originaleye=eye
				finaleyes=[]
				for eye in eyes:
                                        if not (eye[0]>(biggestnose[0]-5) and eye[0]<(biggestnose[0]+biggestnose[3]+5) and eye[1]>(biggestnose[1]-5) and eye[1]<(biggestnose[1]+biggestnose[2]+5)):
                                                finaleyes.append(eye)
                                print "eyes: "+str(finaleyes)
                                print "noses: "+str(noses)
                                for (x,y,h,w) in finaleyes:
                                        cv2.rectangle(thisface,(x,y),(x+w,y+h),(0,255,255),1)
                                for (x,y,h,w) in [biggestnose]:
                                        cv2.rectangle(thisface,(x,y),(x+w,y+h),(255,255,0),1)
			else: #add parsing for more than 2 detected eyes without a nose
				print "feature detection went wrong"
				return []
			cv2.imshow("thisface features",thisface)
			eye1mid=(finaleyes[0][0]+finaleyes[0][3]/2,finaleyes[0][1]+finaleyes[0][2]/2)
			try:
				eye2mid=(finaleyes[1][0]+finaleyes[1][3]/2,finaleyes[1][1]+finaleyes[1][2]/2)
			except:
				print "something went wrong with the format of eyes, skipping to next iteration"
				return []
			if eye1mid[0]<eye2mid[0]:
				lefteye=eye1mid
				righteye=eye2mid
			else:
				lefteye=eye2mid
				righteye=eye1mid
			borderoffset=9.0/12.0
			midborderoffset=3
			eyetriangle=[righteye[0]-lefteye[0],righteye[1]-lefteye[1]]
			topbordermid=[lefteye[0]+eyetriangle[0]/2+eyetriangle[1]/midborderoffset,lefteye[1]+eyetriangle[1]/2-eyetriangle[0]/midborderoffset]
			topborder=[(topbordermid[0]-int(eyetriangle[0]*borderoffset),topbordermid[1]-int(eyetriangle[1]*borderoffset)),(topbordermid[0]+int(eyetriangle[0]*borderoffset),topbordermid[1]+int(eyetriangle[1]*borderoffset))]
			bordertriangle=[topborder[1][0]-topborder[0][0],topborder[1][1]-topborder[0][1]]
			borderlength=int(np.sqrt(bordertriangle[0]**2+bordertriangle[1]**2))
			print bordertriangle
			border=[topborder[0],topborder[1],(topborder[1][0]-bordertriangle[1],topborder[1][1]+bordertriangle[0]),(topborder[0][0]-bordertriangle[1],topborder[0][1]+bordertriangle[0])]
			violation=0
			for i in range(4):
				for j in range(2):
					if border[i][j]>thisface.shape[0] or border[i][j]<0:
						violation=1			
			if violation:
				print "could not align face, features too close to edge"
			else:
				print "aligning face"
				cv2.line(thisface,eye1mid,eye2mid,(255,0,0),1)
				cv2.line(thisface,border[0],border[1],(0,255,0),1)
				cv2.line(thisface,border[2],border[3],(0,255,0),1)
				cv2.line(thisface,border[0],border[3],(0,255,0),1)
				cv2.line(thisface,border[1],border[2],(0,255,0),1)
				#cv2.line(thisface,(nosemid[0]+eyedist,nosemid[1]+noseedgeoffset),(nosemid[0]-eyedist,nosemid[1]+noseedgeoffset),(0,255,0),1)
				facecenter=tuple(np.array([border[0][0]+border[2][0],border[0][1]+border[2][1]])/2)
				cv2.circle(thisface,facecenter,5,(255,0,0),-1)
				cv2.imshow("thisface border",thisface)
				rotationangle=np.arctan(float(eyetriangle[1])/float(eyetriangle[0]))
				rotationmat=cv2.getRotationMatrix2D(facecenter,rotationangle*180/np.pi,1.0)
				print border[0]
				bordercenteroffset=[border[0][0]-facecenter[0],border[0][1]-facecenter[1]]
				print bordercenteroffset
				borderoffsetafterrotation=[bordercenteroffset[0]*np.cos(rotationangle)+bordercenteroffset[1]*np.sin(rotationangle),bordercenteroffset[0]*np.sin(rotationangle)-bordercenteroffset[1]*np.cos(rotationangle)-borderlength]
				print borderoffsetafterrotation
				borderafterrotation=(int(borderoffsetafterrotation[0]+facecenter[0]),int(borderoffsetafterrotation[1]+facecenter[1]))
				print borderafterrotation
				finalface=cv2.warpAffine(thisface,rotationmat,thisface.shape[:2],flags=cv2.INTER_LINEAR)
				finalcroppedface=finalface[borderafterrotation[1]:borderlength+borderafterrotation[1],borderafterrotation[0]:borderafterrotation[0]+borderlength]
				cv2.circle(finalface,borderafterrotation,3,(0,255,0),-1)
				#cv2.circle(finalface,(borderafterrotation[0],borderafterrotation[1]-borderlength),3,(0,255,0),-1)
				cv2.circle(finalface,facecenter,4,(0,255,255),-1)
				cv2.imshow("rotated",finalface)
				cv2.imshow("final cropped face",finalcroppedface)
				cleanface=cv2.warpAffine(cleanface,rotationmat,thisface.shape[:2],flags=cv2.INTER_LINEAR)[borderafterrotation[1]:borderlength+borderafterrotation[1],borderafterrotation[0]:borderafterrotation[0]+borderlength]
				cv2.imshow("clean face",cleanface)
				cleanface=cv2.cvtColor(cleanface,cv2.COLOR_BGR2GRAY)
				cleanface=cv2.resize(cleanface,(60,60))
				cv2.imshow("small clean face",cleanface)
				return cleanface
			while 1:
				k=cv2.waitKey(10)
				if k==27:
					break
				else:
					continue
	return []


def makepredictor():
	imgset=[]
	labels=[]
	facefinder=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_frontalface_alt2.xml")
	eyefinder=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_eye.xml")
	nosefinder=cv2.CascadeClassifier("/home/pi/opencv-2.4.9/data/haarcascades/haarcascade_mcs_nose.xml")
	cam=cv2.VideoCapture(-1)
	while not raw_input("capture image? y/n ")=='n':
		face=getalignface(facefinder,eyefinder,nosefinder,cam)
		if len(face)>0:
			if not raw_input("is this the correct face? y/n ")=='n':
				imgset.append(face)
				labels.append(int(raw_input("who is this? (int) ")))

	labels=np.array(labels)
	facerec=cv2.createLBPHFaceRecognizer()
	facerec.train(imgset,labels)
	return facerec
