''' Created on May 7, 2014 @author: eran ''' from adiencealign.common.images import extract_box import glob import os import time from adiencealign.cascade_detection.cascade_detector import CascadeDetector,\ resolve_boxes, CascadeResult import cv2 import csv ''' Created on Dec 18, 2013 @author: eran ''' ''' Created on Nov 26, 2013 @author: eran ''' class CascadeFaceFinder(object): def __init__(self, min_size = 32, drawn_target_res = 360*360, hangles = [0, -22, 22], langles = [0,-45,-22,22,45], haar_file = 'haarcascade_frontalface_default.xml', lbp_file = 'lbpcascade_frontalface.xml'): ''' finder = CascadeFaceFinder(min_size = 32, drawn_target_res = 360*360, hangles = [0], langles = [0,-45,-22,22,45], parts_threshold = 0) finder.get_faces_in_folder(input_folder, output_dir, drawn_folder, is_small_drawn) or finder.get_faces_in_photo(full_file, output_dir, drawn_folder, is_small_drawn) ''' self.min_size = (min_size,min_size) self.drawn_target_res = drawn_target_res self._hangles = hangles self._langles = langles self.recalc_detectors(haar_file, lbp_file) # self.funnel = FaceFunnel() @property def hangles(self): return self._hangles @hangles.setter def hangles(self,hangles): self._hangles = hangles self.recalc_detectors() @property def langles(self): return self._langles @langles.setter def langles(self,langles): self._langles = langles self.recalc_detectors() def recalc_detectors(self, haar_file, lbp_file): self.haar_dtct = CascadeDetector(cascade_file = haar_file, min_size = self.min_size, min_neighbors = 20, scale_factor = 1.03, cascade_type = 'haar', thr = 0.4, angles = self.hangles) self.lbp_dtct = CascadeDetector(cascade_file = lbp_file, min_size = self.min_size, min_neighbors = 15, scale_factor = 1.04, cascade_type = 'lbp', thr = 0.4, angles = self.langles) def get_faces_list_in_photo(self, img): if self.hangles: haar_faces = self.haar_dtct.detectWithAngles(img, resolve = True) else: haar_faces = [] lbp_faces = self.lbp_dtct.detectWithAngles(img, resolve = True) faces = resolve_boxes({'haar':haar_faces, 'lbp':lbp_faces}, min_overlap = 0.6) return faces def create_faces_file(self, fname, is_overwrite = False, target_file = None): ''' Runs facial detection on fname (say a.jpg, or a.png), and creates a results file (a.faces.txt) target_file - override, and specify a specific target file is_overwrite - allow overwriting an existing results file ''' faces = self.get_faces_list_in_photo(cv2.imread(fname)) results_file = fname.rsplit('.',1)[0] + '.faces.txt' if target_file is None else target_file if os.path.exists(results_file) and not is_overwrite: print("Warning, faces result file", results_file, "exists") else: with open(results_file,'w') as csvfile: csv_writer = csv.writer(csvfile, delimiter=',') header = ['x', 'y','dx','dy', 'score', 'angle', 'type'] csv_writer.writerow(header) for face in faces: csv_writer.writerow([str(i) for i in [int(face.x), int(face.y), int(face.dx), int(face.dy), face.score, face.angle, face.cascade_type]]) return results_file def get_sub_images_from_file(self,original_image_file, faces_file): ''' extracts all the face sub-images from an image file, based on the results in a faces file returns - the list of face images (numpy arrays) ''' img = cv2.imread(original_image_file) faces_reader = csv.reader(open(faces_file)) next(faces_reader) # discard the headings padded_face_images = [] for line in faces_reader: x, y, dx, dy, score, angle, cascade_type = line [x,y,dx,dy,score, angle] = [int(float(i)) for i in [x,y,dx,dy,score, angle]] face = CascadeResult(([x,y,dx,dy], score), cascade_type, angle) padded_face, bounding_box_in_padded_face, _, _ = extract_box(img, face, padding_factor = 0.25) padded_face_images.append(padded_face) return padded_face_images def create_sub_images_from_file(self, original_image_file, faces_file, target_folder = None, img_type = 'png'): ''' reads a faces file, created by "self.create_faces_file" and extracts padded faces from the original image The faces will be created in the same folder as the faces file, unless specified otherwise by "target_folder" returns - the list of face files (strings) ''' target_folder = os.path.split(faces_file)[0] if target_folder is None else target_folder padded_face_images = self.get_sub_images_from_file(original_image_file, faces_file) base_image_name = os.path.split(faces_file)[1].split('.')[0] face_files = [] for n_face, face_img in enumerate(padded_face_images): face_file = os.path.join(target_folder, base_image_name + '_face_%d.%s' %(n_face, img_type)) cv2.imwrite( face_file , face_img ) face_files.append(face_file) return face_files