예제 #1
0
    def __init__(self,  predictor_func,
                        predictor_input_size=0,
                        predictor_masked=True,
                        face_type=FaceType.FULL,
                        default_mode = 4,
                        base_erode_mask_modifier = 0,
                        base_blur_mask_modifier = 0,
                        default_erode_mask_modifier = 0,
                        default_blur_mask_modifier = 0,
                        clip_hborder_mask_per = 0,
                        force_mask_mode=-1):

        super().__init__(predictor_func, Converter.TYPE_FACE)

        #dummy predict and sleep, tensorflow caching kernels. If remove it, conversion speed will be x2 slower
        predictor_func ( np.zeros ( (predictor_input_size,predictor_input_size,3), dtype=np.float32 ) )
        time.sleep(2)

        predictor_func_host, predictor_func = SubprocessFunctionCaller.make_pair(predictor_func)
        self.predictor_func_host = AntiPickler(predictor_func_host)
        self.predictor_func = predictor_func

        self.predictor_masked = predictor_masked
        self.predictor_input_size = predictor_input_size
        self.face_type = face_type
        self.clip_hborder_mask_per = clip_hborder_mask_per

        mode = io.input_int ("Choose mode: (1) overlay, (2) hist match, (3) hist match bw, (4) seamless, (5) raw. Default - %d : " % (default_mode) , default_mode)

        mode_dict = {1:'overlay',
                     2:'hist-match',
                     3:'hist-match-bw',
                     4:'seamless',
                     5:'raw'}

        self.mode = mode_dict.get (mode, mode_dict[default_mode] )

        if self.mode == 'raw':
            mode = io.input_int ("Choose raw mode: (1) rgb, (2) rgb+mask (default), (3) mask only, (4) predicted only : ", 2)
            self.raw_mode = {1:'rgb',
                             2:'rgb-mask',
                             3:'mask-only',
                             4:'predicted-only'}.get (mode, 'rgb-mask')

        if self.mode != 'raw':

            if self.mode == 'seamless':
                if io.input_bool("Seamless hist match? (y/n skip:n) : ", False):
                    self.mode = 'seamless-hist-match'

            if self.mode == 'hist-match' or self.mode == 'hist-match-bw':
                self.masked_hist_match = io.input_bool("Masked hist match? (y/n skip:y) : ", True)

            if self.mode == 'hist-match' or self.mode == 'hist-match-bw' or self.mode == 'seamless-hist-match':
                self.hist_match_threshold = np.clip ( io.input_int("Hist match threshold [0..255] (skip:255) :  ", 255), 0, 255)

        if force_mask_mode != -1:
            self.mask_mode = force_mask_mode
        else:
            if face_type == FaceType.FULL:
                self.mask_mode = np.clip ( io.input_int ("Mask mode: (1) learned, (2) dst, (3) FAN-prd, (4) FAN-dst , (5) FAN-prd*FAN-dst (6) learned*FAN-prd*FAN-dst (?) help. Default - %d : " % (1) , 1, help_message="If you learned mask, then option 1 should be choosed. 'dst' mask is raw shaky mask from dst aligned images. 'FAN-prd' - using super smooth mask by pretrained FAN-model from predicted face. 'FAN-dst' - using super smooth mask by pretrained FAN-model from dst face. 'FAN-prd*FAN-dst' or 'learned*FAN-prd*FAN-dst' - using multiplied masks."), 1, 6 )
            else:
                self.mask_mode = np.clip ( io.input_int ("Mask mode: (1) learned, (2) dst . Default - %d : " % (1) , 1), 1, 2 )

        if self.mode != 'raw':
            self.erode_mask_modifier = base_erode_mask_modifier + np.clip ( io.input_int ("Choose erode mask modifier [-200..200] (skip:%d) : " % (default_erode_mask_modifier), default_erode_mask_modifier), -200, 200)
            self.blur_mask_modifier = base_blur_mask_modifier + np.clip ( io.input_int ("Choose blur mask modifier [-200..200] (skip:%d) : " % (default_blur_mask_modifier), default_blur_mask_modifier), -200, 200)

        self.output_face_scale = np.clip ( 1.0 + io.input_int ("Choose output face scale modifier [-50..50] (skip:0) : ", 0)*0.01, 0.5, 1.5)

        if self.mode != 'raw':
            self.color_transfer_mode = io.input_str ("Apply color transfer to predicted face? Choose mode ( rct/lct skip:None ) : ", None, ['rct','lct'])

        self.super_resolution = io.input_bool("Apply super resolution? (y/n ?:help skip:n) : ", False, help_message="Enhance details by applying DCSCN network.")

        if self.mode != 'raw':
            self.final_image_color_degrade_power = np.clip (  io.input_int ("Degrade color power of final image [0..100] (skip:0) : ", 0), 0, 100)
            self.alpha = io.input_bool("Export png with alpha channel? (y/n skip:n) : ", False)

        io.log_info ("")

        if self.super_resolution:
            host_proc, dc_upscale = SubprocessFunctionCaller.make_pair( imagelib.DCSCN().upscale )
            self.dc_host = AntiPickler(host_proc)
            self.dc_upscale = dc_upscale
        else:
            self.dc_host = None

        if (self.mask_mode >= 3 and self.mask_mode <= 6):
            host_proc, fan_seg_extract = SubprocessFunctionCaller.make_pair( FANSegmentator(256, FaceType.toString( self.face_type ) ).extract )
            self.fan_seg_host = AntiPickler(host_proc)
            self.fan_seg_extract = fan_seg_extract
        else:
            self.fan_seg_host = None
예제 #2
0
        def process_data(self, data):
            filename_path = Path(data[0])

            filename_path_str = str(filename_path)
            if self.cached_image[0] == filename_path_str:
                image = self.cached_image[1]
            else:
                image = cv2_imread(filename_path_str)
                self.cached_image = (filename_path_str, image)

            if image is None:
                self.log_err(
                    'Failed to extract %s, reason: cv2_imread() fail.' %
                    (str(filename_path)))
            else:
                if self.type == 'rects':
                    rects = self.e.extract_from_bgr(image)
                    return [str(filename_path), rects]

                elif self.type == 'landmarks':
                    rects = data[1]
                    landmarks = self.e.extract_from_bgr(image, rects)
                    return [str(filename_path), landmarks]

                elif self.type == 'final':
                    src_dflimg = None
                    (h, w, c) = image.shape
                    if h == w:
                        #extracting from already extracted jpg image?
                        if filename_path.suffix == '.jpg':
                            src_dflimg = DFLJPG.load(str(filename_path))

                    result = []
                    faces = data[1]

                    if self.debug:
                        debug_output_file = '{}{}'.format(
                            str(
                                Path(str(self.output_path) + '_debug') /
                                filename_path.stem), '.jpg')
                        debug_image = image.copy()

                    for (face_idx, face) in enumerate(faces):
                        output_file = '{}_{}{}'.format(
                            str(self.output_path / filename_path.stem),
                            str(face_idx), '.jpg')

                        rect = face[0]
                        image_landmarks = np.array(face[1])

                        if self.debug:
                            LandmarksProcessor.draw_rect_landmarks(
                                debug_image, rect, image_landmarks,
                                self.image_size, self.face_type)

                        if self.face_type == FaceType.MARK_ONLY:
                            face_image = image
                            face_image_landmarks = image_landmarks
                        else:
                            image_to_face_mat = LandmarksProcessor.get_transform_mat(
                                image_landmarks, self.image_size,
                                self.face_type)
                            face_image = cv2.warpAffine(
                                image, image_to_face_mat,
                                (self.image_size, self.image_size),
                                cv2.INTER_LANCZOS4)
                            face_image_landmarks = LandmarksProcessor.transform_points(
                                image_landmarks, image_to_face_mat)

                        if src_dflimg is not None:
                            #if extracting from dflimg just copy it in order not to lose quality
                            shutil.copy(str(filename_path), str(output_file))
                        else:
                            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())

                        result.append(output_file)

                    if self.debug:
                        cv2_imwrite(debug_output_file, debug_image,
                                    [int(cv2.IMWRITE_JPEG_QUALITY), 50])

                    return result
            return None
예제 #3
0
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('-------------------------')
예제 #4
0
        def on_initialize(self, client_dict):
            self.type = client_dict['type']
            self.image_size = client_dict['image_size']
            self.face_type = client_dict['face_type']
            self.max_faces_from_image = client_dict['max_faces_from_image']
            self.device_idx = client_dict['device_idx']
            self.cpu_only = client_dict['device_type'] == 'CPU'
            self.final_output_path = Path(
                client_dict['final_output_dir']
            ) if 'final_output_dir' in client_dict.keys() else None
            self.debug_dir = client_dict['debug_dir']

            #transfer and set stdin in order to work code.interact in debug subprocess
            stdin_fd = client_dict['stdin_fd']
            if stdin_fd is not None and DEBUG:
                sys.stdin = os.fdopen(stdin_fd)

            self.cached_image = (None, None)

            self.e = None
            device_config = nnlib.DeviceConfig(cpu_only=self.cpu_only,
                                               force_gpu_idx=self.device_idx,
                                               allow_growth=True)
            self.device_vram = device_config.gpu_vram_gb[0]

            intro_str = 'Running on %s.' % (client_dict['device_name'])
            if not self.cpu_only and self.device_vram <= 2:
                intro_str += " Recommended to close all programs using this device."

            self.log_info(intro_str)

            if 'rects' in self.type:
                if self.type == 'rects-mt':
                    nnlib.import_all(device_config)
                    self.e = facelib.MTCExtractor()
                elif self.type == 'rects-dlib':
                    nnlib.import_dlib(device_config)
                    self.e = facelib.DLIBExtractor(nnlib.dlib)
                elif self.type == 'rects-s3fd':
                    nnlib.import_all(device_config)
                    self.e = facelib.S3FDExtractor(do_dummy_predict=True)
                else:
                    raise ValueError("Wrong type.")

                if self.e is not None:
                    self.e.__enter__()

            elif self.type == 'landmarks':
                nnlib.import_all(device_config)
                self.e = facelib.FANExtractor()
                self.e.__enter__()
                if self.device_vram >= 2:
                    self.second_pass_e = facelib.S3FDExtractor(
                        do_dummy_predict=False)
                    self.second_pass_e.__enter__()
                else:
                    self.second_pass_e = None

            elif self.type == 'fanseg':
                nnlib.import_all(device_config)
                self.e = TernausNet(256, FaceType.toString(FaceType.FULL))
                self.e.__enter__()

            elif self.type == 'final':
                pass
예제 #5
0
def apply_xseg(input_path, model_path):
    if not input_path.exists():
        raise ValueError(f'{input_path} not found. Please ensure it exists.')

    if not model_path.exists():
        raise ValueError(f'{model_path} not found. Please ensure it exists.')
        
    face_type = None
    
    model_dat = model_path / 'XSeg_data.dat'
    if model_dat.exists():
        dat = pickle.loads( model_dat.read_bytes() )
        dat_options = dat.get('options', None)
        if dat_options is not None:
            face_type = dat_options.get('face_type', None)
        
        
        
    if face_type is None:
        face_type = io.input_str ("XSeg model face type", 'same', ['h','mf','f','wf','head','same'], help_message="Specify face type of trained XSeg model. For example if XSeg model trained as WF, but faceset is HEAD, specify WF to apply xseg only on WF part of HEAD. Default is 'same'").lower()
        if face_type == 'same':
            face_type = None
    
    if face_type is not None:
        face_type = {'h'  : FaceType.HALF,
                     'mf' : FaceType.MID_FULL,
                     'f'  : FaceType.FULL,
                     'wf' : FaceType.WHOLE_FACE,
                     'head' : FaceType.HEAD}[face_type]
                     
    io.log_info(f'Applying trained XSeg model to {input_path.name}/ folder.')

    device_config = nn.DeviceConfig.ask_choose_device(choose_only_one=True)
    nn.initialize(device_config)
        
    
    
    xseg = XSegNet(name='XSeg', 
                    load_weights=True,
                    weights_file_root=model_path,
                    data_format=nn.data_format,
                    raise_on_no_model_files=True)
    xseg_res = xseg.get_resolution()
              
    images_paths = pathex.get_image_paths(input_path, return_Path_class=True)
    
    for filepath in io.progress_bar_generator(images_paths, "Processing"):
        dflimg = DFLIMG.load(filepath)
        if dflimg is None or not dflimg.has_data():
            io.log_info(f'{filepath} is not a DFLIMG')
            continue
        
        img = cv2_imread(filepath).astype(np.float32) / 255.0
        h,w,c = img.shape
        
        img_face_type = FaceType.fromString( dflimg.get_face_type() )
        if face_type is not None and img_face_type != face_type:
            lmrks = dflimg.get_source_landmarks()
            
            fmat = LandmarksProcessor.get_transform_mat(lmrks, w, face_type)
            imat = LandmarksProcessor.get_transform_mat(lmrks, w, img_face_type)
            
            g_p = LandmarksProcessor.transform_points (np.float32([(0,0),(w,0),(0,w) ]), fmat, True)
            g_p2 = LandmarksProcessor.transform_points (g_p, imat)
            
            mat = cv2.getAffineTransform( g_p2, np.float32([(0,0),(w,0),(0,w) ]) )
            
            img = cv2.warpAffine(img, mat, (w, w), cv2.INTER_LANCZOS4)
            img = cv2.resize(img, (xseg_res, xseg_res), interpolation=cv2.INTER_LANCZOS4)
        else:
            if w != xseg_res:
                img = cv2.resize( img, (xseg_res,xseg_res), interpolation=cv2.INTER_LANCZOS4 )    
                    
        if len(img.shape) == 2:
            img = img[...,None]            
    
        mask = xseg.extract(img)
        
        if face_type is not None and img_face_type != face_type:
            mask = cv2.resize(mask, (w, w), interpolation=cv2.INTER_LANCZOS4)
            mask = cv2.warpAffine( mask, mat, (w,w), np.zeros( (h,w,c), dtype=np.float), cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4)
            mask = cv2.resize(mask, (xseg_res, xseg_res), interpolation=cv2.INTER_LANCZOS4)
        mask[mask < 0.5]=0
        mask[mask >= 0.5]=1    
        dflimg.set_xseg_mask(mask)
        dflimg.save()
예제 #6
0
def dev_test_68(input_dir ):
    # process 68 landmarks dataset with .pts files
    input_path = Path(input_dir)
    if not input_path.exists():
        raise ValueError('input_dir not found. Please ensure it exists.')

    output_path = input_path.parent / (input_path.name+'_aligned')

    io.log_info(f'Output dir is % {output_path}')

    if output_path.exists():
        output_images_paths = pathex.get_image_paths(output_path)
        if len(output_images_paths) > 0:
            io.input_bool("WARNING !!! \n %s contains files! \n They will be deleted. \n Press enter to continue." % (str(output_path)), False )
            for filename in output_images_paths:
                Path(filename).unlink()
    else:
        output_path.mkdir(parents=True, exist_ok=True)

    images_paths = pathex.get_image_paths(input_path)

    for filepath in io.progress_bar_generator(images_paths, "Processing"):
        filepath = Path(filepath)


        pts_filepath = filepath.parent / (filepath.stem+'.pts')
        if pts_filepath.exists():
            pts = pts_filepath.read_text()
            pts_lines = pts.split('\n')

            lmrk_lines = None
            for pts_line in pts_lines:
                if pts_line == '{':
                    lmrk_lines = []
                elif pts_line == '}':
                    break
                else:
                    if lmrk_lines is not None:
                        lmrk_lines.append (pts_line)

            if lmrk_lines is not None and len(lmrk_lines) == 68:
                try:
                    lmrks = [ np.array ( lmrk_line.strip().split(' ') ).astype(np.float32).tolist() for lmrk_line in lmrk_lines]
                except Exception as e:
                    print(e)
                    print(filepath)
                    continue

                rect = LandmarksProcessor.get_rect_from_landmarks(lmrks)

                output_filepath = output_path / (filepath.stem+'.jpg')

                img = cv2_imread(filepath)
                img = imagelib.normalize_channels(img, 3)
                cv2_imwrite(output_filepath, img, [int(cv2.IMWRITE_JPEG_QUALITY), 95] )

                DFLJPG.embed_data(output_filepath, face_type=FaceType.toString(FaceType.MARK_ONLY),
                                                landmarks=lmrks,
                                                source_filename=filepath.name,
                                                source_rect=rect,
                                                source_landmarks=lmrks
                                    )

    io.log_info("Done.")
예제 #7
0
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:
            io.input_bool(
                "WARNING !!! \n %s contains files! \n They will be deleted. \n Press enter to continue."
                % (str(output_path)), False)
            for filename in output_images_paths:
                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')
    keys = strings[0].split(',')
    keys_len = len(keys)
    csv_data = []
    for i in range(1, len(strings)):
        values = strings[i].split(',')
        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'])
        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('-------------------------')
예제 #8
0
    def onInitialize(self):
        exec(nnlib.import_all(), locals(), globals())
        self.set_vram_batch_requirements({1.5: 4, 11: 48})

        self.resolution = 256
        self.face_type = FaceType.FULL if self.options[
            'face_type'] == 'f' else FaceType.HALF

        model_name = 'FANSeg'
        self.fan_seg = TernausNet(model_name,
                                  self.resolution,
                                  FaceType.toString(self.face_type),
                                  load_weights=not self.is_first_run(),
                                  weights_file_root=self.get_model_root_path(),
                                  training=True)

        if self.is_training_mode:
            t = SampleProcessor.Types
            face_type = t.FACE_TYPE_FULL if self.options[
                'face_type'] == 'f' else t.FACE_TYPE_HALF

            self.set_training_data_generators([
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=[
                        {
                            'types':
                            (t.IMG_WARPED_TRANSFORMED, face_type, t.MODE_BGR),
                            'resolution':
                            self.resolution,
                            'motion_blur': (25, 5),
                            'gaussian_blur': (25, 5),
                            'border_replicate':
                            False,
                            'random_hsv_shift':
                            True
                        },
                        {
                            'types':
                            (t.IMG_WARPED_TRANSFORMED, face_type, t.MODE_M),
                            'resolution':
                            self.resolution
                        },
                    ]),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=[
                        {
                            'types':
                            (t.IMG_TRANSFORMED, face_type, t.MODE_BGR),
                            'resolution': self.resolution,
                            'random_hsv_shift': True
                        },
                    ])
            ])
예제 #9
0
    def onInitialize(self):
        exec(nnlib.import_all(), locals(), globals())
        self.set_vram_batch_requirements({4: 32})

        self.resolution = 128
        self.face_type = FaceType.FULL if self.options[
            'face_type'] == 'f' else FaceType.HALF

        self.pose_est = PoseEstimator(
            self.resolution,
            FaceType.toString(self.face_type),
            load_weights=not self.is_first_run(),
            weights_file_root=self.get_model_root_path(),
            training=True)

        if self.is_training_mode:
            t = SampleProcessor.Types
            face_type = t.FACE_TYPE_FULL if self.options[
                'face_type'] == 'f' else t.FACE_TYPE_HALF

            self.set_training_data_generators([
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    generators_count=4,
                    sample_process_options=SampleProcessor.Options(
                        rotation_range=[0, 0]),  #random_flip=True,
                    output_sample_types=[{
                        'types': (t.IMG_WARPED_TRANSFORMED, face_type,
                                  t.MODE_BGR_SHUFFLE),
                        'resolution':
                        self.resolution,
                        'motion_blur': (25, 1)
                    }, {
                        'types':
                        (t.IMG_TRANSFORMED, face_type, t.MODE_BGR_SHUFFLE),
                        'resolution':
                        self.resolution
                    }, {
                        'types': (t.IMG_TRANSFORMED, face_type, t.MODE_M,
                                  t.FACE_MASK_FULL),
                        'resolution':
                        self.resolution
                    }, {
                        'types': (t.IMG_PITCH_YAW_ROLL, )
                    }]),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    generators_count=4,
                    sample_process_options=SampleProcessor.Options(
                        rotation_range=[0, 0]),  #random_flip=True,
                    output_sample_types=[{
                        'types':
                        (t.IMG_TRANSFORMED, face_type, t.MODE_BGR_SHUFFLE),
                        'resolution':
                        self.resolution
                    }, {
                        'types': (t.IMG_PITCH_YAW_ROLL, )
                    }])
            ])
예제 #10
0
    def onClientProcessData(self, data):
        filename_path = Path(data[0])

        image = cv2.imread(str(filename_path))
        if image is None:
            print('Failed to extract %s, reason: cv2.imread() fail.' %
                  (str(filename_path)))
        else:
            if self.type == 'rects':
                rects = self.e.extract_from_bgr(image)
                return [str(filename_path), rects]

            elif self.type == 'landmarks':
                rects = data[1]
                landmarks = self.e.extract_from_bgr(image, rects)
                return [str(filename_path), landmarks]

            elif self.type == 'final':
                result = []
                faces = data[1]

                if self.debug:
                    debug_output_file = '{}_{}'.format(
                        str(
                            Path(str(self.output_path) + '_debug') /
                            filename_path.stem), 'debug.png')
                    debug_image = image.copy()

                for (face_idx, face) in enumerate(faces):
                    output_file = '{}_{}{}'.format(
                        str(self.output_path / filename_path.stem),
                        str(face_idx), '.png')

                    rect = face[0]
                    image_landmarks = np.array(face[1])

                    if self.debug:
                        facelib.LandmarksProcessor.draw_rect_landmarks(
                            debug_image, rect, image_landmarks,
                            self.image_size, self.face_type)

                    if self.face_type == FaceType.MARK_ONLY:
                        face_image = image
                        face_image_landmarks = image_landmarks
                    else:
                        image_to_face_mat = facelib.LandmarksProcessor.get_transform_mat(
                            image_landmarks, self.image_size, self.face_type)
                        face_image = cv2.warpAffine(
                            image, image_to_face_mat,
                            (self.image_size, self.image_size),
                            cv2.INTER_LANCZOS4)
                        face_image_landmarks = facelib.LandmarksProcessor.transform_points(
                            image_landmarks, image_to_face_mat)

                    cv2.imwrite(output_file, face_image)

                    a_png = AlignedPNG.load(output_file)

                    d = {
                        'face_type':
                        FaceType.toString(self.face_type),
                        'landmarks':
                        face_image_landmarks.tolist(),
                        'yaw_value':
                        facelib.LandmarksProcessor.calc_face_yaw(
                            face_image_landmarks),
                        'pitch_value':
                        facelib.LandmarksProcessor.calc_face_pitch(
                            face_image_landmarks),
                        'source_filename':
                        filename_path.name,
                        'source_rect':
                        rect,
                        'source_landmarks':
                        image_landmarks.tolist()
                    }
                    a_png.setFaceswapDictData(d)
                    a_png.save(output_file)

                    result.append(output_file)

                if self.debug:
                    cv2.imwrite(debug_output_file, debug_image)

                return result
        return None
예제 #11
0
    def onInitialize(self, batch_size=-1, **in_options):
        exec(nnlib.code_import_all, locals(), globals())
        self.set_vram_batch_requirements({2: 1, 3: 1, 4: 4, 5: 8, 6: 16})

        resolution = self.options['resolution']
        face_type = self.face_type = FaceType.FULL if self.options[
            'face_type'] == 'f' else FaceType.HALF

        self.model = FUNIT(face_type_str=FaceType.toString(face_type),
                           batch_size=self.batch_size,
                           encoder_nf=64,
                           encoder_downs=2,
                           encoder_res_blk=2,
                           class_downs=4,
                           class_nf=64,
                           class_latent=64,
                           mlp_nf=256,
                           mlp_blks=2,
                           dis_nf=64,
                           dis_res_blks=10,
                           num_classes=2,
                           subpixel_decoder=True,
                           initialize_weights=self.is_first_run(),
                           is_training=self.is_training_mode,
                           tf_cpu_mode=self.options['optimizer_mode'] - 1)

        if not self.is_first_run():
            self.load_weights_safe(self.model.get_model_filename_list())

        t = SampleProcessor.Types
        face_type = t.FACE_TYPE_FULL if self.options[
            'face_type'] == 'f' else t.FACE_TYPE_HALF
        if self.is_training_mode:

            output_sample_types = [
                {
                    'types': (t.IMG_TRANSFORMED, face_type, t.MODE_BGR),
                    'resolution': resolution,
                    'normalize_tanh': True
                },
            ]

            self.set_training_data_generators([
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types)
            ])
        else:
            generator = SampleGeneratorFace(
                self.training_data_src_path,
                batch_size=1,
                sample_process_options=SampleProcessor.Options(),
                output_sample_types=[{
                    'types': (t.IMG_SOURCE, face_type, t.MODE_BGR),
                    'resolution':
                    resolution,
                    'normalize_tanh':
                    True
                }])

            io.log_info("Calculating average src face style...")
            codes = []
            for i in io.progress_bar_generator(
                    range(generator.get_total_sample_count())):
                codes += self.model.get_average_class_code(
                    generator.generate_next())

            self.average_class_code = np.mean(np.array(codes), axis=0)[None,
                                                                       ...]
예제 #12
0
def main(input_dir,
         output_dir,
         debug_dir=None,
         detector='mt',
         manual_fix=False,
         manual_output_debug_fix=False,
         manual_window_size=1368,
         image_size=256,
         face_type='full_face',
         device_args={}):

    input_path = Path(input_dir)
    output_path = Path(output_dir)
    face_type = FaceType.fromString(face_type)

    multi_gpu = device_args.get('multi_gpu', False)
    cpu_only = device_args.get('cpu_only', False)

    if not input_path.exists():
        raise ValueError('输入路径不存在,请先确认workspace目录下是否存在data_dst和data_src文件夹')

    if output_path.exists():
        if not manual_output_debug_fix and input_path != output_path:
            output_images_paths = Path_utils.get_image_paths(output_path)
            if len(output_images_paths) > 0:
                io.input_bool("警告 !!! \n %s 已经有图片了! \n 继续执行会删除之前的图片. \n 按回车[Enter]继续" % (str(output_path)), False )
                for filename in output_images_paths:
                    Path(filename).unlink()
    else:
        output_path.mkdir(parents=True, exist_ok=True)

    if manual_output_debug_fix:
        if debug_dir is None:
            raise ValueError('debug-dir must be specified')
        detector = 'manual'
        io.log_info('Performing re-extract frames which were deleted from _debug directory.')

    input_path_image_paths = Path_utils.get_image_unique_filestem_paths(input_path, verbose_print_func=io.log_info)
    if debug_dir is not None:
        debug_output_path = Path(debug_dir)

        if manual_output_debug_fix:
            if not debug_output_path.exists():
                raise ValueError("%s not found " % ( str(debug_output_path) ))

            input_path_image_paths = DeletedFilesSearcherSubprocessor (input_path_image_paths, Path_utils.get_image_paths(debug_output_path) ).run()
            input_path_image_paths = sorted (input_path_image_paths)
            io.log_info('Found %d images.' % (len(input_path_image_paths)))
        else:
            if debug_output_path.exists():
                for filename in Path_utils.get_image_paths(debug_output_path):
                    Path(filename).unlink()
            else:
                debug_output_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 ('正在启动手动提取...')
            data = ExtractSubprocessor ([ ExtractSubprocessor.Data(filename) for filename in input_path_image_paths ], 'landmarks', image_size, face_type, debug_dir, cpu_only=cpu_only, manual=True, manual_window_size=manual_window_size).run()
        else:
            io.log_info ('第一阶段...')
            data = ExtractSubprocessor ([ ExtractSubprocessor.Data(filename) for filename in input_path_image_paths ], 'rects-'+detector, image_size, face_type, debug_dir, multi_gpu=multi_gpu, cpu_only=cpu_only, manual=False).run()

            io.log_info ('第二阶段...')
            data = ExtractSubprocessor (data, 'landmarks', image_size, face_type, debug_dir, multi_gpu=multi_gpu, cpu_only=cpu_only, manual=False).run()

        io.log_info ('第三阶段...')
        data = ExtractSubprocessor (data, 'final', image_size, face_type, debug_dir, 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])

        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.filename) 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', image_size, face_type, debug_dir, manual=True, manual_window_size=manual_window_size).run()
                fix_data = ExtractSubprocessor (fix_data, 'final', image_size, face_type, debug_dir, 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 fix_data])


    io.log_info ('-------------------------')
    io.log_info ('图片数量:        %d' % (images_found) )
    io.log_info ('人脸数量:      %d' % (faces_detected) )
    io.log_info ('-------------------------')
    def onInitialize(self, batch_size=-1, **in_options):

        exec(nnlib.code_import_all, locals(), globals())
        self.set_vram_batch_requirements({4: 4})

        resolution = self.options['resolution']
        bgr_shape = (resolution, resolution, 3)
        mask_shape = (resolution, resolution, 1)
        bgrm_shape = (resolution, resolution, 4)

        ngf = 64
        ndf = 64
        lambda_A = 100
        lambda_B = 100

        use_batch_norm = True  #created_batch_size > 1

        poseest = self.poseest = PoseEstimator(
            resolution, FaceType.toString(FaceType.FULL))

        self.enc = modelify(AVATARModel.DFEncFlow())([
            Input(bgr_shape),
            Input((poseest.class_nums[0], )),
            Input((poseest.class_nums[0], )),
            Input((poseest.class_nums[0], ))
        ])
        dec_Inputs = [Input(K.int_shape(x)[1:]) for x in self.enc.outputs]
        self.decA = modelify(AVATARModel.DFDecFlow(bgr_shape[2]))(dec_Inputs)
        self.decB = modelify(AVATARModel.DFDecFlow(bgr_shape[2]))(dec_Inputs)

        def GA(x):
            return self.decA(self.enc(x))

        self.GA = GA

        def GB(x):
            return self.decB(self.enc(x))

        self.GB = GB

        #self.GA = modelify(AVATARModel.ResNet (bgr_shape[2], use_batch_norm, n_blocks=6, ngf=ngf, use_dropout=True))( Input(bgr_shape) )
        #self.GB = modelify(AVATARModel.ResNet (bgr_shape[2], use_batch_norm, n_blocks=6, ngf=ngf, use_dropout=True))( Input(bgr_shape) )

        #self.GA = modelify(UNet (bgr_shape[2], use_batch_norm, num_downs=get_power_of_two(resolution)-1, ngf=ngf, use_dropout=True))(Input(bgr_shape))
        #self.GB = modelify(UNet (bgr_shape[2], use_batch_norm, num_downs=get_power_of_two(resolution)-1, ngf=ngf, use_dropout=True))(Input(bgr_shape))

        self.DA = modelify(
            AVATARModel.NLayerDiscriminator(use_batch_norm,
                                            ndf=ndf))(Input(bgr_shape))
        self.DB = modelify(
            AVATARModel.NLayerDiscriminator(use_batch_norm,
                                            ndf=ndf))(Input(bgr_shape))

        if not self.is_first_run():
            weights_to_load = [
                # (self.GA, 'GA.h5'),
                # (self.GB, 'GB.h5'),
                (self.enc, 'enc.h5'),
                (self.decA, 'decA.h5'),
                (self.decB, 'decB.h5'),
                (self.DA, 'DA.h5'),
                (self.DB, 'DB.h5'),
            ]
            self.load_weights_safe(weights_to_load)

        real_A0 = Input(bgr_shape)
        real_A0m = Input(mask_shape)
        real_B0 = Input(bgr_shape)
        real_B0m = Input(mask_shape)

        real_A0p, real_A0y, real_A0r = poseest.flow(real_A0)
        real_B0p, real_B0y, real_B0r = poseest.flow(real_B0)

        DA_ones = K.ones_like(K.shape(self.DA.outputs[0]))
        DA_zeros = K.zeros_like(K.shape(self.DA.outputs[0]))
        DB_ones = K.ones_like(K.shape(self.DB.outputs[0]))
        DB_zeros = K.zeros_like(K.shape(self.DB.outputs[0]))

        def DLoss(labels, logits):
            return K.mean(K.binary_crossentropy(labels, logits))

        def CycleLOSS(t1, t2):
            return dssim(kernel_size=int(resolution / 11.6),
                         max_value=2.0)(t1 + 1, t2 + 1)
            return K.mean(K.abs(t1 - t2))

        fake_B0 = self.GA([real_A0, real_B0p, real_B0y, real_B0r])
        fake_A0 = self.GB([real_B0, real_A0p, real_A0y, real_A0r])

        fake_B0p, fake_B0y, fake_B0r = poseest.flow(fake_B0)
        fake_A0p, fake_A0y, fake_A0r = poseest.flow(fake_A0)

        real_A0_d = self.DA(real_A0)
        real_A0_d_ones = K.ones_like(real_A0_d)

        fake_A0_d = self.DA(fake_A0)
        fake_A0_d_ones = K.ones_like(fake_A0_d)
        fake_A0_d_zeros = K.zeros_like(fake_A0_d)

        real_B0_d = self.DB(real_B0)
        real_B0_d_ones = K.ones_like(real_B0_d)

        fake_B0_d = self.DB(fake_B0)
        fake_B0_d_ones = K.ones_like(fake_B0_d)
        fake_B0_d_zeros = K.zeros_like(fake_B0_d)

        rec_A0 = self.GB([fake_B0, real_A0p, real_A0y, real_A0r])
        rec_B0 = self.GA([fake_A0, real_B0p, real_B0y, real_B0r])

        #import code
        #code.interact(local=dict(globals(), **locals()))

        loss_GA = DLoss(fake_B0_d_ones, fake_B0_d ) + \
                  lambda_A * 0.1 * K.mean(  K.square(fake_B0p-real_A0p) + K.square(fake_B0y-real_A0y) + K.square(fake_B0r-real_A0r)  ) + \
                  lambda_A * (CycleLOSS(rec_B0, real_B0) )

        weights_GA = self.enc.trainable_weights + self.decA.trainable_weights  # + #self.GA.trainable_weights

        loss_GB = DLoss(fake_A0_d_ones, fake_A0_d ) + \
                  lambda_B * 0.1 * K.mean( K.square(fake_A0p-real_B0p) + K.square(fake_A0y-real_B0y) + K.square(fake_A0r-real_B0r) ) + \
                  lambda_B * (CycleLOSS(rec_A0, real_A0) )

        weights_GB = self.enc.trainable_weights + self.decB.trainable_weights  # + #self.GB.trainable_weights

        def opt():
            return Adam(lr=2e-5, beta_1=0.5, beta_2=0.999,
                        tf_cpu_mode=2)  #, clipnorm=1)

        self.GA_train = K.function([real_A0, real_A0m, real_B0, real_B0m],
                                   [loss_GA],
                                   opt().get_updates(loss_GA, weights_GA))

        self.GB_train = K.function([real_A0, real_A0m, real_B0, real_B0m],
                                   [loss_GB],
                                   opt().get_updates(loss_GB, weights_GB))

        ###########

        loss_D_A = ( DLoss(real_A0_d_ones, real_A0_d ) + \
                          DLoss(fake_A0_d_zeros, fake_A0_d ) ) * 0.5

        self.DA_train = K.function(
            [real_A0, real_A0m, real_B0, real_B0m], [loss_D_A],
            opt().get_updates(loss_D_A, self.DA.trainable_weights))

        ############

        loss_D_B = ( DLoss(real_B0_d_ones, real_B0_d ) + \
                         DLoss(fake_B0_d_zeros, fake_B0_d ) ) * 0.5

        self.DB_train = K.function(
            [real_A0, real_A0m, real_B0, real_B0m], [loss_D_B],
            opt().get_updates(loss_D_B, self.DB.trainable_weights))

        ############

        self.G_view = K.function([real_A0, real_A0m, real_B0, real_B0m],
                                 [fake_A0, rec_A0, fake_B0, rec_B0])

        if self.is_training_mode:
            t = SampleProcessor.Types
            face_type = t.FACE_TYPE_FULL

            output_sample_types = [
                {
                    'types': (t.IMG_SOURCE, face_type, t.MODE_BGR),
                    'resolution': resolution
                },
                {
                    'types':
                    (t.IMG_SOURCE, face_type, t.MODE_M, t.FACE_MASK_FULL),
                    'resolution': resolution
                },
            ]

            self.set_training_data_generators([
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=self.random_flip, normalize_tanh=True),
                    output_sample_types=output_sample_types),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=self.random_flip, normalize_tanh=True),
                    output_sample_types=output_sample_types)
            ])
        else:
            self.G_convert = K.function([real_A0, real_B0m], [fake_B0])
예제 #14
0
        def on_initialize(self, client_dict):
            self.type = client_dict["type"]
            self.image_size = client_dict["image_size"]
            self.face_type = client_dict["face_type"]
            self.device_idx = client_dict["device_idx"]
            self.cpu_only = client_dict["device_type"] == "CPU"
            self.final_output_path = (Path(client_dict["final_output_dir"])
                                      if "final_output_dir"
                                      in client_dict.keys() else None)
            self.debug_dir = client_dict["debug_dir"]

            # transfer and set stdin in order to work code.interact in debug subprocess
            stdin_fd = client_dict["stdin_fd"]
            if stdin_fd is not None and DEBUG:
                sys.stdin = os.fdopen(stdin_fd)

            self.cached_image = (None, None)

            self.e = None
            device_config = nnlib.DeviceConfig(cpu_only=self.cpu_only,
                                               force_gpu_idx=self.device_idx,
                                               allow_growth=True)
            self.device_vram = device_config.gpu_vram_gb[0]

            intro_str = "Running on %s." % (client_dict["device_name"])
            if not self.cpu_only and self.device_vram <= 2:
                intro_str += " Recommended to close all programs using this device."

            self.log_info(intro_str)

            if "rects" in self.type:
                if self.type == "rects-mt":
                    nnlib.import_all(device_config)
                    self.e = facelib.MTCExtractor()
                elif self.type == "rects-dlib":
                    nnlib.import_dlib(device_config)
                    self.e = facelib.DLIBExtractor(nnlib.dlib)
                elif self.type == "rects-s3fd":
                    nnlib.import_all(device_config)
                    self.e = facelib.S3FDExtractor()
                else:
                    raise ValueError("Wrong type.")

                if self.e is not None:
                    self.e.__enter__()

            elif self.type == "landmarks":
                nnlib.import_all(device_config)
                self.e = facelib.LandmarksExtractor(nnlib.keras)
                self.e.__enter__()
                if self.device_vram >= 2:
                    self.second_pass_e = facelib.S3FDExtractor()
                    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
예제 #15
0
    def onInitialize(self, batch_size=-1, **in_options):
        exec(nnlib.code_import_all, locals(), globals())
        self.set_vram_batch_requirements({4: 16})

        resolution = self.options['resolution']
        face_type = FaceType.FULL if self.options[
            'face_type'] == 'f' else FaceType.HALF
        person_id_max_count = SampleGeneratorFace.get_person_id_max_count(
            self.training_data_src_path)

        self.model = FUNIT(face_type_str=FaceType.toString(face_type),
                           batch_size=self.batch_size,
                           encoder_nf=64,
                           encoder_downs=2,
                           encoder_res_blk=2,
                           class_downs=4,
                           class_nf=64,
                           class_latent=64,
                           mlp_nf=256,
                           mlp_blks=2,
                           dis_nf=64,
                           dis_res_blks=10,
                           num_classes=person_id_max_count,
                           subpixel_decoder=True,
                           initialize_weights=self.is_first_run(),
                           is_training=self.is_training_mode,
                           tf_cpu_mode=self.options['optimizer_mode'] - 1)

        if not self.is_first_run():
            self.load_weights_safe(self.model.get_model_filename_list())

        if self.is_training_mode:
            t = SampleProcessor.Types
            face_type = t.FACE_TYPE_FULL if self.options[
                'face_type'] == 'f' else t.FACE_TYPE_HALF

            output_sample_types = [{
                'types': (t.IMG_TRANSFORMED, face_type, t.MODE_BGR),
                'resolution':
                128,
                'normalize_tanh':
                True
            }]

            self.set_training_data_generators([
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types,
                    person_id_mode=True),
                SampleGeneratorFace(
                    self.training_data_src_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types,
                    person_id_mode=True),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types,
                    person_id_mode=True),
                SampleGeneratorFace(
                    self.training_data_dst_path,
                    debug=self.is_debug(),
                    batch_size=self.batch_size,
                    sample_process_options=SampleProcessor.Options(
                        random_flip=True),
                    output_sample_types=output_sample_types,
                    person_id_mode=True),
            ])
예제 #16
0
def main(input_dir,
         output_dir,
         debug,
         detector='mt',
         multi_gpu=True,
         cpu_only=False,
         manual_fix=False,
         manual_window_size=0,
         image_size=256,
         face_type='full_face'):
    print("Running extractor.\r\n")

    input_path = Path(input_dir)
    output_path = Path(output_dir)
    face_type = FaceType.fromString(face_type)

    if not input_path.exists():
        print('Input directory not found. Please ensure it exists.')
        return

    if output_path.exists():
        for filename in Path_utils.get_image_paths(output_path):
            Path(filename).unlink()
    else:
        output_path.mkdir(parents=True, exist_ok=True)

    if debug:
        debug_output_path = Path(str(output_path) + '_debug')
        if debug_output_path.exists():
            for filename in Path_utils.get_image_paths(debug_output_path):
                Path(filename).unlink()
        else:
            debug_output_path.mkdir(parents=True, exist_ok=True)

    input_path_image_paths = Path_utils.get_image_unique_filestem_paths(
        input_path, verbose=True)
    images_found = len(input_path_image_paths)
    faces_detected = 0
    if images_found != 0:
        if detector == 'manual':
            print('Performing manual extract...')
            extracted_faces = ExtractSubprocessor(
                [(filename, []) for filename in input_path_image_paths],
                'landmarks',
                image_size,
                face_type,
                debug,
                cpu_only=cpu_only,
                manual=True,
                manual_window_size=manual_window_size).process()
        else:
            print('Performing 1st pass...')
            extracted_rects = ExtractSubprocessor(
                [(x, ) for x in input_path_image_paths],
                'rects',
                image_size,
                face_type,
                debug,
                multi_gpu=multi_gpu,
                cpu_only=cpu_only,
                manual=False,
                detector=detector).process()

            print('Performing 2nd pass...')
            extracted_faces = ExtractSubprocessor(extracted_rects,
                                                  'landmarks',
                                                  image_size,
                                                  face_type,
                                                  debug,
                                                  multi_gpu=multi_gpu,
                                                  cpu_only=cpu_only,
                                                  manual=False).process()

            if manual_fix:
                print('Performing manual fix...')

                if all(
                        np.array(
                            [len(data[1]) > 0
                             for data in extracted_faces]) == True):
                    print('All faces are detected, manual fix not needed.')
                else:
                    extracted_faces = ExtractSubprocessor(
                        extracted_faces,
                        'landmarks',
                        image_size,
                        face_type,
                        debug,
                        manual=True,
                        manual_window_size=manual_window_size).process()

        if len(extracted_faces) > 0:
            print('Performing 3rd pass...')
            final_imgs_paths = ExtractSubprocessor(
                extracted_faces,
                'final',
                image_size,
                face_type,
                debug,
                multi_gpu=multi_gpu,
                cpu_only=cpu_only,
                manual=False,
                output_path=output_path).process()
            faces_detected = len(final_imgs_paths)

    print('-------------------------')
    print('Images found:        %d' % (images_found))
    print('Faces detected:      %d' % (faces_detected))
    print('-------------------------')
예제 #17
0
파일: Model.py 프로젝트: rumax/DeepFaceLab
    def on_initialize(self):
        device_config = nn.getCurrentDeviceConfig()
        nn.initialize(data_format="NHWC")
        tf = nn.tf

        device_config = nn.getCurrentDeviceConfig()
        devices = device_config.devices

        self.resolution = resolution = 256  #self.options['resolution']
        #self.face_type = {'h'  : FaceType.HALF,
        #                  'mf' : FaceType.MID_FULL,
        #                  'f'  : FaceType.FULL,
        #                  'wf' : FaceType.WHOLE_FACE}[ self.options['face_type'] ]
        self.face_type = FaceType.FULL

        place_model_on_cpu = len(devices) == 0
        models_opt_device = '/CPU:0' if place_model_on_cpu else '/GPU:0'

        bgr_shape = nn.get4Dshape(resolution, resolution, 3)
        mask_shape = nn.get4Dshape(resolution, resolution, 1)

        # Initializing model classes
        self.model = TernausNet(f'{self.model_name}_FANSeg',
                                resolution,
                                FaceType.toString(self.face_type),
                                load_weights=not self.is_first_run(),
                                weights_file_root=self.get_model_root_path(),
                                training=True,
                                place_model_on_cpu=place_model_on_cpu)

        if self.is_training:
            # Adjust batch size for multiple GPU
            gpu_count = max(1, len(devices))
            bs_per_gpu = max(1, self.get_batch_size() // gpu_count)
            self.set_batch_size(gpu_count * bs_per_gpu)

            # Compute losses per GPU
            gpu_pred_list = []

            gpu_losses = []
            gpu_loss_gvs = []

            for gpu_id in range(gpu_count):
                with tf.device(
                        f'/GPU:{gpu_id}' if len(devices) != 0 else f'/CPU:0'):

                    with tf.device(f'/CPU:0'):
                        # slice on CPU, otherwise all batch data will be transfered to GPU first
                        batch_slice = slice(gpu_id * bs_per_gpu,
                                            (gpu_id + 1) * bs_per_gpu)
                        gpu_input_t = self.model.input_t[batch_slice, :, :, :]
                        gpu_target_t = self.model.target_t[
                            batch_slice, :, :, :]

                    # process model tensors
                    gpu_pred_logits_t, gpu_pred_t = self.model.net(
                        [gpu_input_t])
                    gpu_pred_list.append(gpu_pred_t)

                    gpu_loss = tf.reduce_mean(
                        tf.nn.sigmoid_cross_entropy_with_logits(
                            labels=gpu_target_t, logits=gpu_pred_logits_t),
                        axis=[1, 2, 3])
                    gpu_losses += [gpu_loss]

                    gpu_loss_gvs += [
                        nn.tf_gradients(gpu_loss, self.model.net_weights)
                    ]

            # Average losses and gradients, and create optimizer update ops
            with tf.device(models_opt_device):
                pred = nn.tf_concat(gpu_pred_list, 0)
                loss = tf.reduce_mean(gpu_losses)

                loss_gv_op = self.model.opt.get_update_op(
                    nn.tf_average_gv_list(gpu_loss_gvs))

            # Initializing training and view functions
            def train(input_np, target_np):
                l, _ = nn.tf_sess.run([loss, loss_gv_op],
                                      feed_dict={
                                          self.model.input_t: input_np,
                                          self.model.target_t: target_np
                                      })
                return l

            self.train = train

            def view(input_np):
                return nn.tf_sess.run([pred],
                                      feed_dict={self.model.input_t: input_np})

            self.view = view

            # initializing sample generators
            training_data_src_path = self.training_data_src_path
            training_data_dst_path = self.training_data_dst_path

            cpu_count = min(multiprocessing.cpu_count(), 8)
            src_generators_count = cpu_count // 2
            dst_generators_count = cpu_count // 2
            src_generators_count = int(src_generators_count * 1.5)

            src_generator = SampleGeneratorFace(
                training_data_src_path,
                random_ct_samples_path=training_data_src_path,
                debug=self.is_debug(),
                batch_size=self.get_batch_size(),
                sample_process_options=SampleProcessor.Options(
                    random_flip=True),
                output_sample_types=[
                    {
                        'sample_type': SampleProcessor.SampleType.FACE_IMAGE,
                        'ct_mode': 'lct',
                        'warp': True,
                        'transform': True,
                        'channel_type': SampleProcessor.ChannelType.BGR,
                        'face_type': self.face_type,
                        'motion_blur': (25, 5),
                        'gaussian_blur': (25, 5),
                        'data_format': nn.data_format,
                        'resolution': resolution
                    },
                    {
                        'sample_type': SampleProcessor.SampleType.FACE_MASK,
                        'warp': True,
                        'transform': True,
                        'channel_type': SampleProcessor.ChannelType.G,
                        'face_mask_type':
                        SampleProcessor.FaceMaskType.FULL_FACE,
                        'face_type': self.face_type,
                        'data_format': nn.data_format,
                        'resolution': resolution
                    },
                ],
                generators_count=src_generators_count)

            dst_generator = SampleGeneratorFace(
                training_data_dst_path,
                debug=self.is_debug(),
                batch_size=self.get_batch_size(),
                sample_process_options=SampleProcessor.Options(
                    random_flip=True),
                output_sample_types=[
                    {
                        'sample_type': SampleProcessor.SampleType.FACE_IMAGE,
                        'warp': False,
                        'transform': True,
                        'channel_type': SampleProcessor.ChannelType.BGR,
                        'face_type': self.face_type,
                        'motion_blur': (25, 5),
                        'gaussian_blur': (25, 5),
                        'data_format': nn.data_format,
                        'resolution': resolution
                    },
                ],
                generators_count=dst_generators_count,
                raise_on_no_data=False)
            if not dst_generator.is_initialized():
                io.log_info(
                    f"\nTo view the model on unseen faces, place any aligned faces in {training_data_dst_path}.\n"
                )

            self.set_training_data_generators([src_generator, dst_generator])
예제 #18
0
 def on_cli_initialize(self):
     if (self.mask_mode >= 3
             and self.mask_mode <= 6) and self.fan_seg == None:
         self.fan_seg = FANSegmentator(256,
                                       FaceType.toString(FaceType.FULL))
예제 #19
0
        def process_data(self, filepath):
            try:
                dflimg = DFLIMG.load (filepath)
                if dflimg is None or not dflimg.has_data():
                    self.log_err (f"{filepath.name} is not a dfl image file")
                else:
                    img = cv2_imread(filepath)
                    h,w = img.shape[:2]
                    if h != w:
                        raise Exception(f'w != h in {filepath}')
                    
                    image_size = self.image_size
                    face_type = self.face_type
                    output_filepath = self.output_dirpath / filepath.name
                    
                    if face_type is not None:
                        lmrks = dflimg.get_landmarks()
                        mat = LandmarksProcessor.get_transform_mat(lmrks, image_size, face_type)
                        
                        img = cv2.warpAffine(img, mat, (image_size, image_size), flags=cv2.INTER_LANCZOS4 )
                        img = np.clip(img, 0, 255).astype(np.uint8)
                        
                        cv2_imwrite ( str(output_filepath), img, [int(cv2.IMWRITE_JPEG_QUALITY), 100] )

                        dfl_dict = dflimg.get_dict()
                        dflimg = DFLIMG.load (output_filepath)
                        dflimg.set_dict(dfl_dict)
                        
                        xseg_mask = dflimg.get_xseg_mask()
                        if xseg_mask is not None:
                            xseg_res = 256
                            
                            xseg_lmrks = lmrks.copy()
                            xseg_lmrks *= (xseg_res / w)
                            xseg_mat = LandmarksProcessor.get_transform_mat(xseg_lmrks, xseg_res, face_type)
                            
                            xseg_mask = cv2.warpAffine(xseg_mask, xseg_mat, (xseg_res, xseg_res), flags=cv2.INTER_LANCZOS4 )
                            xseg_mask[xseg_mask < 0.5] = 0
                            xseg_mask[xseg_mask >= 0.5] = 1

                            dflimg.set_xseg_mask(xseg_mask)
                        
                        seg_ie_polys = dflimg.get_seg_ie_polys()
                        
                        for poly in seg_ie_polys.get_polys():
                            poly_pts = poly.get_pts()
                            poly_pts = LandmarksProcessor.transform_points(poly_pts, mat)
                            poly.set_points(poly_pts)
                            
                        dflimg.set_seg_ie_polys(seg_ie_polys)
                        
                        lmrks = LandmarksProcessor.transform_points(lmrks, mat)
                        dflimg.set_landmarks(lmrks)
    
                        image_to_face_mat = dflimg.get_image_to_face_mat()
                        if image_to_face_mat is not None:
                            image_to_face_mat = LandmarksProcessor.get_transform_mat ( dflimg.get_source_landmarks(), image_size, face_type )
                            dflimg.set_image_to_face_mat(image_to_face_mat)
                        dflimg.set_face_type( FaceType.toString(face_type) )
                        dflimg.save()
                        
                    else:
                        dfl_dict = dflimg.get_dict()
                         
                        scale = w / image_size
                        
                        img = cv2.resize(img, (image_size, image_size), interpolation=cv2.INTER_LANCZOS4)                    
                        
                        cv2_imwrite ( str(output_filepath), img, [int(cv2.IMWRITE_JPEG_QUALITY), 100] )

                        dflimg = DFLIMG.load (output_filepath)
                        dflimg.set_dict(dfl_dict)
                        
                        lmrks = dflimg.get_landmarks()                    
                        lmrks /= scale
                        dflimg.set_landmarks(lmrks)
                        
                        seg_ie_polys = dflimg.get_seg_ie_polys()
                        seg_ie_polys.mult_points( 1.0 / scale)
                        dflimg.set_seg_ie_polys(seg_ie_polys)
                        
                        image_to_face_mat = dflimg.get_image_to_face_mat()
    
                        if image_to_face_mat is not None:
                            face_type = FaceType.fromString ( dflimg.get_face_type() )
                            image_to_face_mat = LandmarksProcessor.get_transform_mat ( dflimg.get_source_landmarks(), image_size, face_type )
                            dflimg.set_image_to_face_mat(image_to_face_mat)
                        dflimg.save()

                    return (1, filepath, output_filepath)
            except:
                self.log_err (f"Exception occured while processing file {filepath}. Error: {traceback.format_exc()}")

            return (0, filepath, None)
예제 #20
0
        def process_data(self, data):
            filename_path = Path(data[0])

            filename_path_str = str(filename_path)
            if self.cached_image[0] == filename_path_str:
                image = self.cached_image[
                    1]  #cached image for manual extractor
            else:
                image = cv2_imread(filename_path_str)

                if image is None:
                    self.log_err(
                        'Failed to extract %s, reason: cv2_imread() fail.' %
                        (str(filename_path)))
                    return None

                image_shape = image.shape
                if len(image_shape) == 2:
                    h, w = image.shape
                    ch = 1
                else:
                    h, w, ch = image.shape

                if ch == 1:
                    image = np.repeat(image[:, :, np.newaxis], 3, -1)
                elif ch == 4:
                    image = image[:, :, 0:3]

                wm = w % 2
                hm = h % 2
                if wm + hm != 0:  #fix odd image
                    image = image[0:h - hm, 0:w - wm, :]
                self.cached_image = (filename_path_str, image)

            src_dflimg = None
            h, w, ch = image.shape
            if h == w:
                #extracting from already extracted jpg image?
                if filename_path.suffix == '.jpg':
                    src_dflimg = DFLJPG.load(str(filename_path))

            if self.type == 'rects':
                if min(w, h) < 128:
                    self.log_err('Image is too small %s : [%d, %d]' %
                                 (str(filename_path), w, h))
                    rects = []
                else:
                    rects = self.e.extract_from_bgr(image)

                return [str(filename_path), rects]

            elif self.type == 'landmarks':
                rects = data[1]
                if rects is None:
                    landmarks = None
                else:
                    landmarks = self.e.extract_from_bgr(
                        image, rects,
                        self.second_pass_e if src_dflimg is None else None)

                return [str(filename_path), landmarks]

            elif self.type == 'final':

                result = []
                faces = data[1]

                if self.debug_dir is not None:
                    debug_output_file = str(
                        Path(self.debug_dir) / (filename_path.stem + '.jpg'))
                    debug_image = image.copy()

                if src_dflimg is not None and len(faces) != 1:
                    #if re-extracting from dflimg and more than 1 or zero faces detected - dont process and just copy it
                    print("src_dflimg is not None and len(faces) != 1",
                          str(filename_path))
                    output_file = str(self.output_path / filename_path.name)
                    if str(filename_path) != str(output_file):
                        shutil.copy(str(filename_path), str(output_file))
                    result.append(output_file)
                else:
                    face_idx = 0
                    for face in faces:
                        rect = np.array(face[0])
                        image_landmarks = face[1]
                        if image_landmarks is None:
                            continue
                        image_landmarks = np.array(image_landmarks)

                        if self.face_type == FaceType.MARK_ONLY:
                            face_image = image
                            face_image_landmarks = image_landmarks
                        else:
                            image_to_face_mat = LandmarksProcessor.get_transform_mat(
                                image_landmarks, self.image_size,
                                self.face_type)
                            face_image = cv2.warpAffine(
                                image, image_to_face_mat,
                                (self.image_size, self.image_size),
                                cv2.INTER_LANCZOS4)
                            face_image_landmarks = LandmarksProcessor.transform_points(
                                image_landmarks, image_to_face_mat)

                            landmarks_bbox = LandmarksProcessor.transform_points(
                                [(0, 0), (0, self.image_size - 1),
                                 (self.image_size - 1, self.image_size - 1),
                                 (self.image_size - 1, 0)], image_to_face_mat,
                                True)

                            rect_area = mathlib.polygon_area(
                                np.array(rect[[0, 2, 2, 0]]),
                                np.array(rect[[1, 1, 3, 3]]))
                            landmarks_area = mathlib.polygon_area(
                                landmarks_bbox[:, 0], landmarks_bbox[:, 1])

                            if landmarks_area > 4 * rect_area:  #get rid of faces which umeyama-landmark-area > 4*detector-rect-area
                                continue

                        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:
                            #if extracting from dflimg copy it in order not to lose quality
                            output_file = str(self.output_path /
                                              filename_path.name)
                            if str(filename_path) != str(output_file):
                                shutil.copy(str(filename_path),
                                            str(output_file))
                        else:
                            output_file = '{}_{}{}'.format(
                                str(self.output_path / filename_path.stem),
                                str(face_idx), '.jpg')
                            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)

                        result.append(output_file)
                        face_idx += 1

                if self.debug_dir is not None:
                    cv2_imwrite(debug_output_file, debug_image,
                                [int(cv2.IMWRITE_JPEG_QUALITY), 50])

                return result
예제 #21
0
        def process_data(self, data):
            filename_path = Path(data.filename)

            filename_path_str = str(filename_path)
            if self.cached_image[0] == filename_path_str:
                image = self.cached_image[
                    1]  #cached image for manual extractor
            else:
                image = cv2_imread(filename_path_str)

                if image is None:
                    self.log_err(
                        'Failed to extract %s, reason: cv2_imread() fail.' %
                        (str(filename_path)))
                    return data

                image = imagelib.normalize_channels(image, 3)
                h, w, ch = image.shape

                wm, hm = w % 2, h % 2
                if wm + hm != 0:  #fix odd image
                    image = image[0:h - hm, 0:w - wm, :]
                self.cached_image = (filename_path_str, image)

            src_dflimg = None
            h, w, ch = image.shape
            if h == w:
                #extracting from already extracted jpg image?
                if filename_path.suffix == '.png':
                    src_dflimg = DFLPNG.load(str(filename_path))
                if filename_path.suffix == '.jpg':
                    src_dflimg = DFLJPG.load(str(filename_path))

            if 'rects' in self.type:
                if min(w, h) < 128:
                    self.log_err('Image is too small %s : [%d, %d]' %
                                 (str(filename_path), w, h))
                    data.rects = []
                else:
                    for rot in ([0, 90, 270, 180]):
                        data.rects_rotation = rot
                        if rot == 0:
                            rotated_image = image
                        elif rot == 90:
                            rotated_image = image.swapaxes(0, 1)[:, ::-1, :]
                        elif rot == 180:
                            rotated_image = image[::-1, ::-1, :]
                        elif rot == 270:
                            rotated_image = image.swapaxes(0, 1)[::-1, :, :]

                        rects = data.rects = self.e.extract(rotated_image,
                                                            is_bgr=True)
                        if len(rects) != 0:
                            break

                    if self.max_faces_from_image != 0 and len(data.rects) > 1:
                        data.rects = data.rects[0:self.max_faces_from_image]

                return data

            elif self.type == 'landmarks':

                if data.rects_rotation == 0:
                    rotated_image = image
                elif data.rects_rotation == 90:
                    rotated_image = image.swapaxes(0, 1)[:, ::-1, :]
                elif data.rects_rotation == 180:
                    rotated_image = image[::-1, ::-1, :]
                elif data.rects_rotation == 270:
                    rotated_image = image.swapaxes(0, 1)[::-1, :, :]

                data.landmarks = self.e.extract(
                    rotated_image,
                    data.rects,
                    self.second_pass_e if
                    (src_dflimg is None and data.landmarks_accurate) else None,
                    is_bgr=True)
                if data.rects_rotation != 0:
                    for i, (rect,
                            lmrks) in enumerate(zip(data.rects,
                                                    data.landmarks)):
                        new_rect, new_lmrks = rect, lmrks
                        (l, t, r, b) = rect
                        if data.rects_rotation == 90:
                            new_rect = (t, h - l, b, h - r)
                            if lmrks is not None:
                                new_lmrks = lmrks[:, ::-1].copy()
                                new_lmrks[:, 1] = h - new_lmrks[:, 1]
                        elif data.rects_rotation == 180:
                            if lmrks is not None:
                                new_rect = (w - l, h - t, w - r, h - b)
                                new_lmrks = lmrks.copy()
                                new_lmrks[:, 0] = w - new_lmrks[:, 0]
                                new_lmrks[:, 1] = h - new_lmrks[:, 1]
                        elif data.rects_rotation == 270:
                            new_rect = (w - b, l, w - t, r)
                            if lmrks is not None:
                                new_lmrks = lmrks[:, ::-1].copy()
                                new_lmrks[:, 0] = w - new_lmrks[:, 0]
                        data.rects[i], data.landmarks[i] = new_rect, new_lmrks

                return data

            elif self.type == 'final':
                data.final_output_files = []
                rects = data.rects
                landmarks = data.landmarks

                if self.debug_dir is not None:
                    debug_output_file = str(
                        Path(self.debug_dir) / (filename_path.stem + '.jpg'))
                    debug_image = image.copy()

                if src_dflimg is not None and len(rects) != 1:
                    #if re-extracting from dflimg and more than 1 or zero faces detected - dont process and just copy it
                    print("src_dflimg is not None and len(rects) != 1",
                          str(filename_path))
                    output_file = str(self.final_output_path /
                                      filename_path.name)
                    if str(filename_path) != str(output_file):
                        shutil.copy(str(filename_path), str(output_file))
                    data.final_output_files.append(output_file)
                else:
                    face_idx = 0
                    for rect, image_landmarks in zip(rects, landmarks):

                        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

                        rect = np.array(rect)

                        if self.face_type == FaceType.MARK_ONLY:
                            image_to_face_mat = None
                            face_image = image
                            face_image_landmarks = image_landmarks
                        else:
                            image_to_face_mat = LandmarksProcessor.get_transform_mat(
                                image_landmarks, self.image_size,
                                self.face_type)

                            face_image = cv2.warpAffine(
                                image, image_to_face_mat,
                                (self.image_size, self.image_size),
                                cv2.INTER_LANCZOS4)
                            face_image_landmarks = LandmarksProcessor.transform_points(
                                image_landmarks, image_to_face_mat)

                            landmarks_bbox = LandmarksProcessor.transform_points(
                                [(0, 0), (0, self.image_size - 1),
                                 (self.image_size - 1, self.image_size - 1),
                                 (self.image_size - 1, 0)], image_to_face_mat,
                                True)

                            rect_area = mathlib.polygon_area(
                                np.array(rect[[0, 2, 2, 0]]),
                                np.array(rect[[1, 1, 3, 3]]))
                            landmarks_area = mathlib.polygon_area(
                                landmarks_bbox[:, 0], landmarks_bbox[:, 1])

                            if landmarks_area > 4 * rect_area:  #get rid of faces which umeyama-landmark-area > 4*detector-rect-area
                                continue

                            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 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])

                        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)

                        data.final_output_files.append(output_file)
                        face_idx += 1
                    data.faces_detected = face_idx

                if self.debug_dir is not None:
                    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,
                        fanseg_mask=fanseg_mask,
                    )
예제 #22
0
    def convert_face(self, img_bgr, img_face_landmarks, debug):
        if (self.mask_mode == 3
                or self.mask_mode == 4) and self.fan_seg == None:
            self.fan_seg = FANSegmentator(256,
                                          FaceType.toString(FaceType.FULL))

        if self.over_res != 1:
            img_bgr = cv2.resize(img_bgr, (img_bgr.shape[1] * self.over_res,
                                           img_bgr.shape[0] * self.over_res))
            img_face_landmarks = img_face_landmarks * self.over_res

        if debug:
            debugs = [img_bgr.copy()]

        img_size = img_bgr.shape[1], img_bgr.shape[0]

        img_face_mask_a = LandmarksProcessor.get_image_hull_mask(
            img_bgr.shape, img_face_landmarks)

        face_mat = LandmarksProcessor.get_transform_mat(
            img_face_landmarks, self.output_size, face_type=self.face_type)
        face_output_mat = LandmarksProcessor.get_transform_mat(
            img_face_landmarks,
            self.output_size,
            face_type=self.face_type,
            scale=self.output_face_scale)

        dst_face_bgr = cv2.warpAffine(img_bgr,
                                      face_mat,
                                      (self.output_size, self.output_size),
                                      flags=cv2.INTER_LANCZOS4)
        dst_face_mask_a_0 = cv2.warpAffine(
            img_face_mask_a,
            face_mat, (self.output_size, self.output_size),
            flags=cv2.INTER_LANCZOS4)

        predictor_input_bgr = cv2.resize(
            dst_face_bgr,
            (self.predictor_input_size, self.predictor_input_size))
        predictor_input_mask_a_0 = cv2.resize(
            dst_face_mask_a_0,
            (self.predictor_input_size, self.predictor_input_size))
        predictor_input_mask_a = np.expand_dims(predictor_input_mask_a_0, -1)

        predicted_bgra = self.predictor_func(
            np.concatenate((predictor_input_bgr, predictor_input_mask_a), -1))

        prd_face_bgr = np.clip(predicted_bgra[:, :, 0:3], 0, 1.0)
        prd_face_mask_a_0 = np.clip(predicted_bgra[:, :, 3], 0.0, 1.0)

        if self.mask_mode == 2:  #dst
            prd_face_mask_a_0 = predictor_input_mask_a_0
        elif self.mask_mode == 3:  #FAN-prd
            prd_face_bgr_256 = cv2.resize(prd_face_bgr, (256, 256))
            prd_face_bgr_256_mask = self.fan_seg.extract_from_bgr(
                np.expand_dims(prd_face_bgr_256, 0))[0]
            prd_face_mask_a_0 = cv2.resize(
                prd_face_bgr_256_mask,
                (self.predictor_input_size, self.predictor_input_size))
        elif self.mask_mode == 4:  #FAN-dst
            face_256_mat = LandmarksProcessor.get_transform_mat(
                img_face_landmarks, 256, face_type=FaceType.FULL)
            dst_face_256_bgr = cv2.warpAffine(img_bgr,
                                              face_256_mat, (256, 256),
                                              flags=cv2.INTER_LANCZOS4)
            dst_face_256_mask = self.fan_seg.extract_from_bgr(
                np.expand_dims(dst_face_256_bgr, 0))[0]
            prd_face_mask_a_0 = cv2.resize(
                dst_face_256_mask,
                (self.predictor_input_size, self.predictor_input_size))

        prd_face_mask_a_0[prd_face_mask_a_0 < 0.001] = 0.0

        prd_face_mask_a = np.expand_dims(prd_face_mask_a_0, axis=-1)
        prd_face_mask_aaa = np.repeat(prd_face_mask_a, (3, ), axis=-1)

        img_face_mask_aaa = cv2.warpAffine(prd_face_mask_aaa,
                                           face_output_mat,
                                           img_size,
                                           np.zeros(img_bgr.shape,
                                                    dtype=np.float32),
                                           flags=cv2.WARP_INVERSE_MAP
                                           | cv2.INTER_LANCZOS4)
        img_face_mask_aaa = np.clip(img_face_mask_aaa, 0.0, 1.0)
        img_face_mask_aaa[img_face_mask_aaa <= 0.1] = 0.0  #get rid of noise

        if debug:
            debugs += [img_face_mask_aaa.copy()]

        if 'seamless' in self.mode:
            #mask used for cv2.seamlessClone
            img_face_seamless_mask_aaa = None
            for i in range(9, 0, -1):
                a = img_face_mask_aaa > i / 10.0
                if len(np.argwhere(a)) == 0:
                    continue
                img_face_seamless_mask_aaa = img_face_mask_aaa.copy()
                img_face_seamless_mask_aaa[a] = 1.0
                img_face_seamless_mask_aaa[img_face_seamless_mask_aaa <= i /
                                           10.0] = 0.0

        out_img = img_bgr.copy()

        if self.mode == 'raw':
            if self.raw_mode == 'rgb' or self.raw_mode == 'rgb-mask':
                out_img = cv2.warpAffine(
                    prd_face_bgr, face_output_mat, img_size, out_img,
                    cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4,
                    cv2.BORDER_TRANSPARENT)

            if self.raw_mode == 'rgb-mask':
                out_img = np.concatenate(
                    [out_img,
                     np.expand_dims(img_face_mask_aaa[:, :, 0], -1)], -1)

            if self.raw_mode == 'mask-only':
                out_img = img_face_mask_aaa

            if self.raw_mode == 'predicted-only':
                out_img = cv2.warpAffine(
                    prd_face_bgr, face_output_mat, img_size,
                    np.zeros(out_img.shape, dtype=np.float32),
                    cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4,
                    cv2.BORDER_TRANSPARENT)

        elif ('seamless' not in self.mode) or (img_face_seamless_mask_aaa
                                               is not None):
            #averaging [lenx, leny, maskx, masky] by grayscale gradients of upscaled mask
            ar = []
            for i in range(1, 10):
                maxregion = np.argwhere(img_face_mask_aaa > i / 10.0)
                if maxregion.size != 0:
                    miny, minx = maxregion.min(axis=0)[:2]
                    maxy, maxx = maxregion.max(axis=0)[:2]
                    lenx = maxx - minx
                    leny = maxy - miny
                    maskx = (minx + (lenx / 2))
                    masky = (miny + (leny / 2))
                    if lenx >= 4 and leny >= 4:
                        ar += [[lenx, leny, maskx, masky]]

            if len(ar) > 0:
                lenx, leny, maskx, masky = np.mean(ar, axis=0)

                if debug:
                    io.log_info("lenx/leny:(%d/%d) maskx/masky:(%f/%f)" %
                                (lenx, leny, maskx, masky))

                maskx = int(maskx)
                masky = int(masky)

                lowest_len = min(lenx, leny)

                if debug:
                    io.log_info("lowest_len = %f" % (lowest_len))

                img_mask_blurry_aaa = img_face_mask_aaa

                if self.erode_mask_modifier != 0:
                    ero = int(lowest_len *
                              (0.126 - lowest_len * 0.00004551365) * 0.01 *
                              self.erode_mask_modifier)
                    if debug:
                        io.log_info("erode_size = %d" % (ero))
                    if ero > 0:
                        img_mask_blurry_aaa = cv2.erode(
                            img_mask_blurry_aaa,
                            cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
                                                      (ero, ero)),
                            iterations=1)
                    elif ero < 0:
                        img_mask_blurry_aaa = cv2.dilate(
                            img_mask_blurry_aaa,
                            cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
                                                      (-ero, -ero)),
                            iterations=1)

                if self.seamless_erode_mask_modifier != 0:
                    ero = int(lowest_len *
                              (0.126 - lowest_len * 0.00004551365) * 0.01 *
                              self.seamless_erode_mask_modifier)
                    if debug:
                        io.log_info("seamless_erode_size = %d" % (ero))
                    if ero > 0:
                        img_face_seamless_mask_aaa = cv2.erode(
                            img_face_seamless_mask_aaa,
                            cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
                                                      (ero, ero)),
                            iterations=1)
                    elif ero < 0:
                        img_face_seamless_mask_aaa = cv2.dilate(
                            img_face_seamless_mask_aaa,
                            cv2.getStructuringElement(cv2.MORPH_ELLIPSE,
                                                      (-ero, -ero)),
                            iterations=1)
                    img_face_seamless_mask_aaa = np.clip(
                        img_face_seamless_mask_aaa, 0, 1)

                if self.clip_hborder_mask_per > 0:  #clip hborder before blur
                    prd_hborder_rect_mask_a = np.ones(prd_face_mask_a.shape,
                                                      dtype=np.float32)
                    prd_border_size = int(prd_hborder_rect_mask_a.shape[1] *
                                          self.clip_hborder_mask_per)
                    prd_hborder_rect_mask_a[:, 0:prd_border_size, :] = 0
                    prd_hborder_rect_mask_a[:, -prd_border_size:, :] = 0
                    prd_hborder_rect_mask_a = np.expand_dims(
                        cv2.blur(prd_hborder_rect_mask_a,
                                 (prd_border_size, prd_border_size)), -1)

                    img_prd_hborder_rect_mask_a = cv2.warpAffine(
                        prd_hborder_rect_mask_a, face_output_mat, img_size,
                        np.zeros(img_bgr.shape, dtype=np.float32),
                        cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4)
                    img_prd_hborder_rect_mask_a = np.expand_dims(
                        img_prd_hborder_rect_mask_a, -1)
                    img_mask_blurry_aaa *= img_prd_hborder_rect_mask_a
                    img_mask_blurry_aaa = np.clip(img_mask_blurry_aaa, 0, 1.0)

                    if debug:
                        debugs += [img_mask_blurry_aaa.copy()]

                if self.blur_mask_modifier > 0:
                    blur = int(lowest_len * 0.10 * 0.01 *
                               self.blur_mask_modifier)
                    if debug:
                        io.log_info("blur_size = %d" % (blur))
                    if blur > 0:
                        img_mask_blurry_aaa = cv2.blur(img_mask_blurry_aaa,
                                                       (blur, blur))

                img_mask_blurry_aaa = np.clip(img_mask_blurry_aaa, 0, 1.0)

                if debug:
                    debugs += [img_mask_blurry_aaa.copy()]

                if self.color_transfer_mode is not None:
                    if self.color_transfer_mode == 'rct':
                        if debug:
                            debugs += [
                                np.clip(
                                    cv2.warpAffine(
                                        prd_face_bgr, face_output_mat,
                                        img_size,
                                        np.zeros(img_bgr.shape,
                                                 dtype=np.float32),
                                        cv2.WARP_INVERSE_MAP
                                        | cv2.INTER_LANCZOS4,
                                        cv2.BORDER_TRANSPARENT), 0, 1.0)
                            ]

                        prd_face_bgr = image_utils.reinhard_color_transfer(
                            np.clip((prd_face_bgr * 255).astype(np.uint8), 0,
                                    255),
                            np.clip((dst_face_bgr * 255).astype(np.uint8), 0,
                                    255),
                            source_mask=prd_face_mask_a,
                            target_mask=prd_face_mask_a)
                        prd_face_bgr = np.clip(
                            prd_face_bgr.astype(np.float32) / 255.0, 0.0, 1.0)

                        if debug:
                            debugs += [
                                np.clip(
                                    cv2.warpAffine(
                                        prd_face_bgr, face_output_mat,
                                        img_size,
                                        np.zeros(img_bgr.shape,
                                                 dtype=np.float32),
                                        cv2.WARP_INVERSE_MAP
                                        | cv2.INTER_LANCZOS4,
                                        cv2.BORDER_TRANSPARENT), 0, 1.0)
                            ]

                    elif self.color_transfer_mode == 'lct':
                        if debug:
                            debugs += [
                                np.clip(
                                    cv2.warpAffine(
                                        prd_face_bgr, face_output_mat,
                                        img_size,
                                        np.zeros(img_bgr.shape,
                                                 dtype=np.float32),
                                        cv2.WARP_INVERSE_MAP
                                        | cv2.INTER_LANCZOS4,
                                        cv2.BORDER_TRANSPARENT), 0, 1.0)
                            ]

                        prd_face_bgr = image_utils.linear_color_transfer(
                            prd_face_bgr, dst_face_bgr)
                        prd_face_bgr = np.clip(prd_face_bgr, 0.0, 1.0)

                        if debug:
                            debugs += [
                                np.clip(
                                    cv2.warpAffine(
                                        prd_face_bgr, face_output_mat,
                                        img_size,
                                        np.zeros(img_bgr.shape,
                                                 dtype=np.float32),
                                        cv2.WARP_INVERSE_MAP
                                        | cv2.INTER_LANCZOS4,
                                        cv2.BORDER_TRANSPARENT), 0, 1.0)
                            ]

                if self.mode == 'hist-match-bw':
                    prd_face_bgr = cv2.cvtColor(prd_face_bgr,
                                                cv2.COLOR_BGR2GRAY)
                    prd_face_bgr = np.repeat(np.expand_dims(prd_face_bgr, -1),
                                             (3, ), -1)

                if self.mode == 'hist-match' or self.mode == 'hist-match-bw':
                    if debug:
                        debugs += [
                            cv2.warpAffine(
                                prd_face_bgr, face_output_mat, img_size,
                                np.zeros(img_bgr.shape, dtype=np.float32),
                                cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4,
                                cv2.BORDER_TRANSPARENT)
                        ]

                    hist_mask_a = np.ones(prd_face_bgr.shape[:2] + (1, ),
                                          dtype=np.float32)

                    if self.masked_hist_match:
                        hist_mask_a *= prd_face_mask_a

                    hist_match_1 = prd_face_bgr * hist_mask_a + (
                        1.0 - hist_mask_a) * np.ones(
                            prd_face_bgr.shape[:2] + (1, ), dtype=np.float32)
                    hist_match_1[hist_match_1 > 1.0] = 1.0

                    hist_match_2 = dst_face_bgr * hist_mask_a + (
                        1.0 - hist_mask_a) * np.ones(
                            prd_face_bgr.shape[:2] + (1, ), dtype=np.float32)
                    hist_match_2[hist_match_1 > 1.0] = 1.0

                    prd_face_bgr = image_utils.color_hist_match(
                        hist_match_1, hist_match_2, self.hist_match_threshold)

                if self.mode == 'hist-match-bw':
                    prd_face_bgr = prd_face_bgr.astype(dtype=np.float32)

                out_img = cv2.warpAffine(
                    prd_face_bgr, face_output_mat, img_size, out_img,
                    cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4,
                    cv2.BORDER_TRANSPARENT)
                out_img = np.clip(out_img, 0.0, 1.0)

                if debug:
                    debugs += [out_img.copy()]

                if self.mode == 'overlay':
                    pass

                if 'seamless' in self.mode:
                    try:
                        out_img = cv2.seamlessClone(
                            (out_img * 255).astype(np.uint8),
                            (img_bgr * 255).astype(np.uint8),
                            (img_face_seamless_mask_aaa * 255).astype(
                                np.uint8), (maskx, masky), cv2.NORMAL_CLONE)
                        out_img = out_img.astype(dtype=np.float32) / 255.0
                    except Exception as e:
                        #seamlessClone may fail in some cases
                        e_str = traceback.format_exc()

                        if 'MemoryError' in e_str:
                            raise Exception(
                                "Seamless fail: " + e_str
                            )  #reraise MemoryError in order to reprocess this data by other processes
                        else:
                            print("Seamless fail: " + e_str)

                    if debug:
                        debugs += [out_img.copy()]

                out_img = np.clip(
                    img_bgr * (1 - img_mask_blurry_aaa) +
                    (out_img * img_mask_blurry_aaa), 0, 1.0)

                if self.mode == 'seamless-hist-match':
                    out_face_bgr = cv2.warpAffine(
                        out_img, face_mat,
                        (self.output_size, self.output_size))
                    new_out_face_bgr = image_utils.color_hist_match(
                        out_face_bgr, dst_face_bgr, self.hist_match_threshold)
                    new_out = cv2.warpAffine(
                        new_out_face_bgr, face_mat, img_size, img_bgr.copy(),
                        cv2.WARP_INVERSE_MAP | cv2.INTER_LANCZOS4,
                        cv2.BORDER_TRANSPARENT)
                    out_img = np.clip(
                        img_bgr * (1 - img_mask_blurry_aaa) +
                        (new_out * img_mask_blurry_aaa), 0, 1.0)

                if self.final_image_color_degrade_power != 0:
                    if debug:
                        debugs += [out_img.copy()]
                    out_img_reduced = image_utils.reduce_colors(out_img, 256)
                    if self.final_image_color_degrade_power == 100:
                        out_img = out_img_reduced
                    else:
                        alpha = self.final_image_color_degrade_power / 100.0
                        out_img = (out_img * (1.0 - alpha) +
                                   out_img_reduced * alpha)

                if self.alpha:
                    out_img = np.concatenate([
                        out_img,
                        np.expand_dims(img_mask_blurry_aaa[:, :, 0], -1)
                    ], -1)

        if self.over_res != 1:
            out_img = cv2.resize(out_img, (img_bgr.shape[1] // self.over_res,
                                           img_bgr.shape[0] // self.over_res))

        out_img = np.clip(out_img, 0.0, 1.0)

        if debug:
            debugs += [out_img.copy()]

        return debugs if debug else out_img
예제 #23
0
def main(input_dir,
         output_dir,
         debug_dir=None,
         detector='mt',
         manual_fix=False,
         manual_output_debug_fix=False,
         manual_window_size=1368,
         image_size=256,
         face_type='full_face',
         max_faces_from_image=0,
         device_args={}):

    input_path = Path(input_dir)
    output_path = Path(output_dir)
    face_type = FaceType.fromString(face_type)

    multi_gpu = device_args.get('multi_gpu', False)
    cpu_only = device_args.get('cpu_only', False)

    if not input_path.exists():
        raise ValueError('Input directory not found. Please ensure it exists.')

    if output_path.exists():
        if not manual_output_debug_fix and input_path != output_path:
            output_images_paths = Path_utils.get_image_paths(output_path)
            if len(output_images_paths) > 0:
                io.input_bool(
                    "WARNING !!! \n %s contains files! \n They will be deleted. \n Press enter to continue."
                    % (str(output_path)), False)
                for filename in output_images_paths:
                    Path(filename).unlink()
    else:
        output_path.mkdir(parents=True, exist_ok=True)

    if manual_output_debug_fix:
        if debug_dir is None:
            raise ValueError('debug-dir must be specified')
        detector = 'manual'
        io.log_info(
            'Performing re-extract frames which were deleted from _debug directory.'
        )

    input_path_image_paths = Path_utils.get_image_unique_filestem_paths(
        input_path, verbose_print_func=io.log_info)
    if debug_dir is not None:
        debug_output_path = Path(debug_dir)

        if manual_output_debug_fix:
            if not debug_output_path.exists():
                raise ValueError("%s not found " % (str(debug_output_path)))

            input_path_image_paths = DeletedFilesSearcherSubprocessor(
                input_path_image_paths,
                Path_utils.get_image_paths(debug_output_path)).run()
            input_path_image_paths = sorted(input_path_image_paths)
            io.log_info('Found %d images.' % (len(input_path_image_paths)))
        else:
            if debug_output_path.exists():
                for filename in Path_utils.get_image_paths(debug_output_path):
                    Path(filename).unlink()
            else:
                debug_output_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(filename)
                    for filename in input_path_image_paths
                ],
                'landmarks',
                image_size,
                face_type,
                debug_dir,
                cpu_only=cpu_only,
                manual=True,
                manual_window_size=manual_window_size).run()
        else:
            io.log_info('Performing 1st pass...')
            data = ExtractSubprocessor(
                [
                    ExtractSubprocessor.Data(filename)
                    for filename in input_path_image_paths
                ],
                'rects-' + detector,
                image_size,
                face_type,
                debug_dir,
                multi_gpu=multi_gpu,
                cpu_only=cpu_only,
                manual=False,
                max_faces_from_image=max_faces_from_image).run()

            io.log_info('Performing 2nd pass...')
            data = ExtractSubprocessor(data,
                                       'landmarks',
                                       image_size,
                                       face_type,
                                       debug_dir,
                                       multi_gpu=multi_gpu,
                                       cpu_only=cpu_only,
                                       manual=False).run()

        io.log_info('Performing 3rd pass...')
        data = ExtractSubprocessor(data,
                                   'final',
                                   image_size,
                                   face_type,
                                   debug_dir,
                                   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])

        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.filename) 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',
                    image_size,
                    face_type,
                    debug_dir,
                    manual=True,
                    manual_window_size=manual_window_size).run()
                fix_data = ExtractSubprocessor(
                    fix_data,
                    'final',
                    image_size,
                    face_type,
                    debug_dir,
                    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 fix_data])

    io.log_info('-------------------------')
    io.log_info('Images found:        %d' % (images_found))
    io.log_info('Faces detected:      %d' % (faces_detected))
    io.log_info('-------------------------')
예제 #24
0
    def onClientProcessData(self, data):
        filename_path = Path(data[0])

        image = cv2_imread(str(filename_path))
        if image is None:
            print('Failed to extract %s, reason: cv2_imread() fail.' %
                  (str(filename_path)))
        else:
            if self.type == 'rects':
                rects = self.e.extract_from_bgr(image)
                return [str(filename_path), rects]

            elif self.type == 'landmarks':
                rects = data[1]
                landmarks = self.e.extract_from_bgr(image, rects)
                return [str(filename_path), landmarks]

            elif self.type == 'final':
                result = []
                faces = data[1]

                if self.debug:
                    debug_output_file = '{}{}'.format(
                        str(
                            Path(str(self.output_path) + '_debug') /
                            filename_path.stem), '.jpg')
                    debug_image = image.copy()

                for (face_idx, face) in enumerate(faces):
                    output_file = '{}_{}{}'.format(
                        str(self.output_path / filename_path.stem),
                        str(face_idx), '.jpg')

                    rect = face[0]
                    image_landmarks = np.array(face[1])

                    if self.debug:
                        facelib.LandmarksProcessor.draw_rect_landmarks(
                            debug_image, rect, image_landmarks,
                            self.image_size, self.face_type)

                    if self.face_type == FaceType.MARK_ONLY:
                        face_image = image
                        face_image_landmarks = image_landmarks
                    else:
                        image_to_face_mat = facelib.LandmarksProcessor.get_transform_mat(
                            image_landmarks, self.image_size, self.face_type)
                        face_image = cv2.warpAffine(
                            image, image_to_face_mat,
                            (self.image_size, self.image_size),
                            cv2.INTER_LANCZOS4)
                        face_image_landmarks = facelib.LandmarksProcessor.transform_points(
                            image_landmarks, image_to_face_mat)

                    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(),
                        yaw_value=facelib.LandmarksProcessor.calc_face_yaw(
                            face_image_landmarks),
                        pitch_value=facelib.LandmarksProcessor.calc_face_pitch(
                            face_image_landmarks),
                        source_filename=filename_path.name,
                        source_rect=rect,
                        source_landmarks=image_landmarks.tolist())

                    result.append(output_file)

                if self.debug:
                    cv2_imwrite(debug_output_file, debug_image,
                                [int(cv2.IMWRITE_JPEG_QUALITY), 50])

                return result
        return None
예제 #25
0
def main(input_dir,
         output_dir,
         debug=False,
         detector='mt',
         manual_fix=False,
         manual_output_debug_fix=False,
         manual_window_size=1368,
         image_size=256,
         face_type='full_face',
         device_args={}):

    input_path = Path(input_dir)
    output_path = Path(output_dir)
    face_type = FaceType.fromString(face_type)

    multi_gpu = device_args.get('multi_gpu', False)
    cpu_only = device_args.get('cpu_only', False)

    if not input_path.exists():
        raise ValueError('Input directory not found. Please ensure it exists.')

    if output_path.exists():
        if not manual_output_debug_fix:
            for filename in Path_utils.get_image_paths(output_path):
                Path(filename).unlink()
    else:
        output_path.mkdir(parents=True, exist_ok=True)

    if manual_output_debug_fix:
        debug = True
        detector = 'manual'
        io.log_info(
            'Performing re-extract frames which were deleted from _debug directory.'
        )

    input_path_image_paths = Path_utils.get_image_unique_filestem_paths(
        input_path, verbose_print_func=io.log_info)
    if debug:
        debug_output_path = Path(str(output_path) + '_debug')

        if manual_output_debug_fix:
            if not debug_output_path.exists():
                raise ValueError("%s not found " % (str(debug_output_path)))

            input_path_image_paths = DeletedFilesSearcherSubprocessor(
                input_path_image_paths,
                Path_utils.get_image_paths(debug_output_path)).run()
            input_path_image_paths = sorted(input_path_image_paths)
        else:
            if debug_output_path.exists():
                for filename in Path_utils.get_image_paths(debug_output_path):
                    Path(filename).unlink()
            else:
                debug_output_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...')
            extracted_faces = ExtractSubprocessor(
                [(filename, []) for filename in input_path_image_paths],
                'landmarks',
                image_size,
                face_type,
                debug,
                cpu_only=cpu_only,
                manual=True,
                manual_window_size=manual_window_size).run()
        else:
            io.log_info('Performing 1st pass...')
            extracted_rects = ExtractSubprocessor(
                [(x, ) for x in input_path_image_paths],
                'rects',
                image_size,
                face_type,
                debug,
                multi_gpu=multi_gpu,
                cpu_only=cpu_only,
                manual=False,
                detector=detector).run()

            io.log_info('Performing 2nd pass...')
            extracted_faces = ExtractSubprocessor(extracted_rects,
                                                  'landmarks',
                                                  image_size,
                                                  face_type,
                                                  debug,
                                                  multi_gpu=multi_gpu,
                                                  cpu_only=cpu_only,
                                                  manual=False).run()

            if manual_fix:
                io.log_info('Performing manual fix...')

                if all(
                        np.array(
                            [len(data[1]) > 0
                             for data in extracted_faces]) == True):
                    io.log_info(
                        'All faces are detected, manual fix not needed.')
                else:
                    extracted_faces = ExtractSubprocessor(
                        extracted_faces,
                        'landmarks',
                        image_size,
                        face_type,
                        debug,
                        manual=True,
                        manual_window_size=manual_window_size).run()

        if len(extracted_faces) > 0:
            io.log_info('Performing 3rd pass...')
            final_imgs_paths = ExtractSubprocessor(
                extracted_faces,
                'final',
                image_size,
                face_type,
                debug,
                multi_gpu=multi_gpu,
                cpu_only=cpu_only,
                manual=False,
                output_path=output_path).run()
            faces_detected = len(final_imgs_paths)

    io.log_info('-------------------------')
    io.log_info('Images found:        %d' % (images_found))
    io.log_info('Faces detected:      %d' % (faces_detected))
    io.log_info('-------------------------')
예제 #26
0
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=0,
         cpu_only = False,
         force_gpu_idxs = None,
         ):
    face_type = FaceType.fromString(face_type)

    image_size = 512
    
    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"\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()
    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 ('-------------------------')
예제 #27
0
        def final_stage(
            data,
            image,
            face_type,
            image_size,
            jpeg_quality,
            extract_from_dflimg=False,
            output_debug_path=None,
            final_output_path=None,
        ):
            data.final_output_files = []
            filepath = data.filepath
            rects = data.rects
            landmarks = data.landmarks

            if output_debug_path is not None:
                debug_image = image.copy()

            if extract_from_dflimg and len(rects) != 1:
                #if re-extracting from dflimg and more than 1 or zero faces detected - dont process and just copy it
                print("extract_from_dflimg and len(rects) != 1", filepath)
                output_filepath = final_output_path / filepath.name
                if filepath != str(output_file):
                    shutil.copy(str(filepath), str(output_filepath))
                data.final_output_files.append(output_filepath)
            else:
                face_idx = 0
                for rect, image_landmarks in zip(rects, landmarks):

                    if extract_from_dflimg and face_idx > 1:
                        #cannot extract more than 1 face from dflimg
                        break

                    if image_landmarks is None:
                        continue

                    rect = np.array(rect)

                    if face_type == FaceType.MARK_ONLY:
                        image_to_face_mat = None
                        face_image = image
                        face_image_landmarks = image_landmarks
                    else:
                        image_to_face_mat = LandmarksProcessor.get_transform_mat(
                            image_landmarks, image_size, face_type)

                        face_image = cv2.warpAffine(image, image_to_face_mat,
                                                    (image_size, image_size),
                                                    cv2.INTER_LANCZOS4)
                        face_image_landmarks = LandmarksProcessor.transform_points(
                            image_landmarks, image_to_face_mat)

                        landmarks_bbox = LandmarksProcessor.transform_points(
                            [(0, 0), (0, image_size - 1),
                             (image_size - 1, image_size - 1),
                             (image_size - 1, 0)], image_to_face_mat, True)

                        rect_area = mathlib.polygon_area(
                            np.array(rect[[0, 2, 2, 0]]).astype(np.float32),
                            np.array(rect[[1, 1, 3, 3]]).astype(np.float32))
                        landmarks_area = mathlib.polygon_area(
                            landmarks_bbox[:, 0].astype(np.float32),
                            landmarks_bbox[:, 1].astype(np.float32))

                        if not data.manual and face_type <= FaceType.FULL_NO_ALIGN and landmarks_area > 4 * rect_area:  #get rid of faces which umeyama-landmark-area > 4*detector-rect-area
                            continue

                        if output_debug_path is not None:
                            LandmarksProcessor.draw_rect_landmarks(
                                debug_image,
                                rect,
                                image_landmarks,
                                face_type,
                                image_size,
                                transparent_mask=True)

                    output_path = final_output_path
                    if data.force_output_path is not None:
                        output_path = data.force_output_path

                    if extract_from_dflimg and filepath.suffix == '.jpg':
                        #if extracting from dflimg and jpg copy it in order not to lose quality
                        output_filepath = output_path / filepath.name
                        if filepath != output_filepath:
                            shutil.copy(str(filepath), str(output_filepath))
                    else:
                        output_filepath = output_path / f"{filepath.stem}_{face_idx}.jpg"
                        cv2_imwrite(
                            output_filepath, face_image,
                            [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_quality])

                    dflimg = DFLJPG.load(output_filepath)
                    dflimg.set_face_type(FaceType.toString(face_type))
                    dflimg.set_landmarks(face_image_landmarks.tolist())
                    dflimg.set_source_filename(filepath.name)
                    dflimg.set_source_rect(rect)
                    dflimg.set_source_landmarks(image_landmarks.tolist())
                    dflimg.set_image_to_face_mat(image_to_face_mat)
                    dflimg.save()

                    data.final_output_files.append(output_filepath)
                    face_idx += 1
                data.faces_detected = face_idx

            if output_debug_path is not None:
                cv2_imwrite(output_debug_path / (filepath.stem + '.jpg'),
                            debug_image, [int(cv2.IMWRITE_JPEG_QUALITY), 50])

            return data
예제 #28
0
 def get_face_type(self):
     return self.dfl_dict.get('face_type', FaceType.toString(FaceType.FULL))
예제 #29
0
def extract_vggface2_dataset(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.')

    bb_csv = input_path / 'loose_bb_train.csv'
    if not bb_csv.exists():
        raise ValueError('loose_bb_train.csv found. Please ensure it exists.')

    bb_lines = bb_csv.read_text().split('\n')
    bb_lines.pop(0)

    bb_dict = {}
    for line in bb_lines:
        name, l, t, w, h = line.split(',')
        name = name[1:-1]
        l, t, w, h = [int(x) for x in (l, t, w, h)]
        bb_dict[name] = (l, t, w, h)

    output_path = input_path.parent / (input_path.name + '_out')

    dir_names = pathex.get_all_dir_names(input_path)

    if not output_path.exists():
        output_path.mkdir(parents=True, exist_ok=True)

    data = []
    for dir_name in io.progress_bar_generator(dir_names, "Collecting"):
        cur_input_path = input_path / dir_name
        cur_output_path = output_path / dir_name

        if not cur_output_path.exists():
            cur_output_path.mkdir(parents=True, exist_ok=True)

        input_path_image_paths = pathex.get_image_paths(cur_input_path)

        for filename in input_path_image_paths:
            filename_path = Path(filename)

            name = filename_path.parent.name + '/' + filename_path.stem
            if name not in bb_dict:
                continue

            l, t, w, h = bb_dict[name]
            if min(w, h) < 128:
                continue

            data += [
                ExtractSubprocessor.Data(filename=filename,
                                         rects=[(l, t, l + w, t + h)],
                                         landmarks_accurate=False,
                                         force_output_path=cur_output_path)
            ]

    face_type = FaceType.fromString('full_face')

    io.log_info('Performing 2nd pass...')
    data = ExtractSubprocessor(data,
                               'landmarks',
                               256,
                               face_type,
                               debug_dir=None,
                               multi_gpu=multi_gpu,
                               cpu_only=cpu_only,
                               manual=False).run()

    io.log_info('Performing 3rd pass...')
    ExtractSubprocessor(data,
                        'final',
                        256,
                        face_type,
                        debug_dir=None,
                        multi_gpu=multi_gpu,
                        cpu_only=cpu_only,
                        manual=False,
                        final_output_path=None).run()
예제 #30
0
        def process_data(self, data):
            filename_path = Path(data[0])

            filename_path_str = str(filename_path)
            if self.cached_image[0] == filename_path_str:
                image = self.cached_image[1]
            else:
                image = cv2_imread(filename_path_str)
                self.cached_image = (filename_path_str, image)

            if image is None:
                self.log_err(
                    'Failed to extract %s, reason: cv2_imread() fail.' %
                    (str(filename_path)))
            else:
                if self.type == 'rects':
                    rects = self.e.extract_from_bgr(image)
                    return [str(filename_path), rects]

                elif self.type == 'landmarks':
                    rects = data[1]
                    landmarks = self.e.extract_from_bgr(image, rects)
                    return [str(filename_path), landmarks]

                elif self.type == 'final':
                    src_dflimg = None
                    (h, w, c) = image.shape
                    if h == w:
                        #extracting from already extracted jpg image?
                        if filename_path.suffix == '.jpg':
                            src_dflimg = DFLJPG.load(str(filename_path))

                    result = []
                    faces = data[1]

                    if self.debug:
                        debug_output_file = '{}{}'.format(
                            str(
                                Path(str(self.output_path) + '_debug') /
                                filename_path.stem), '.jpg')
                        debug_image = image.copy()

                    face_idx = 0
                    for face in faces:
                        rect = np.array(face[0])
                        image_landmarks = np.array(face[1])

                        if self.face_type == FaceType.MARK_ONLY:
                            face_image = image
                            face_image_landmarks = image_landmarks
                        else:
                            image_to_face_mat = LandmarksProcessor.get_transform_mat(
                                image_landmarks, self.image_size,
                                self.face_type)
                            face_image = cv2.warpAffine(
                                image, image_to_face_mat,
                                (self.image_size, self.image_size),
                                cv2.INTER_LANCZOS4)
                            face_image_landmarks = LandmarksProcessor.transform_points(
                                image_landmarks, image_to_face_mat)

                            landmarks_bbox = LandmarksProcessor.transform_points(
                                [(0, 0), (0, self.image_size - 1),
                                 (self.image_size - 1, self.image_size - 1),
                                 (self.image_size - 1, 0)], image_to_face_mat,
                                True)

                            rect_area = mathlib.polygon_area(
                                np.array(rect[[0, 2, 2, 0]]),
                                np.array(rect[[1, 1, 3, 3]]))
                            landmarks_area = mathlib.polygon_area(
                                landmarks_bbox[:, 0], landmarks_bbox[:, 1])

                            if landmarks_area > 4 * rect_area:  #get rid of faces which umeyama-landmark-area > 4*detector-rect-area
                                continue

                        if self.debug:
                            LandmarksProcessor.draw_rect_landmarks(
                                debug_image, rect, image_landmarks,
                                self.image_size, self.face_type)

                        output_file = '{}_{}{}'.format(
                            str(self.output_path / filename_path.stem),
                            str(face_idx), '.jpg')
                        face_idx += 1

                        if src_dflimg is not None:
                            #if extracting from dflimg just copy it in order not to lose quality
                            shutil.copy(str(filename_path), str(output_file))
                        else:
                            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())

                        result.append(output_file)

                    if self.debug:
                        cv2_imwrite(debug_output_file, debug_image,
                                    [int(cv2.IMWRITE_JPEG_QUALITY), 50])

                    return result
            return None