<filename>combinebackup.py
from lib.device import Camera
from lib.processors_noopenmdao import findFaceGetPulse
#from lib.interface import plotXY, imshow, waitKey, destroyWindow
from lib.interface import plotXY, imshow, waitKey, destroyWindow
from cv2 import moveWindow
import argparse
import numpy as np
import datetime
#TODO: work on serial port comms, if anyone asks for it
#from serial import Serial
import socket
import sys
import cv2
#from emotion_recognition import EmotionRecognition
#from constants import *

from scipy.spatial import distance as dist
#from imutils.video import VideoStream
from imutils import face_utils
from threading import Thread
#import playsound
import imutils
import time
import dlib
import Tkinter as tki
from PIL import Image
from PIL import ImageTk

class getPulseApp(object):

    """
    Python application that finds a face in a webcam stream, then isolates the
    forehead.

    Then the average green-light intensity in the forehead region is gathered
    over time, and the detected person's pulse is estimated.
    """

    def __init__(self, args):
        # Imaging device - must be a connected camera (not an ip camera or mjpeg
        # stream)
        serial = args.serial
        baud = args.baud
        self.send_serial = False
        self.send_udp = False
	self.COUNTER = 0
        if serial:
            self.send_serial = True
            if not baud:
                baud = 9600
            else:
                baud = int(baud)
            self.serial = Serial(port=serial, baudrate=baud)

        udp = args.udp
        if udp:
            self.send_udp = True
            if ":" not in udp:
                ip = udp
                port = 5005
            else:
                ip, port = udp.split(":")
                port = int(port)
            self.udp = (ip, port)
            self.sock = socket.socket(socket.AF_INET, # Internet
                 socket.SOCK_DGRAM) # UDP

        self.cameras = []
        self.selected_cam = 0
        for i in range(3):
            camera = Camera(camera=i)  # first camera by default
            if camera.valid or not len(self.cameras):
                self.cameras.append(camera)
            else:
                break
        self.w, self.h = 0, 0
        self.pressed = 0
	
        # Containerized analysis of recieved image frames (an openMDAO assembly)
        # is defined next.

        # This assembly is designed to handle all image & signal analysis,
        # such as face detection, forehead isolation, time series collection,
        # heart-beat detection, etc.

        # Basically, everything that isn't communication
        # to the camera device or part of the GUI
        self.processor = findFaceGetPulse(bpm_limits=[50, 160],
                                          data_spike_limit=2500.,
                                          face_detector_smoothness=10.)

        # Init parameters for the cardiac data plot
        self.bpm_plot = False
        self.plot_title = "Real-Time Heart Rate"

        # Maps keystrokes to specified methods
        #(A GUI window must have focus for these to work)
        self.key_controls = {"s": self.toggle_search,
                             "d": self.toggle_display_plot,
                             "c": self.toggle_cam,
                             "f": self.write_csv}
    def eye_aspect_ratio(self,eye):
	# compute the euclidean distances between the two sets of
	# vertical eye landmarks (x, y)-coordinates
	A = dist.euclidean(eye[1], eye[5])
	B = dist.euclidean(eye[2], eye[4])

	# compute the euclidean distance between the horizontal
	# eye landmark (x, y)-coordinates
	C = dist.euclidean(eye[0], eye[3])

	# compute the eye aspect ratio
	ear = (A + B) / (2.0 * C)

	# return the eye aspect ratio
	return ear
    def toggle_cam(self):
        if len(self.cameras) > 1:
            self.processor.find_faces = True
            self.bpm_plot = False
            destroyWindow(self.plot_title)
            self.selected_cam += 1
            self.selected_cam = self.selected_cam % len(self.cameras)

    def write_csv(self):
        """
        Writes current data to a csv file
        """
        fn = "Webcam-pulse" + str(datetime.datetime.now())
        fn = fn.replace(":", "_").replace(".", "_")
        data = np.vstack((self.processor.times, self.processor.samples)).T
        np.savetxt(fn + ".csv", data, delimiter=',')
        print("Writing csv")

    def toggle_search(self):
        """
        Toggles a motion lock on the processor's face detection component.

        Locking the forehead location in place significantly improves
        data quality, once a forehead has been sucessfully isolated.
        """
        #state = self.processor.find_faces.toggle()
        state = self.processor.find_faces_toggle()
        print("face detection lock =", not state)

    def toggle_display_plot(self):
        """
        Toggles the data display.
        """
        if self.bpm_plot:
            print("bpm plot disabled")
            self.bpm_plot = False
            destroyWindow(self.plot_title)
        else:
            print("bpm plot enabled")
            if self.processor.find_faces:
                self.toggle_search()
            self.bpm_plot = True
            self.make_bpm_plot()
            moveWindow(self.plot_title, self.w, 0)

    def make_bpm_plot(self):
        """
        Creates and/or updates the data display
        """
        frame1=plotXY([[self.processor.times,
                 self.processor.samples],
                [self.processor.freqs,
                 self.processor.fft]],
               labels=[False, True],
               showmax=[False, "bpm"],
               label_ndigits=[0, 0],
               showmax_digits=[0, 1],
               skip=[3, 3],
               name=self.plot_title)#,
               #bg=self.processor.slices[0])
    def key_handler(self):
        """
        Handle keystrokes, as set at the bottom of __init__()

        A plotting or camera frame window must have focus for keypresses to be
        detected.
        """

        self.pressed = waitKey(10) & 255  # wait for keypress for 10 ms
        if self.pressed == 27:  # exit program on 'esc'
            print("Exiting")
            for cam in self.cameras:
                cam.cam.release()
            if self.send_serial:
                self.serial.close()
            sys.exit()

        for key in self.key_controls.keys():
            if chr(self.pressed) == key:
                self.key_controls[key]()

    def main_loop(self,eye_aspect_ratio,root):
        """
        Single iteration of the application's main loop.
        """
        # Get current image frame from the camera
        frame = self.cameras[self.selected_cam].get_frame()
	#print frame.shape
        self.h, self.w, _c = frame.shape
	#print self.h, self.w, _c
	#result = network.predict(poc.format_image(frame))
	#frame = cameras[selected_cam].get_frame()
	frame = imutils.resize(frame, width=450)
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	# detect faces in the grayscale frame
	rects = detector(gray, 0)
	ALARM_ON=False
	# loop over the face detections
	for rect in rects:
		# determine the facial landmarks for the face region, then
		# convert the facial landmark (x, y)-coordinates to a NumPy
		# array
		shape = predictor(gray, rect)
		shape = face_utils.shape_to_np(shape)

		# extract the left and right eye coordinates, then use the
		# coordinates to compute the eye aspect ratio for both eyes
		leftEye = shape[lStart:lEnd]
		rightEye = shape[rStart:rEnd]
		leftEAR = eye_aspect_ratio(leftEye)
		rightEAR = eye_aspect_ratio(rightEye)

		# average the eye aspect ratio together for both eyes
		ear = (leftEAR + rightEAR) / 2.0

		# compute the convex hull for the left and right eye, then
		# visualize each of the eyes
		leftEyeHull = cv2.convexHull(leftEye)
		rightEyeHull = cv2.convexHull(rightEye)
		#cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
		#cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)

		# check to see if the eye aspect ratio is below the blink
		# threshold, and if so, increment the blink frame counter
		if ear < EYE_AR_THRESH:
			self.COUNTER += 1
			

			# if the eyes were closed for a sufficient number of
			# then sound the alarm
			if self.COUNTER >= EYE_AR_CONSEC_FRAMES:
				# if the alarm is not on, turn it on
				if not ALARM_ON:
					print ear, 'sleepy'
					ALARM_ON = True

		# otherwise, the eye aspect ratio is not below the blink
		# threshold, so reset the counter and alarm
		else:
			print ear, 'awake'
			self.COUNTER = 0
			ALARM_ON = False
	#if result is None:
	#  print ''
	#a = result[0].tolist().index(max(result[0]))
	# set current image frame to the processor's input
	self.processor.frame_in = frame
	# process the image frame to perform all needed analysis
	self.processor.run(self.selected_cam,ALARM_ON,root)
	# collect the output frame for display
	output_frame = self.processor.frame_out
	#cv2.imshow('haha',output_frame) 
	#print output_frame
	if output_frame is not None:
		#print 'face detect'
		img = Image.fromarray(output_frame)
		imgtk = ImageTk.PhotoImage(image=img)
		lmain.imgtk = imgtk 
		lmain.configure(image=imgtk)
		  
	# create and/or update the raw data display if needed
	if self.bpm_plot:
	    self.make_bpm_plot()

	if self.send_serial:
	    self.serial.write(str(self.processor.bpm) + "\r\n")

	if self.send_udp:
	    self.sock.sendto(str(self.processor.bpm), self.udp)

	  # handle any key presses
	self.key_handler()
	return output_frame
    def show_frame(self,frame,a):
	img = Image.fromarray(frame)
	imgtk = ImageTk.PhotoImage(image=img)
	if a ==0:
		lmain.imgtk = imgtk
		lmain.configure(image=imgtk)
		'''lmain1.imgtk = imgtk
		lmain1.configure(image=imgtk)'''

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Webcam pulse detector.')
    parser.add_argument('--serial', default=None,
                        help='serial port destination for bpm data')
    parser.add_argument('--baud', default=None,
                        help='Baud rate for serial transmission')
    parser.add_argument('--udp', default=None,
                        help='udp address:port destination for bpm data')
    parser.add_argument('--train', default=None,
                        help='udp address:port destination for bpm data')
    args = parser.parse_args()
    App = getPulseApp(args)
    #self.root.mainloop()
    '''if len(sys.argv) <= 1:
      show_usage()
      exit()
    if args.train == 'train':
      network.start_training()
      network.save_model()
    elif args.train== 'poc':
      import poc
    else:
      show_usage()'''
    #network = EmotionRecognition()
    #network.build_network()
    #video_capture = cv2.VideoCapture(0)
    font = cv2.FONT_HERSHEY_SIMPLEX
    EYE_AR_THRESH = 0.3
    EYE_AR_CONSEC_FRAMES = 48
    
    ALARM_ON = False
    # initialize dlib's face detector (HOG-based) and then create
    # the facial landmark predictor
    print("[INFO] loading facial landmark predictor...")
    detector = dlib.get_frontal_face_detector()
    #predictor = dlib.shape_predictor(args["shape_predictor"])
    predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
    # grab the indexes of the facial landmarks for the left and
    # right eye, respectively
    (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"] 
    (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
    te=[]
    root = tki.Tk()
    root.bind('<Escape>', lambda e: root.quit())
    root.wm_title("Pulse Sleep Detection")
    lmain = tki.Label(root)
    lmain.pack()
    lmain1 = tki.Label(root)
    lmain1.pack( side = tki.LEFT )
    #lmain1 = tki.Label(root)
    #lmain1.pack( side = tki.LEFT )
    #App.eye_aspect_ratio(te)
    while True:
        App.main_loop(App.eye_aspect_ratio,root)

    root.mainloop()
    
    
