def main( detector=None, input_path=None, output_path=None, output_debug=None, manual_fix=False, manual_output_debug_fix=False, manual_window_size=1368, image_size=256, face_type='full_face', max_faces_from_image=0, cpu_only=False, force_gpu_idxs=None, ): face_type = FaceType.fromString(face_type) if not input_path.exists(): io.log_err('Input directory not found. Please ensure it exists.') return if detector is None: io.log_info("Choose detector type.") io.log_info("[0] S3FD") io.log_info("[1] manual") detector = {0: 's3fd', 1: 'manual'}[io.input_int("", 0, [0, 1])] device_config = nn.DeviceConfig.GPUIndexes( force_gpu_idxs or nn.ask_choose_device_idxs(choose_only_one=detector=='manual', suggest_all_gpu=True) ) \ if not cpu_only else nn.DeviceConfig.CPU() output_debug_path = output_path.parent / (output_path.name + '_debug') if output_debug is None: output_debug = io.input_bool( f"Write debug images to {output_debug_path.name}?", False) if output_path.exists(): if not manual_output_debug_fix and input_path != output_path: output_images_paths = pathex.get_image_paths(output_path) if len(output_images_paths) > 0: io.input( f"WARNING !!! \n {output_path} contains files! \n They will be deleted. \n Press enter to continue." ) for filename in output_images_paths: Path(filename).unlink() else: output_path.mkdir(parents=True, exist_ok=True) input_path_image_paths = pathex.get_image_unique_filestem_paths( input_path, verbose_print_func=io.log_info) if manual_output_debug_fix: if not output_debug_path.exists(): io.log_err( f'{output_debug_path} not found. Re-extract faces with "Write debug images" option.' ) return else: detector = 'manual' io.log_info( 'Performing re-extract frames which were deleted from _debug directory.' ) input_path_image_paths = DeletedFilesSearcherSubprocessor( input_path_image_paths, pathex.get_image_paths(output_debug_path)).run() input_path_image_paths = sorted(input_path_image_paths) io.log_info('Found %d images.' % (len(input_path_image_paths))) else: if output_debug_path.exists(): for filename in pathex.get_image_paths(output_debug_path): Path(filename).unlink() else: output_debug_path.mkdir(parents=True, exist_ok=True) images_found = len(input_path_image_paths) faces_detected = 0 if images_found != 0: if detector == 'manual': io.log_info('Performing manual extract...') data = ExtractSubprocessor( [ ExtractSubprocessor.Data(Path(filename)) for filename in input_path_image_paths ], 'landmarks-manual', image_size, face_type, output_debug_path if output_debug else None, manual_window_size=manual_window_size, device_config=device_config).run() io.log_info('Performing 3rd pass...') data = ExtractSubprocessor( data, 'final', image_size, face_type, output_debug_path if output_debug else None, final_output_path=output_path, device_config=device_config).run() else: io.log_info('Extracting faces...') data = ExtractSubprocessor( [ ExtractSubprocessor.Data(Path(filename)) for filename in input_path_image_paths ], 'all', image_size, face_type, output_debug_path if output_debug else None, max_faces_from_image=max_faces_from_image, final_output_path=output_path, device_config=device_config).run() faces_detected += sum([d.faces_detected for d in data]) if manual_fix: if all(np.array([d.faces_detected > 0 for d in data]) == True): io.log_info('All faces are detected, manual fix not needed.') else: fix_data = [ ExtractSubprocessor.Data(d.filepath) for d in data if d.faces_detected == 0 ] io.log_info('Performing manual fix for %d images...' % (len(fix_data))) fix_data = ExtractSubprocessor( fix_data, 'landmarks-manual', image_size, face_type, output_debug_path if output_debug else None, manual_window_size=manual_window_size, device_config=device_config).run() fix_data = ExtractSubprocessor( fix_data, 'final', image_size, face_type, output_debug_path if output_debug else None, final_output_path=output_path, device_config=device_config).run() faces_detected += sum([d.faces_detected for d in fix_data]) io.log_info('-------------------------') io.log_info('Images found: %d' % (images_found)) io.log_info('Faces detected: %d' % (faces_detected)) io.log_info('-------------------------')
def pack(samples_path): samples_dat_path = samples_path / packed_faceset_filename if samples_dat_path.exists(): io.log_info(f"{samples_dat_path} : file already exists !") io.input("Press enter to continue and overwrite.") as_person_faceset = False dir_names = pathex.get_all_dir_names(samples_path) if len(dir_names) != 0: as_person_faceset = io.input_bool(f"{len(dir_names)} subdirectories found, process as person faceset?", True) if as_person_faceset: image_paths = [] for dir_name in dir_names: image_paths += pathex.get_image_paths(samples_path / dir_name) else: image_paths = pathex.get_image_paths(samples_path) samples = samplelib.SampleLoader.load_face_samples(image_paths) samples_len = len(samples) samples_configs = [] for sample in io.progress_bar_generator (samples, "Processing"): sample_filepath = Path(sample.filename) sample.filename = sample_filepath.name if as_person_faceset: sample.person_name = sample_filepath.parent.name samples_configs.append ( sample.get_config() ) samples_bytes = pickle.dumps(samples_configs, 4) of = open(samples_dat_path, "wb") of.write ( struct.pack ("Q", PackedFaceset.VERSION ) ) of.write ( struct.pack ("Q", len(samples_bytes) ) ) of.write ( samples_bytes ) del samples_bytes #just free mem del samples_configs sample_data_table_offset = of.tell() of.write ( bytes( 8*(samples_len+1) ) ) #sample data offset table data_start_offset = of.tell() offsets = [] for sample in io.progress_bar_generator(samples, "Packing"): try: if sample.person_name is not None: sample_path = samples_path / sample.person_name / sample.filename else: sample_path = samples_path / sample.filename with open(sample_path, "rb") as f: b = f.read() offsets.append ( of.tell() - data_start_offset ) of.write(b) except: raise Exception(f"error while processing sample {sample_path}") offsets.append ( of.tell() ) of.seek(sample_data_table_offset, 0) for offset in offsets: of.write ( struct.pack("Q", offset) ) of.seek(0,2) of.close() for filename in io.progress_bar_generator(image_paths, "Deleting files"): Path(filename).unlink() if as_person_faceset: for dir_name in io.progress_bar_generator(dir_names, "Deleting dirs"): dir_path = samples_path / dir_name try: shutil.rmtree(dir_path) except: io.log_info (f"unable to remove: {dir_path} ")
def dev_test(input_dir): """ extract FaceSynthetics dataset https://github.com/microsoft/FaceSynthetics BACKGROUND = 0 SKIN = 1 NOSE = 2 RIGHT_EYE = 3 LEFT_EYE = 4 RIGHT_BROW = 5 LEFT_BROW = 6 RIGHT_EAR = 7 LEFT_EAR = 8 MOUTH_INTERIOR = 9 TOP_LIP = 10 BOTTOM_LIP = 11 NECK = 12 HAIR = 13 BEARD = 14 CLOTHING = 15 GLASSES = 16 HEADWEAR = 17 FACEWEAR = 18 IGNORE = 255 """ image_size = 1024 face_type = FaceType.WHOLE_FACE input_path = Path(input_dir) output_path = input_path.parent / f'{input_path.name}_out' if output_path.exists(): output_images_paths = pathex.get_image_paths(output_path) if len(output_images_paths) != 0: io.input(f"\n WARNING !!! \n {output_path} contains files! \n They will be deleted. \n Press enter to continue.\n") for filename in output_images_paths: Path(filename).unlink() output_path.mkdir(parents=True, exist_ok=True) data = [] for filepath in io.progress_bar_generator(pathex.get_paths(input_path), "Processing"): if filepath.suffix == '.txt': image_filepath = filepath.parent / f'{filepath.name.split("_")[0]}.png' if not image_filepath.exists(): print(f'{image_filepath} does not exist, skipping') lmrks = [] for lmrk_line in filepath.read_text().split('\n'): if len(lmrk_line) == 0: continue x, y = lmrk_line.split(' ') x, y = float(x), float(y) lmrks.append( (x,y) ) lmrks = np.array(lmrks[:68], np.float32) rect = LandmarksProcessor.get_rect_from_landmarks(lmrks) data += [ ExtractSubprocessor.Data(filepath=image_filepath, rects=[rect], landmarks=[ lmrks ] ) ] if len(data) > 0: io.log_info ("Performing 3rd pass...") data = ExtractSubprocessor (data, 'final', image_size, 95, face_type, final_output_path=output_path, device_config=nn.DeviceConfig.CPU()).run() for filename in io.progress_bar_generator(pathex.get_image_paths (output_path), "Processing"): filepath = Path(filename) dflimg = DFLJPG.load(filepath) src_filename = dflimg.get_source_filename() image_to_face_mat = dflimg.get_image_to_face_mat() seg_filepath = input_path / ( Path(src_filename).stem + '_seg.png') if not seg_filepath.exists(): raise ValueError(f'{seg_filepath} does not exist') seg = cv2_imread(seg_filepath) seg_inds = np.isin(seg, [1,2,3,4,5,6,9,10,11]) seg[~seg_inds] = 0 seg[seg_inds] = 1 seg = seg.astype(np.float32) seg = cv2.warpAffine(seg, image_to_face_mat, (image_size, image_size), cv2.INTER_LANCZOS4) dflimg.set_xseg_mask(seg) dflimg.save()
def main( detector=None, input_path=None, output_path=None, output_debug=None, manual_fix=False, manual_output_debug_fix=False, manual_window_size=1368, face_type='full_face', max_faces_from_image=None, image_size=None, jpeg_quality=None, cpu_only=False, force_gpu_idxs=None, ): if not input_path.exists(): io.log_err('Input directory not found. Please ensure it exists.') return if not output_path.exists(): output_path.mkdir(parents=True, exist_ok=True) if face_type is not None: face_type = FaceType.fromString(face_type) if face_type is None: if manual_output_debug_fix: files = pathex.get_image_paths(output_path) if len(files) != 0: dflimg = DFLIMG.load(Path(files[0])) if dflimg is not None and dflimg.has_data(): face_type = FaceType.fromString(dflimg.get_face_type()) input_image_paths = pathex.get_image_unique_filestem_paths( input_path, verbose_print_func=io.log_info) output_images_paths = pathex.get_image_paths(output_path) output_debug_path = output_path.parent / (output_path.name + '_debug') continue_extraction = False if not manual_output_debug_fix and len(output_images_paths) > 0: if len(output_images_paths) > 128: continue_extraction = io.input_bool( "Continue extraction?", True, help_message= "Extraction can be continued, but you must specify the same options again." ) if len(output_images_paths) > 128 and continue_extraction: try: input_image_paths = input_image_paths[ [Path(x).stem for x in input_image_paths]. index(Path(output_images_paths[-128]).stem.split('_')[0]):] except: io.log_err( "Error in fetching the last index. Extraction cannot be continued." ) return elif input_path != output_path: io.input( f"\n WARNING !!! \n {output_path} contains files! \n They will be deleted. \n Press enter to continue.\n" ) for filename in output_images_paths: Path(filename).unlink() device_config = nn.DeviceConfig.GPUIndexes( force_gpu_idxs or nn.ask_choose_device_idxs(choose_only_one=detector=='manual', suggest_all_gpu=True) ) \ if not cpu_only else nn.DeviceConfig.CPU() if face_type is None: face_type = io.input_str( "Face type", 'wf', ['f', 'wf', 'head'], help_message= "Full face / whole face / head. 'Whole face' covers full area of face include forehead. 'head' covers full head, but requires XSeg for src and dst faceset." ).lower() face_type = { 'f': FaceType.FULL, 'wf': FaceType.WHOLE_FACE, 'head': FaceType.HEAD }[face_type] if max_faces_from_image is None: max_faces_from_image = io.input_int( f"Max number of faces from image", 0, help_message= "If you extract a src faceset that has frames with a large number of faces, it is advisable to set max faces to 3 to speed up extraction. 0 - unlimited" ) if image_size is None: image_size = io.input_int( f"Image size", 512 if face_type < FaceType.HEAD else 768, valid_range=[256, 2048], help_message= "Output image size. The higher image size, the worse face-enhancer works. Use higher than 512 value only if the source image is sharp enough and the face does not need to be enhanced." ) if jpeg_quality is None: jpeg_quality = io.input_int( f"Jpeg quality", 90, valid_range=[1, 100], help_message= "Jpeg quality. The higher jpeg quality the larger the output file size." ) if detector is None: io.log_info("Choose detector type.") io.log_info("[0] S3FD") io.log_info("[1] manual") detector = {0: 's3fd', 1: 'manual'}[io.input_int("", 0, [0, 1])] if output_debug is None: output_debug = io.input_bool( f"Write debug images to {output_debug_path.name}?", False) if output_debug: output_debug_path.mkdir(parents=True, exist_ok=True) if manual_output_debug_fix: if not output_debug_path.exists(): io.log_err( f'{output_debug_path} not found. Re-extract faces with "Write debug images" option.' ) return else: detector = 'manual' io.log_info( 'Performing re-extract frames which were deleted from _debug directory.' ) input_image_paths = DeletedFilesSearcherSubprocessor( input_image_paths, pathex.get_image_paths(output_debug_path)).run() input_image_paths = sorted(input_image_paths) io.log_info('Found %d images.' % (len(input_image_paths))) else: if not continue_extraction and output_debug_path.exists(): for filename in pathex.get_image_paths(output_debug_path): Path(filename).unlink() images_found = len(input_image_paths) faces_detected = 0 if images_found != 0: if detector == 'manual': io.log_info('Performing manual extract...') data = ExtractSubprocessor( [ ExtractSubprocessor.Data(Path(filename)) for filename in input_image_paths ], 'landmarks-manual', image_size, jpeg_quality, face_type, output_debug_path if output_debug else None, manual_window_size=manual_window_size, device_config=device_config).run() io.log_info('Performing 3rd pass...') data = ExtractSubprocessor( data, 'final', image_size, jpeg_quality, face_type, output_debug_path if output_debug else None, final_output_path=output_path, device_config=device_config).run() else: io.log_info('Extracting faces...') data = ExtractSubprocessor( [ ExtractSubprocessor.Data(Path(filename)) for filename in input_image_paths ], 'all', image_size, jpeg_quality, face_type, output_debug_path if output_debug else None, max_faces_from_image=max_faces_from_image, final_output_path=output_path, device_config=device_config).run() faces_detected += sum([d.faces_detected for d in data]) if manual_fix: if all(np.array([d.faces_detected > 0 for d in data]) == True): io.log_info('All faces are detected, manual fix not needed.') else: fix_data = [ ExtractSubprocessor.Data(d.filepath) for d in data if d.faces_detected == 0 ] io.log_info('Performing manual fix for %d images...' % (len(fix_data))) fix_data = ExtractSubprocessor( fix_data, 'landmarks-manual', image_size, jpeg_quality, face_type, output_debug_path if output_debug else None, manual_window_size=manual_window_size, device_config=device_config).run() fix_data = ExtractSubprocessor( fix_data, 'final', image_size, jpeg_quality, face_type, output_debug_path if output_debug else None, final_output_path=output_path, device_config=device_config).run() faces_detected += sum([d.faces_detected for d in fix_data]) io.log_info('-------------------------') io.log_info('Images found: %d' % (images_found)) io.log_info('Faces detected: %d' % (faces_detected)) io.log_info('-------------------------')
def dev_test1(input_dir): # LaPa dataset image_size = 1024 face_type = FaceType.HEAD input_path = Path(input_dir) images_path = input_path / 'images' if not images_path.exists: raise ValueError('LaPa dataset: images folder not found.') labels_path = input_path / 'labels' if not labels_path.exists: raise ValueError('LaPa dataset: labels folder not found.') landmarks_path = input_path / 'landmarks' if not landmarks_path.exists: raise ValueError('LaPa dataset: landmarks folder not found.') output_path = input_path / 'out' if output_path.exists(): output_images_paths = pathex.get_image_paths(output_path) if len(output_images_paths) != 0: io.input(f"\n WARNING !!! \n {output_path} contains files! \n They will be deleted. \n Press enter to continue.\n") for filename in output_images_paths: Path(filename).unlink() output_path.mkdir(parents=True, exist_ok=True) data = [] img_paths = pathex.get_image_paths (images_path) for filename in img_paths: filepath = Path(filename) landmark_filepath = landmarks_path / (filepath.stem + '.txt') if not landmark_filepath.exists(): raise ValueError(f'no landmarks for {filepath}') #img = cv2_imread(filepath) lm = landmark_filepath.read_text() lm = lm.split('\n') if int(lm[0]) != 106: raise ValueError(f'wrong landmarks format in {landmark_filepath}') lmrks = [] for i in range(106): x,y = lm[i+1].split(' ') x,y = float(x), float(y) lmrks.append ( (x,y) ) lmrks = np.array(lmrks) l,t = np.min(lmrks, 0) r,b = np.max(lmrks, 0) l,t,r,b = ( int(x) for x in (l,t,r,b) ) #for x, y in lmrks: # x,y = int(x), int(y) # cv2.circle(img, (x, y), 1, (0,255,0) , 1, lineType=cv2.LINE_AA) #imagelib.draw_rect(img, (l,t,r,b), (0,255,0) ) data += [ ExtractSubprocessor.Data(filepath=filepath, rects=[ (l,t,r,b) ]) ] #cv2.imshow("", img) #cv2.waitKey(0) if len(data) > 0: device_config = nn.DeviceConfig.BestGPU() io.log_info ("Performing 2nd pass...") data = ExtractSubprocessor (data, 'landmarks', image_size, 95, face_type, device_config=device_config).run() io.log_info ("Performing 3rd pass...") data = ExtractSubprocessor (data, 'final', image_size, 95, face_type, final_output_path=output_path, device_config=device_config).run() for filename in pathex.get_image_paths (output_path): filepath = Path(filename) dflimg = DFLJPG.load(filepath) src_filename = dflimg.get_source_filename() image_to_face_mat = dflimg.get_image_to_face_mat() label_filepath = labels_path / ( Path(src_filename).stem + '.png') if not label_filepath.exists(): raise ValueError(f'{label_filepath} does not exist') mask = cv2_imread(label_filepath) #mask[mask == 10] = 0 # remove hair mask[mask > 0] = 1 mask = cv2.warpAffine(mask, image_to_face_mat, (image_size, image_size), cv2.INTER_LINEAR) mask = cv2.blur(mask, (3,3) ) #cv2.imshow("", (mask*255).astype(np.uint8) ) #cv2.waitKey(0) dflimg.set_xseg_mask(mask) dflimg.save() import code code.interact(local=dict(globals(), **locals()))