import cv2 import csv import sys import os from PIL import Image import io import base64 def detect_faces(image_path, output_image_path=None): """ detects if an image contains a face. returns: - 0 if no face is detected, 1 if at least one face is detected - the number of faces detected - list of detected face coordinates """ try: # **CHANGED** Load haar cascade with absolute path cascade_path = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml' face_cascade = cv2.CascadeClassifier(cascade_path) # Check if the cascade file is loaded correctly if face_cascade.empty(): raise IOError('Unable to load cascade classifier from: ' + cascade_path) # load image image = cv2.imread(image_path) if image is None: raise ValueError("image not found or could not be loaded.") # convert to greyscale gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # detect faces faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) face_crops = [] if len(faces) != 0: # if face detected if output_image_path: draw_faces(image, faces, output_image_path) pil_image = Image.open(image_path) # **CHANGED** Load image with Pillow to perform the image crops face_crops = crop_faces(pil_image, faces) # **CHANGED** Run the new crop faces function return (1, int(len(faces)), faces.tolist(), face_crops) # **CHANGED** Return the new crops function as well else: # if no face detected print("no face detected.") return (0, 0, [], []) # **CHANGED** except Exception as e: print(f"Error in face detection: {e}") return (0, 0, [], []) # **CHANGED** def draw_faces(image, faces, output_image_path): """ draws bounding boxes around detected faces and saves the image. prints the bounding box coordinates (x, y, width, height). writes face coordinates to a CSV file. """ # open csv file in write mode with open('faces_detected.csv', mode='w', newline='') as file: writer = csv.writer(file) # write header writer.writerow(['FACE', 'X', 'Y', 'W', 'H']) for i, (x, y, w, h) in enumerate(faces, 1): # draw rectangle (bounding box) around each face cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2) # green bounding box # print the coordinates of each bounding box print(f"face {i} found at (x={x}, y={y}, width={w}, height={h})") # write face data to csv writer.writerow([i, x, y, w, h]) # save image to output path cv2.imwrite(output_image_path, image) # Save the image print(f"Image saved to {output_image_path}") def crop_faces(image, faces): """ Crops the faces from the image based on the bounding box coordinates. Args: image: PIL Image object. faces: List of face coordinates (x, y, w, h). Returns: List of base64 encoded face crops. """ face_crops = [] for x, y, w, h in faces: try: face = image.crop((x, y, x + w, y + h)) buffered = io.BytesIO() face.save(buffered, format="PNG") img_str = base64.b64encode(buffered.getvalue()).decode('utf-8') face_crops.append(img_str) except Exception as e: print(f"Error cropping face: {e}") continue return face_crops