├── .gitignore ├── README.md ├── LICENSE └── webcam_face.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | credit must be given to Robert van Straalen for part of this source code 2 | 3 | ## How to use this repository 4 | 5 | 6 | You will need to choose a folder to put your friend's face images. The images should be in the following format: friend_name.jpg 7 | 8 | This python script loads two variables from an external file called "project_paths.txt" (excluded for security reasons) the contents of this text file are just two lines, the path to the folder containing your friend's photos and the IP address of your video stream. a sample project_paths.txt looks like this: 9 | 10 | path/to/image_folder 11 | 192.168.1.100 12 | 13 | That's it, go ahead and run the script! 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Timothy Schellin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /webcam_face.py: -------------------------------------------------------------------------------- 1 | ''' 2 | @author - Tim Schellin 3 | 2/20/2020 4 | ''' 5 | 6 | import face_recognition 7 | import cv2 8 | import numpy as np 9 | import glob 10 | import os 11 | import logging 12 | import urllib 13 | import time 14 | from PIL import Image 15 | 16 | 17 | IMAGES_PATH = '' 18 | WEBCAM_IP = '' 19 | CAMERA_DEVICE_ID = 2 20 | MAX_DISTANCE = 0.6 21 | 22 | 23 | def main(): 24 | global IMAGES_PATH, WEBCAM_IP 25 | IMAGES_PATH, WEBCAM_IP = load_paths() 26 | known_faces = load_identities() 27 | run_face_recognition(known_faces) 28 | 29 | 30 | def run_face_recognition(known_faces): 31 | known_face_encodings = list(known_faces.values()) 32 | known_face_names = list(known_faces.keys()) 33 | 34 | stream = urllib.urlopen(WEBCAM_IP) 35 | bytes = '' 36 | while True: 37 | bytes += stream.read(1024) 38 | a = bytes.find(b'\xff\xd8') 39 | b = bytes.find(b'\xff\xd9') 40 | 41 | if a != -1 and b != -1: 42 | jpg = bytes[a:b+2] 43 | bytes = bytes[b+2:] 44 | frame = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR) 45 | face_locations, face_encodings = get_embed_from_img(frame, convert_to_rgb=True) 46 | 47 | # Loop through each face in this frame of video and see if there's a match 48 | for location, face_encoding in zip(face_locations, face_encodings): 49 | distances = face_recognition.face_distance(known_face_encodings, face_encoding) 50 | if np.any(distances <= MAX_DISTANCE): 51 | best_match_idx = np.argmin(distances) 52 | name = known_face_names[best_match_idx] 53 | else: 54 | name = None 55 | # put recognition info on the image 56 | draw_box_on_face(frame, location, name) 57 | cv2.imshow('Video', frame) # Display the resulting image 58 | if cv2.waitKey(1) & 0xFF == ord('q'): 59 | break 60 | cv2.destroyAllWindows() 61 | 62 | 63 | def draw_box_on_face(frame, location, name=None): 64 | top, right, bottom, left = location 65 | if name is None: 66 | name = 'Unknown' 67 | color = (0, 0, 255) # red for unrecognized face 68 | else: 69 | color = (0, 128, 0) # dark green for recognized face 70 | cv2.rectangle(frame, (left, top), (right, bottom), color, 2) 71 | cv2.rectangle(frame, (left, bottom - 35), (right, bottom), color, cv2.FILLED) 72 | cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1) 73 | 74 | 75 | def get_embed_from_img(image, convert_to_rgb=False): 76 | if convert_to_rgb: 77 | image = image[:, :, ::-1] 78 | face_locations = face_recognition.face_locations(image) 79 | face_encodings = face_recognition.face_encodings(image, face_locations) 80 | return face_locations, face_encodings 81 | 82 | 83 | def load_identities(): 84 | known_faces = {} 85 | for filename in glob.glob(os.path.join(IMAGES_PATH, '*.jpg')): 86 | image_rgb = face_recognition.load_image_file(filename) 87 | identity = os.path.splitext(os.path.basename(filename))[0] 88 | locations, encodings = get_embed_from_img(image_rgb, convert_to_rgb=True) 89 | try: 90 | known_faces[identity] = encodings[0] 91 | except: 92 | pass 93 | return known_faces 94 | 95 | 96 | def save_to_folder(name, frame): 97 | img = Image.fromarray(frame) 98 | filename = '{0}/{1}/{1}{2}.jpg'.format(IMAGES_PATH, name, time.time()) 99 | img.save(filename) 100 | 101 | def load_paths(): 102 | lines = [line.rstrip('\n') for line in open('project_paths.txt').readlines()] 103 | return lines[0], lines[1] 104 | 105 | if __name__ == "__main__": 106 | main() 107 | --------------------------------------------------------------------------------