Grouping images based on the face in the images

Viewed 53

I have roughly 5000 photographs of various persons that I am organising according to the person. As a result, I intend to develop a Python script to carry out the task. I'm new to the Opencv library and am unsure whether this is feasible to do. To locate the faces in the photos, I wrote the code below.

import cv2

def find_faces(imagePath,results_path):

faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_eye.xml")

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(gray,scaleFactor=1.3,minNeighbors=3,minSize=(30, 30))

for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi_color = image[y:y + h, x:x + w]
    roi_gray = gray[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    if len(eyes) >= 2:
        cv2.imwrite(results_path + str(w) + str(h) + '_faces.jpg', roi_color)

Now I need to organise the photographs per person.Any help with the next steps is greatly appreciated.

1 Answers

As a fan of dlib / face_recognition libs I'd propose to use them (look at face_recognition tutorial - it's really easy)) to:

  1. Create a dictionary with face encodings for all images and pathes to the image files:

  2. Loop through the face encodings and compare each one with the rest: you don't need 100% similarity, normally 72..75% (0.28..0.25) means the same individual. I'm using something like that to store face data:

     class Face_Dictionary():
         """[The class contains all data structures to store in memory as 
            well as load and save to file
            face encodings data, including picture file full path and 
            face location for each face on every picture]
         """    
    
     def __init__(self, dicfilename="", mode="load"): #Create all data objects
         self.mode = mode
         self.dicfilename = dicfilename
         self.fl_Loaded = False
         self.fl_Saved = False
         self.Encodings = []
         self.Names = []
         self.facelocs = []
         self.fd = {"encodings": self.Encodings, "names": self.Names, 
                     "locations": self.facelocs}
         if bool(self.dicfilename) and self.mode == "load":
             self.fl_Loaded = self.load()
    
    
     def __del__(self): #redefine method del()
         del(self.Encodings)
         del(self.Names)
         del(self.facelocs)
         del(self.fd)
    
     def load(self):
         """
         [Loads a dictionary with face encodings from Pickle-type file into self.fd]
    
         Args:
             dicfilename ([str]): [Pickle-type file *.pkl]
    
         Returns:
             [bool]: [True if loaded. Also sets self.fl_Loaded as True]
         """
         if bool(self.dicfilename) and self.mode == "load":
             try:
                 f = open(self.dicfilename, "rb")
             except (IOError, EOFError) as e:
                 print("[ERR] Не можу знайти/прочитати файл кодувань обличь: %s" % e)
                 return False
             else:
                 if os.path.getsize(self.dicfilename) > 15:
                     self.fd = load(f)
                     self.fl_Loaded = True
                 else:
                     f.close()
                     return  False
             f.close()
             return True
         else:
             return False
    
     def save(self):
         """
         [Saves dictionary with face encodings to Pickle-type file]
    
         Args:
             None
    
         Returns:
             [bool]: [True if self.fd has been saved to the original <self.dicfilename.pkl>.
             Also sets self.fl_Saved as True]
         """
         if bool(self.dicfilename) and self.mode == "save":
             try:
                 f = open(self.dicfilename, "wb")
             except OSError:
                 print("[ERR] Не можу створити файл бази даних %s" % self.dicfilename)
                 return False
             dump(self.fd, f, protocol=HIGHEST_PROTOCOL)
             f.close()
             self.fl_Saved = True
             return True
    
     def save_as(self, filename):
         """
         [Saves dictionary with face encodings to Pickle-type file with specified name]
    
         Args:
             filename ([str]): [Pickle-type file *.pkl]
    
         Returns:
             [bool]: [True if self.fd has been saved to the original <self.dicfilename.pkl>.
             Also sets self.fl_Saved as True]
         """
         if bool(filename):
             try:
                 f = open(filename, "wb")
             except OSError:
                 print("[ERR] Не можу створити файл бази даних %s" % filename)
                 return False
             dump(self.fd, f, protocol=HIGHEST_PROTOCOL)
             f.close()
             self.fl_Saved = True
             return True   
    
Related