From a7c6b2fd3e3d4683836a861e34e97d4e7bc5e31b Mon Sep 17 00:00:00 2001 From: Jeremy Hummel Date: Sat, 10 Aug 2019 13:22:13 -0700 Subject: [PATCH 1/6] Extract as aligned faces as PNG --- mainscripts/Extractor.py | 102 +++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/mainscripts/Extractor.py b/mainscripts/Extractor.py index bb9873a..8dc005e 100644 --- a/mainscripts/Extractor.py +++ b/mainscripts/Extractor.py @@ -82,12 +82,12 @@ class ExtractSubprocessor(Subprocessor): self.second_pass_e.__enter__() else: self.second_pass_e = None - + elif self.type == 'fanseg': nnlib.import_all (device_config) self.e = facelib.FANSegmentator(256, FaceType.toString(FaceType.FULL) ) self.e.__enter__() - + elif self.type == 'final': pass @@ -135,7 +135,7 @@ class ExtractSubprocessor(Subprocessor): if filename_path.suffix == '.png': src_dflimg = DFLPNG.load ( str(filename_path) ) if filename_path.suffix == '.jpg': - src_dflimg = DFLJPG.load ( str(filename_path) ) + src_dflimg = DFLPNG.load ( str(filename_path) ) if 'rects' in self.type: if min(w,h) < 128: @@ -217,7 +217,7 @@ class ExtractSubprocessor(Subprocessor): if src_dflimg is not None and face_idx > 1: #cannot extract more than 1 face from dflimg break - + if image_landmarks is None: continue @@ -248,17 +248,17 @@ class ExtractSubprocessor(Subprocessor): if str(filename_path) != str(output_file): shutil.copy ( str(filename_path), str(output_file) ) else: - output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.jpg') - cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_JPEG_QUALITY), 85] ) + output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.png') + cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0] ) - DFLJPG.embed_data(output_file, face_type=FaceType.toString(self.face_type), - landmarks=face_image_landmarks.tolist(), - source_filename=filename_path.name, - source_rect=rect, - source_landmarks=image_landmarks.tolist(), - image_to_face_mat=image_to_face_mat, - pitch_yaw_roll=data.pitch_yaw_roll - ) + DFLPNG.embed_data(output_file, face_type=FaceType.toString(self.face_type), + landmarks=face_image_landmarks.tolist(), + source_filename=filename_path.name, + source_rect=rect, + source_landmarks=image_landmarks.tolist(), + image_to_face_mat=image_to_face_mat, + pitch_yaw_roll=data.pitch_yaw_roll + ) data.final_output_files.append (output_file) face_idx += 1 @@ -268,15 +268,15 @@ class ExtractSubprocessor(Subprocessor): cv2_imwrite(debug_output_file, debug_image, [int(cv2.IMWRITE_JPEG_QUALITY), 50] ) return data - + elif self.type == 'fanseg': if src_dflimg is not None: fanseg_mask = self.e.extract( image / 255.0 ) - src_dflimg.embed_and_set( filename_path_str, + src_dflimg.embed_and_set( filename_path_str, fanseg_mask=fanseg_mask, #fanseg_mask_ver=FANSegmentator.VERSION, ) - + #overridable def get_data_name (self, data): #return string identificator of your data @@ -401,13 +401,13 @@ class ExtractSubprocessor(Subprocessor): self.text_lines_img = self.cache_text_lines_img[1] else: self.text_lines_img = (imagelib.get_draw_text_lines ( self.image, sh, - [ '[Mouse click] - lock/unlock selection', - '[Mouse wheel] - change rect', - '[Enter] / [Space] - confirm / skip frame', - '[,] [.]- prev frame, next frame. [Q] - skip remaining frames', - '[a] - accuracy on/off (more fps)', - '[h] - hide this help' - ], (1, 1, 1) )*255).astype(np.uint8) + [ '[Mouse click] - lock/unlock selection', + '[Mouse wheel] - change rect', + '[Enter] / [Space] - confirm / skip frame', + '[,] [.]- prev frame, next frame. [Q] - skip remaining frames', + '[a] - accuracy on/off (more fps)', + '[h] - hide this help' + ], (1, 1, 1) )*255).astype(np.uint8) self.cache_text_lines_img = (sh, self.text_lines_img) @@ -494,10 +494,10 @@ class ExtractSubprocessor(Subprocessor): break if self.x != new_x or \ - self.y != new_y or \ - self.rect_size != new_rect_size or \ - self.extract_needed or \ - redraw_needed: + self.y != new_y or \ + self.rect_size != new_rect_size or \ + self.extract_needed or \ + redraw_needed: self.x = new_x self.y = new_y self.rect_size = new_rect_size @@ -684,11 +684,11 @@ class DeletedFilesSearcherSubprocessor(Subprocessor): def extract_fanseg(input_dir, device_args={} ): multi_gpu = device_args.get('multi_gpu', False) cpu_only = device_args.get('cpu_only', False) - + input_path = Path(input_dir) if not input_path.exists(): raise ValueError('Input directory not found. Please ensure it exists.') - + paths_to_extract = [] for filename in Path_utils.get_image_paths(input_path) : filepath = Path(filename) @@ -701,31 +701,31 @@ def extract_fanseg(input_dir, device_args={} ): if dflimg is not None: paths_to_extract.append (filepath) - + paths_to_extract_len = len(paths_to_extract) if paths_to_extract_len > 0: io.log_info ("Performing extract fanseg for %d files..." % (paths_to_extract_len) ) data = ExtractSubprocessor ([ ExtractSubprocessor.Data(filename) for filename in paths_to_extract ], 'fanseg', multi_gpu=multi_gpu, cpu_only=cpu_only).run() -def extract_umd_csv(input_file_csv, +def extract_umd_csv(input_file_csv, image_size=256, face_type='full_face', device_args={} ): - + #extract faces from umdfaces.io dataset csv file with pitch,yaw,roll info. multi_gpu = device_args.get('multi_gpu', False) cpu_only = device_args.get('cpu_only', False) face_type = FaceType.fromString(face_type) - + input_file_csv_path = Path(input_file_csv) if not input_file_csv_path.exists(): raise ValueError('input_file_csv not found. Please ensure it exists.') - + input_file_csv_root_path = input_file_csv_path.parent output_path = input_file_csv_path.parent / ('aligned_' + input_file_csv_path.name) - + io.log_info("Output dir is %s." % (str(output_path)) ) - + if output_path.exists(): output_images_paths = Path_utils.get_image_paths(output_path) if len(output_images_paths) > 0: @@ -734,15 +734,15 @@ def extract_umd_csv(input_file_csv, Path(filename).unlink() else: output_path.mkdir(parents=True, exist_ok=True) - + try: with open( str(input_file_csv_path), 'r') as f: csv_file = f.read() except Exception as e: io.log_err("Unable to open or read file " + str(input_file_csv_path) + ": " + str(e) ) return - - strings = csv_file.split('\n') + + strings = csv_file.split('\n') keys = strings[0].split(',') keys_len = len(keys) csv_data = [] @@ -751,39 +751,39 @@ def extract_umd_csv(input_file_csv, if keys_len != len(values): io.log_err("Wrong string in csv file, skipping.") continue - + csv_data += [ { keys[n] : values[n] for n in range(keys_len) } ] - + data = [] for d in csv_data: filename = input_file_csv_root_path / d['FILE'] - - pitch, yaw, roll = float(d['PITCH']), float(d['YAW']), float(d['ROLL']) + + pitch, yaw, roll = float(d['PITCH']), float(d['YAW']), float(d['ROLL']) if pitch < -90 or pitch > 90 or yaw < -90 or yaw > 90 or roll < -90 or roll > 90: continue - + pitch_yaw_roll = pitch/90.0, yaw/90.0, roll/90.0 - + x,y,w,h = float(d['FACE_X']), float(d['FACE_Y']), float(d['FACE_WIDTH']), float(d['FACE_HEIGHT']) data += [ ExtractSubprocessor.Data(filename=filename, rects=[ [x,y,x+w,y+h] ], pitch_yaw_roll=pitch_yaw_roll) ] - + images_found = len(data) faces_detected = 0 if len(data) > 0: io.log_info ("Performing 2nd pass from csv file...") data = ExtractSubprocessor (data, 'landmarks', multi_gpu=multi_gpu, cpu_only=cpu_only).run() - + io.log_info ('Performing 3rd pass...') data = ExtractSubprocessor (data, 'final', image_size, face_type, None, multi_gpu=multi_gpu, cpu_only=cpu_only, manual=False, final_output_path=output_path).run() faces_detected += sum([d.faces_detected for d in data]) - - + + io.log_info ('-------------------------') io.log_info ('Images found: %d' % (images_found) ) io.log_info ('Faces detected: %d' % (faces_detected) ) io.log_info ('-------------------------') - + def main(input_dir, output_dir, debug_dir=None, From 5d91470e3ddb4da7d6d6fb44d355593dc37a6a5b Mon Sep 17 00:00:00 2001 From: Brigham Lysenko Date: Sun, 11 Aug 2019 15:32:41 -0600 Subject: [PATCH 2/6] Added conditional type extraction --- mainscripts/Extractor.py | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/mainscripts/Extractor.py b/mainscripts/Extractor.py index 8dc005e..f46613e 100644 --- a/mainscripts/Extractor.py +++ b/mainscripts/Extractor.py @@ -242,23 +242,35 @@ class ExtractSubprocessor(Subprocessor): if self.debug_dir is not None: LandmarksProcessor.draw_rect_landmarks (debug_image, rect, image_landmarks, self.image_size, self.face_type, transparent_mask=True) - if src_dflimg is not None and filename_path.suffix == '.jpg': - #if extracting from dflimg and jpg copy it in order not to lose quality - output_file = str(self.final_output_path / filename_path.name) + if filename_path.suffix == '.jpg': + print(filename_path.suffix + 'is a jpeg') + # if extracting from dflimg and jpg copy it in order not to lose quality + output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), + str(face_idx), '.jpg') if str(filename_path) != str(output_file): - shutil.copy ( str(filename_path), str(output_file) ) + shutil.copy(str(filename_path), str(output_file)) + cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_JPEG_QUALITY), 85]) + DFLJPG.embed_data(output_file, face_type=FaceType.toString(self.face_type), + landmarks=face_image_landmarks.tolist(), + source_filename=filename_path.name, + source_rect=rect, + source_landmarks=image_landmarks.tolist(), + image_to_face_mat=image_to_face_mat, + pitch_yaw_roll=data.pitch_yaw_roll + ) else: - output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.png') - cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0] ) - - DFLPNG.embed_data(output_file, face_type=FaceType.toString(self.face_type), - landmarks=face_image_landmarks.tolist(), - source_filename=filename_path.name, - source_rect=rect, - source_landmarks=image_landmarks.tolist(), - image_to_face_mat=image_to_face_mat, - pitch_yaw_roll=data.pitch_yaw_roll - ) + print(filename_path.suffix + 'is a png') + output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), + str(face_idx), '.png') + cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0]) + DFLPNG.embed_data(output_file, face_type=FaceType.toString(self.face_type), + landmarks=face_image_landmarks.tolist(), + source_filename=filename_path.name, + source_rect=rect, + source_landmarks=image_landmarks.tolist(), + image_to_face_mat=image_to_face_mat, + pitch_yaw_roll=data.pitch_yaw_roll + ) data.final_output_files.append (output_file) face_idx += 1 From e32c7a963fc9b742608f1264b25cbdb163ffd865 Mon Sep 17 00:00:00 2001 From: Brigham Lysenko Date: Sun, 11 Aug 2019 15:35:57 -0600 Subject: [PATCH 3/6] fixed typo --- mainscripts/Extractor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainscripts/Extractor.py b/mainscripts/Extractor.py index f46613e..da666a2 100644 --- a/mainscripts/Extractor.py +++ b/mainscripts/Extractor.py @@ -243,7 +243,7 @@ class ExtractSubprocessor(Subprocessor): LandmarksProcessor.draw_rect_landmarks (debug_image, rect, image_landmarks, self.image_size, self.face_type, transparent_mask=True) if filename_path.suffix == '.jpg': - print(filename_path.suffix + 'is a jpeg') + # if extracting from dflimg and jpg copy it in order not to lose quality output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.jpg') @@ -259,7 +259,7 @@ class ExtractSubprocessor(Subprocessor): pitch_yaw_roll=data.pitch_yaw_roll ) else: - print(filename_path.suffix + 'is a png') + output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.png') cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0]) From 75e50cbc5ba23cf23a4fb2826b078a08d7211535 Mon Sep 17 00:00:00 2001 From: Brigham Lysenko Date: Mon, 12 Aug 2019 15:52:23 -0600 Subject: [PATCH 4/6] fixed png loading --- mainscripts/Extractor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mainscripts/Extractor.py b/mainscripts/Extractor.py index da666a2..13e79b0 100644 --- a/mainscripts/Extractor.py +++ b/mainscripts/Extractor.py @@ -135,7 +135,7 @@ class ExtractSubprocessor(Subprocessor): if filename_path.suffix == '.png': src_dflimg = DFLPNG.load ( str(filename_path) ) if filename_path.suffix == '.jpg': - src_dflimg = DFLPNG.load ( str(filename_path) ) + src_dflimg = DFLJPG.load ( str(filename_path) ) if 'rects' in self.type: if min(w,h) < 128: @@ -249,7 +249,7 @@ class ExtractSubprocessor(Subprocessor): str(face_idx), '.jpg') if str(filename_path) != str(output_file): shutil.copy(str(filename_path), str(output_file)) - cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_JPEG_QUALITY), 85]) + cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_JPEG_QUALITY), 95]) DFLJPG.embed_data(output_file, face_type=FaceType.toString(self.face_type), landmarks=face_image_landmarks.tolist(), source_filename=filename_path.name, @@ -262,7 +262,7 @@ class ExtractSubprocessor(Subprocessor): output_file = '{}_{}{}'.format(str(self.final_output_path / filename_path.stem), str(face_idx), '.png') - cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0]) + cv2_imwrite(output_file, face_image, [int(cv2.IMWRITE_PNG_COMPRESSION), 3]) DFLPNG.embed_data(output_file, face_type=FaceType.toString(self.face_type), landmarks=face_image_landmarks.tolist(), source_filename=filename_path.name, From 1fa0a0c7390767c7a36df8aec10a4800e2965196 Mon Sep 17 00:00:00 2001 From: Brigham Lysenko Date: Mon, 12 Aug 2019 16:21:05 -0600 Subject: [PATCH 5/6] Removed flip restrictions --- models/ModelBase.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/models/ModelBase.py b/models/ModelBase.py index 25757b3..ef7836e 100644 --- a/models/ModelBase.py +++ b/models/ModelBase.py @@ -129,10 +129,7 @@ class ModelBase(object): self.options['sort_by_yaw'] = self.options.get('sort_by_yaw', False) if ask_random_flip: - if (self.iter == 0): self.options['random_flip'] = io.input_bool("Flip faces randomly? (y/n ?:help skip:y) : ", True, help_message="Predicted face will look more naturally without this option, but src faceset should cover all face directions as dst faceset.") - else: - self.options['random_flip'] = self.options.get('random_flip', True) if ask_src_scale_mod: if (self.iter == 0): From 7c205f0166849e2b461ed4501dbce23c223466e5 Mon Sep 17 00:00:00 2001 From: Brigham Lysenko Date: Mon, 12 Aug 2019 16:24:32 -0600 Subject: [PATCH 6/6] Gave prompt patience --- models/ModelBase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/ModelBase.py b/models/ModelBase.py index ef7836e..412b9eb 100644 --- a/models/ModelBase.py +++ b/models/ModelBase.py @@ -128,7 +128,7 @@ class ModelBase(object): else: self.options['sort_by_yaw'] = self.options.get('sort_by_yaw', False) - if ask_random_flip: + if ask_override: self.options['random_flip'] = io.input_bool("Flip faces randomly? (y/n ?:help skip:y) : ", True, help_message="Predicted face will look more naturally without this option, but src faceset should cover all face directions as dst faceset.") if ask_src_scale_mod: