from typing import List import face_recognition from PIL import Image from os import path as p import os import numpy as np # Main method utilized to crop the group photos into various individual person photos to feed into the model def getCroppedImages(image: Image.Image, cap = -1): """Takes a PIL image, and returns a list of PIL images with the cropped faces""" image = image.convert("RGB") face_locations = face_recognition.face_locations(np.array(image)) face_locations_n = [] outputs = [] num = 0 # Adjust dimensions of cropping to include more context width, height = image.size # Get image dimensions for f in face_locations: if cap != -1 and num >= cap: break # Original coordinates: (top, right, bottom, left) top, right, bottom, left = f # Center of the face rectangle center_x = (left + right) / 2 center_y = (top + bottom) / 2 # Expanded dimensions box_width = (right - left) * 1.6 box_height = (bottom - top) * 1.6 new_left = int(center_x - box_width / 2) new_right = int(center_x + box_width / 2) new_top = int(center_y - box_height / 2) new_bottom = int(center_y + box_height / 2) # Clamp to image boundaries new_left = max(0, new_left) new_right = min(width, new_right) new_top = max(0, new_top) new_bottom = min(height, new_bottom) # Crop the image with the new coordinates c = (new_left, new_top, new_right, new_bottom) outputs.append(image.crop(c)) face_locations_n.append(c) num += 1 # Return face_locations_n, outputs return face_locations_n, outputs # These following methods crop images but are not utilized in our app # def getFaceLocationsAndFiles(input_path: str, output_dir: str, output_name: str,): # """ # input_path: local or absolute path to the input image\n # output_dir: folder (local or absolute path) to save the output image to\n # output_name: name for the new image (do not include extension)\n # returns: list of face locations and list of paths to the cropped face images # """ # locs, imgs = getCroppedImages(Image.open(input_path)) # output_paths = [] # num = 0 # for i in imgs: # path = p.join(output_dir, f"{output_name}_{num}.png") # i.save(path) # output_paths.append(p.abspath(path)) # num += 1 # return locs, output_paths # def createCroppedSetFromImage(input_path: str, output_dir: str, output_name: str, cap = -1): # """ # input_path: local or absolute path to the input image\n # output_dir: folder (local or absolute path) to save the output image to\n # output_name: name for the new image (do not include extension)\n # cap: set to -1 to process all faces detected, otherwise will limit faces to value\n # returns: list of absolute paths to the images # """ # imgs = getCroppedImages(Image.open(input_path))[1] # num = 0 # for i in imgs: # path = p.join(output_dir, f"{output_name}_{num}.png") # i.save(path) # num += 1 # def createCroppedSets(input_path: str, output_path: str): # """ # Iterates through subdirectories in the input directory, making a duplicate of it in the output directory. # Then iterates through all images in the subdirectory, cropping each face and saving it to the output directory. # For example for params "input" and "output", input/Dwayne Johnson/img.png will be cropped and # saved to output/Dwayne Johnson/0_0.png (repeated for all folder and the images they contain) # WARNING: IF A DIRECTORY WITH THE SAME NAME AS THE OUTPUT DIRECTORY, IT WILL BE DELETED # """ # # delete previous folder so there's no conflicts # if(p.exists(output_path)): # shutil.rmtree(output_path) # os.mkdir(output_path) # # iterate through all subdirectories in input directory # for dir in [name for name in os.listdir(input_path) if p.isdir(p.join(input_path, name))]: # sub_out = p.join(output_path, dir) # sub_in = p.join(input_path, dir) # os.mkdir(sub_out) # n = 0 # # iterate through all files in subdirectory # for img in [name for name in os.listdir(sub_in) if p.isfile(p.join(sub_in, name))]: # createCroppedSetFromImage(p.join(sub_in, img), sub_out, n, 1) # n += 1