diff --git a/Gaze Detection/Operations.py b/Gaze Detection/Operations.py new file mode 100644 index 0000000..0a8fa41 --- /dev/null +++ b/Gaze Detection/Operations.py @@ -0,0 +1,5 @@ +import face_forward +import face_recognition +import cv2 +import os + diff --git a/Gaze Detection/Suspects/suspect_2.jpg b/Gaze Detection/Suspects/suspect_2.jpg new file mode 100644 index 0000000..d229c27 Binary files /dev/null and b/Gaze Detection/Suspects/suspect_2.jpg differ diff --git a/Gaze Detection/Suspects/suspect_3.jpg b/Gaze Detection/Suspects/suspect_3.jpg new file mode 100644 index 0000000..a97d748 Binary files /dev/null and b/Gaze Detection/Suspects/suspect_3.jpg differ diff --git a/Gaze Detection/caught/suspect_1.jpg b/Gaze Detection/caught/suspect_1.jpg index a170c28..ce441ac 100644 Binary files a/Gaze Detection/caught/suspect_1.jpg and b/Gaze Detection/caught/suspect_1.jpg differ diff --git a/Gaze Detection/caught/suspect_10.jpg b/Gaze Detection/caught/suspect_10.jpg new file mode 100644 index 0000000..aedd922 Binary files /dev/null and b/Gaze Detection/caught/suspect_10.jpg differ diff --git a/Gaze Detection/caught/suspect_12.jpg b/Gaze Detection/caught/suspect_12.jpg new file mode 100644 index 0000000..9746231 Binary files /dev/null and b/Gaze Detection/caught/suspect_12.jpg differ diff --git a/Gaze Detection/caught/suspect_2.jpg b/Gaze Detection/caught/suspect_2.jpg new file mode 100644 index 0000000..c14b6e1 Binary files /dev/null and b/Gaze Detection/caught/suspect_2.jpg differ diff --git a/Gaze Detection/caught/suspect_6.jpg b/Gaze Detection/caught/suspect_6.jpg new file mode 100644 index 0000000..a297adc Binary files /dev/null and b/Gaze Detection/caught/suspect_6.jpg differ diff --git a/Gaze Detection/clean_up.py b/Gaze Detection/clean_up.py new file mode 100644 index 0000000..dcbcaa9 --- /dev/null +++ b/Gaze Detection/clean_up.py @@ -0,0 +1,51 @@ +import face_recognition +import os + + +# Removes duplicates of suspects +def cleanUp(): + dir = "caught/" + fileCount = len(os.listdir(dir)) + print("num of images: " + str(fileCount)) + if(os.path.exists(dir + "suspect_1.jpg")): + # Adds suspect_1 to the individual suspects array + suspect1 = face_recognition.load_image_file(dir + "suspect_1.jpg") + suspect1Encoding = face_recognition.face_encodings(suspect1)[0] + individual_suspects = [suspect1Encoding] + i=2 + # Iterates from suspect_2 to the last suspect + for suspects in range(2,fileCount+1): + image,i = loadNextImage(i) + try: + imageEncoding = face_recognition.face_encodings(image)[0] + except IndexError: + print("there are no detected faces") + i+=1 + continue + # results is a boolean array that compares the encoding with each individual suspect + results = face_recognition.compare_faces(individual_suspects, imageEncoding) + if(not True in results): + # suspect is a new individual and is added to the array + individual_suspects.append(imageEncoding) + else: + os.remove(dir + "suspect_" + str(i)+ ".jpg") + print("suspect_" + str(i) + " was removed") + i+=1 + numIndividualSuspects = len(individual_suspects) + print("num of individual suspects: " + str(numIndividualSuspects)) + else: + return + +# Gets the next valid image +# i is the index of the next valid image +def loadNextImage(j): + i=j + while os.path.exists(dir): + try: + image = face_recognition.load_image_file(dir + "suspect_" + str(i) +".jpg") + return image,i + except FileNotFoundError: + i+=1 + continue + +cleanUp() \ No newline at end of file diff --git a/Gaze Detection/face_forward.py b/Gaze Detection/face_forward.py index 2d6b57a..fa8946c 100644 --- a/Gaze Detection/face_forward.py +++ b/Gaze Detection/face_forward.py @@ -19,9 +19,19 @@ def main(): print(facial_features[0][0]) print(str(timer)) +def up_sample(landmark_list , sample_size=4): + for face_landmark in landmark_list: + if len(face_landmark) > 1: + for key in face_landmark.keys(): + face_landmark[key] = [(w[0]*sample_size , w[1]*sample_size) for w in face_landmark[key]] + return landmark_list + def facial_coordinates(image): - print ('starting isForward') - face_landmarks_list = face_recognition.face_landmarks(image,model="small") + #print ('starting isForward') + small_frame = cv2.resize(image, (0, 0), fx=0.25, fy=0.25) + face_landmarks_list = face_recognition.face_landmarks(small_frame) + face_landmarks_list = up_sample(face_landmarks_list) + pil_image = Image.fromarray(image) d = ImageDraw.Draw(pil_image) @@ -30,9 +40,9 @@ def facial_coordinates(image): # Let's trace out each facial feature in the image with a line! for facial_feature in face_landmarks.keys(): - # if facial_feature == "chin" or facial_feature == "nose_tip": - print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature])) - return face_landmarks[facial_feature] + #if facial_feature == "nose_bridge" or facial_feature == "nose_tip": + #print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature])) + return face_landmarks["nose_bridge"], face_landmarks["nose_tip"] # return the picture # return pil_image @@ -49,9 +59,10 @@ def nose_inCircle(nose, center, radius): def calculate_length(a, b): #calculations to get length with points - # (Xa, Ya) and (Xb, Yb) - delta_x = math.abs(b[0] - a[0]) - delta_y = math.abs(b[1] - b[1]) + # (Xa, Ya) and (Xb, Yb) + delta_x = abs(b[0] - a[0]) + delta_y = abs(b[1] - a[1]) + size = math.sqrt(delta_x**2 + delta_y**2) return size @@ -64,14 +75,10 @@ def display(image): # image.show() def transform(image, size): - if size is "small": - #Shrink image to a fourth of the size to process faster - image = cv2.resize(image, (0, 0), fx=0.25, fy=0.25) - else: - #Shrink image to a fourth of the size to process faster - image = cv2.resize(image, (0, 0), fx=2, fy=2) + #Shrink image to a fourth of the size to process faster + image = cv2.resize(image, (0, 0), fx=size, fy=size) + return image if __name__ == '__main__': main() - diff --git a/Gaze Detection/real_time.py b/Gaze Detection/real_time.py index 811f60d..8c66f61 100644 --- a/Gaze Detection/real_time.py +++ b/Gaze Detection/real_time.py @@ -1,8 +1,10 @@ +from __future__ import division import face_forward import face_recognition import cv2 +import sys import os - +import math # Get a reference to webcam #0 (the default one) video_capture = cv2.VideoCapture(0) @@ -30,8 +32,18 @@ suspicion_levels = [] process_this_frame = True suspect_num = 0 -priority = "0" +#priority = "0"#****** +priority = 0 solid = True +initial = True + +# Checks if a face encoding exists in current known face encodings +def checkDupe(face_encoding): + results = face_recognition.compare_faces(known_face_encodings, face_encoding) + if(not True in results): + return False + else: + return True #We will only anylyze every 5 frames facial features frame_count = 0 @@ -41,8 +53,18 @@ ret, frame = video_capture.read() # Resize frame of video to 1/4 size for faster face recognition processing - small_frame = face_forward.transform(frame, 'small') - frame = face_forward.transform(frame, 'big') + resize_small = .25 + small_frame = face_forward.transform(frame,resize_small) + + #Make frame big given arg + if initial: + print("STARTING AT DEFULT CAMERA SIZE 1\n -use W to increase and S to decrease-") + video_size = 1 + frame = face_forward.transform(frame, video_size) + + #Get transformation number + t = int(round(float(video_size)/resize_small)) + # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) rgb_small_frame = small_frame[:, :, ::-1] @@ -52,9 +74,11 @@ # Find all the faces and face encodings in the current frame of video face_locations = face_recognition.face_locations(rgb_small_frame) face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations) + face_names = [] for face_encoding in face_encodings: + # See if the face is a match for the known face(s) matches = face_recognition.compare_faces(known_face_encodings, face_encoding) name = "Unknown" @@ -68,7 +92,7 @@ #only inciment priority once every 10 frames suspicion_levels[first_match_index] += 1 if suspicion_levels[first_match_index]%2 == 0: - priority = int(suspicion_levels[first_match_index]/10) + #priority = int(suspicion_levels[first_match_index]/10)#************ if solid: solid = False else: @@ -89,6 +113,23 @@ #add it to list of known faces known_face_encodings.append(suspect_face_encoding) known_face_names.append("SUSPECT_" + str(suspect_num)) + + if(len(face_recognition.face_encodings(suspect_image)) != 0): + suspect_face_encoding = face_recognition.face_encodings(suspect_image)[0] + # Removes frame from storage if encoding returns duplicate + if(checkDupe(suspect_face_encoding)): + print("captured frame is a duplicate. Removing...") + os.remove(storage + "/suspect_" + str(suspect_num) + ".jpg") + suspect_num -= 1 + continue + #Initialize suspition level + suspicion_levels.append(0) + print("Suspect priorities: "+ str(suspicion_levels)) + #add it to list of known faces + known_face_encodings.append(suspect_face_encoding) + known_face_names.append("SUSPECT_" + str(suspect_num)) + print("suspect_" + str(suspect_num) + " detected") + face_names.append(name) process_this_frame = not process_this_frame @@ -100,12 +141,12 @@ # frame = face_forward.isLookingForward(frame) # Blow the box to the size of video feed - top *= 8 - right *= 8 - bottom *= 8 - left *= 8 + top *= t + right *= t + bottom *= t + left *= t - priority = int(priority) + #priority = int(priority)#********* #Set color of bounding box TextColor = (255, 255, 255) if priority < 5: @@ -130,12 +171,35 @@ TextColor = (0, 0, 0) #Get pos of nose - center = int((left+right)/2), int((top+(bottom - 70))/2) + center = int((left+right)/2), int((top+(bottom - 20))/2) #Get radius - radius = int(((bottom-70) - top)/5) + radius = int(((bottom - 20) - top)/5) + #Get nose point and bridge points + ff = face_forward.facial_coordinates(frame) + looking = True + #If we did find a face and facial features + if ff : + noseBridgePts = ff[0] + nosePointPts = ff[1] + #Check if all nose point tips are in the circle + for x in nosePointPts: + inCircle1 = face_forward.nose_inCircle(x, center, radius) + #cv2.line(frame,center,x, (255,255,255),1) + if inCircle1 == False: + looking = False + #Check if the low nose bridge point is in the circle + inCircle2 = face_forward.nose_inCircle(noseBridgePts[3], center, radius) + #cv2.line(frame,center,noseBridgePts[3], (255,255,255),1) + if inCircle2 == False: + looking = False + #print(looking) + if looking == True: + if priority<2: + add = 0.20 + else: + add = add+.00001 + priority = priority + add - #nose[] = face_forward.getNose(frame) - # Draw a bounding box around the face cv2.rectangle(frame, (left, top), (right, bottom), color, 2) #cv2.circle(frame, left, 3, (0,0,255), thickness=1, lineType=8, shift=0) @@ -145,7 +209,9 @@ cv2.circle(frame,center, radius, color) font = cv2.FONT_HERSHEY_DUPLEX cv2.putText(frame, name, (left + 6, bottom - 38), font, 1.2, TextColor, 1) - cv2.putText(frame, "Priority: " + str(priority), (left + 6, bottom - 6), font, 0.8, TextColor, 1) + priorityStr = str(math.floor(priority)) + #cv2.putText(frame, "Priority: " + str(priority), (left + 6, bottom - 6), font, 0.8, TextColor, 1) + cv2.putText(frame, "Priority: " + priorityStr, (left + 6, bottom - 6), font, 0.8, TextColor, 1) # Display the resulting image cv2.imshow('Live Feed', frame) @@ -158,9 +224,27 @@ if cv2.waitKey(1) & 0xFF == ord('q'): break + # Resize with numbers + initial = False + if cv2.waitKey(1) & 0xFF == ord('w'): + video_size += 1 + print("Video_size is: "+ str(video_size)) + if cv2.waitKey(1) & 0xFF == ord('s'): + if video_size > 1: + video_size -= 1 + print("Video_size is: "+ str(video_size)) + # elif cv2.waitKey(1) & 0xFF == ord('2'): + # video_size = 2 + # elif cv2.waitKey(1) & 0xFF == ord('3'): + # video_size = 3 + # elif cv2.waitKey(1) & 0xFF == ord('4'): + # video_size = 4 + # Release handle to the webcam video_capture.release() cv2.destroyAllWindows() def drawCircle(image, center, radius): cv2.circle(image, center, radius, color, thickness=1, lineType=8, shift=0) + +print("Program Closed") diff --git a/Gaze Detection/real_time_makeup.py b/Gaze Detection/real_time_makeup.py new file mode 100644 index 0000000..2a7dabc --- /dev/null +++ b/Gaze Detection/real_time_makeup.py @@ -0,0 +1,92 @@ +import cv2 +import face_recognition +from PIL import Image, ImageDraw +import numpy as np +import face_forward + + +def PIL2array(img): + """ Convert a PIL/Pillow image to a numpy array """ + return np.array(img.getdata(), + np.uint8).reshape(img.size[1], img.size[0], 3) + +def up_sample(landmark_list , sample_size=4): + for face_landmark in landmark_list: + if len(face_landmark) > 1: + for key in face_landmark.keys(): + face_landmark[key] = [(w[0]*sample_size , w[1]*sample_size) for w in face_landmark[key]] + return landmark_list + + +class FaceLandMarkDetection: + + def predict(self , frame): + face_landmarks = face_recognition.face_landmarks(frame) + if down_sampling: + self.face_landmarks = up_sample(face_landmarks) + else: + self.face_landmarks = face_landmarks + + + def plot(self , frame): + pil_image = Image.fromarray(frame) + for face_landmarks in self.face_landmarks: + if len(face_landmarks) > 1: + d = ImageDraw.Draw(pil_image, 'RGBA') + + # Make the eyebrows into a nightmare + d.polygon(face_landmarks['left_eyebrow'], fill=(68, 54, 39, 128)) + d.polygon(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 128)) + d.line(face_landmarks['left_eyebrow'], fill=(68, 54, 39, 150), width=5) + d.line(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 150), width=5) + + # Gloss the lips + d.polygon(face_landmarks['top_lip'], fill=(150, 0, 0, 128)) + d.polygon(face_landmarks['bottom_lip'], fill=(150, 0, 0, 128)) + d.line(face_landmarks['top_lip'], fill=(150, 0, 0, 64), width=8) + d.line(face_landmarks['bottom_lip'], fill=(150, 0, 0, 64), width=8) + + # Sparkle the eyes + d.polygon(face_landmarks['left_eye'], fill=(255, 255, 255, 30)) + d.polygon(face_landmarks['right_eye'], fill=(255, 255, 255, 30)) + + # Apply some eyeliner + d.line(face_landmarks['left_eye'] + [face_landmarks['left_eye'][0]], fill=(0, 0, 0, 110), width=6) + d.line(face_landmarks['right_eye'] + [face_landmarks['right_eye'][0]], fill=(0, 0, 0, 110), width=6) + + return PIL2array(pil_image) + +video_capture = cv2.VideoCapture(0) +video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) +video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + + +face_landmark_detection = FaceLandMarkDetection() +down_sampling = True +while True: + # Grab a single frame of video + ret, frame = video_capture.read() + + if down_sampling: + small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25) + + # Find all facial features in all the faces in the image + face_landmark_detection.predict(small_frame) + else: + # Find all facial features in all the faces in the image + face_landmark_detection.predict(frame) + + ### plot + frame = face_landmark_detection.plot(frame) + + frame = face_forward.transform(frame, "Big") + # Display the resulting image + cv2.imshow('Video', frame) + + # Hit 'q' on the keyboard to quit! + if cv2.waitKey(1) & 0xFF == ord('q'): + break + +# Release handle to the webcam +video_capture.release() +cv2.destroyAllWindows() \ No newline at end of file diff --git a/Gaze Detection/server.html b/Gaze Detection/server.html new file mode 100644 index 0000000..9a4d35a --- /dev/null +++ b/Gaze Detection/server.html @@ -0,0 +1,11 @@ + + +
+ +
+
+
\ No newline at end of file
diff --git a/Gaze Detection/server.py b/Gaze Detection/server.py
new file mode 100644
index 0000000..47ea771
--- /dev/null
+++ b/Gaze Detection/server.py
@@ -0,0 +1,18 @@
+from http.server import HTTPServer, SimpleHTTPRequestHandler
+
+class Server(SimpleHTTPRequestHandler):
+
+ def do_get(self):
+ if self.path == '/':
+ self.path = '/index.html'
+ try:
+ file_to_open = open(self.path[1:]).read()
+ self.send_response(200)
+ except:
+ file_to_open = "File Not Found"
+ self.send_response(404)
+ self.end_headers()
+ self.wfile.write(bytes(file_to_open, 'utf-8'))
+
+httpd = HTTPServer(('localhost', 8080), Server)
+httpd.serve_forever()
\ No newline at end of file