CoolFace
Apppublic

sczhou/CodeFormer

sourceHugging Faceupdated 4mo agoView on Hugging Face
2.4klikes
app.py381 linesDownload Raw Back to root
1"""2This file is used for deploying hugging face demo:3https://huggingface.co/spaces/sczhou/CodeFormer4"""5import spaces6import sys7sys.path.append('CodeFormer')8import os9import cv210import numpy as np11import torch12import torch.nn.functional as F13import uuid, threading, time, glob14import gradio as gr15 16from torchvision.transforms.functional import normalize17 18from basicsr.utils import imwrite, img2tensor, tensor2img19from basicsr.utils.download_util import load_file_from_url20from facelib.utils.face_restoration_helper import FaceRestoreHelper21from basicsr.archs.rrdbnet_arch import RRDBNet22from basicsr.utils.realesrgan_utils import RealESRGANer23from facelib.utils.misc import is_gray24 25from basicsr.utils.registry import ARCH_REGISTRY26 27 28os.system("pip freeze")29 30pretrain_model_url = {31    'codeformer': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth',32    'detection': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/detection_Resnet50_Final.pth',33    'parsing': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/parsing_parsenet.pth',34    'realesrgan': 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/RealESRGAN_x2plus.pth'35}36# download weights37if not os.path.exists('CodeFormer/weights/CodeFormer/codeformer.pth'):38    load_file_from_url(url=pretrain_model_url['codeformer'], model_dir='CodeFormer/weights/CodeFormer', progress=True, file_name=None)39if not os.path.exists('CodeFormer/weights/facelib/detection_Resnet50_Final.pth'):40    load_file_from_url(url=pretrain_model_url['detection'], model_dir='CodeFormer/weights/facelib', progress=True, file_name=None)41if not os.path.exists('CodeFormer/weights/facelib/parsing_parsenet.pth'):42    load_file_from_url(url=pretrain_model_url['parsing'], model_dir='CodeFormer/weights/facelib', progress=True, file_name=None)43if not os.path.exists('CodeFormer/weights/realesrgan/RealESRGAN_x2plus.pth'):44    load_file_from_url(url=pretrain_model_url['realesrgan'], model_dir='CodeFormer/weights/realesrgan', progress=True, file_name=None)45 46# download images47torch.hub.download_url_to_file(48    'https://replicate.com/api/models/sczhou/codeformer/files/fa3fe3d1-76b0-4ca8-ac0d-0a925cb0ff54/06.png',49    '01.png')50torch.hub.download_url_to_file(51    'https://replicate.com/api/models/sczhou/codeformer/files/a1daba8e-af14-4b00-86a4-69cec9619b53/04.jpg',52    '02.jpg')53torch.hub.download_url_to_file(54    'https://replicate.com/api/models/sczhou/codeformer/files/542d64f9-1712-4de7-85f7-3863009a7c3d/03.jpg',55    '03.jpg')56torch.hub.download_url_to_file(57    'https://replicate.com/api/models/sczhou/codeformer/files/a11098b0-a18a-4c02-a19a-9a7045d68426/010.jpg',58    '04.jpg')59torch.hub.download_url_to_file(60    'https://replicate.com/api/models/sczhou/codeformer/files/7cf19c2c-e0cf-4712-9af8-cf5bdbb8d0ee/012.jpg',61    '05.jpg')62torch.hub.download_url_to_file(63    'https://raw.githubusercontent.com/sczhou/CodeFormer/master/inputs/cropped_faces/0729.png',64    '06.png')65 66 67def imread_unicode_safe(path):68    with open(path, "rb") as f:69        data = np.frombuffer(f.read(), dtype=np.uint8)70    return cv2.imdecode(data, cv2.IMREAD_COLOR)71 72def delayed_remove(path, delay=60):73    time.sleep(delay)74    try:75        if os.path.exists(path):76            os.remove(path)77            print(f"[CLEANUP] removed: {path}")78        else:79            print(f"[CLEANUP] already gone: {path}")80    except Exception as e:81        print(f"[CLEANUP] failed: {path} | {e}")82 83# set enhancer with RealESRGAN84def set_realesrgan():85    half = True if torch.cuda.is_available() else False86    model = RRDBNet(87        num_in_ch=3,88        num_out_ch=3,89        num_feat=64,90        num_block=23,91        num_grow_ch=32,92        scale=2,93    )94    upsampler = RealESRGANer(95        scale=2,96        model_path="CodeFormer/weights/realesrgan/RealESRGAN_x2plus.pth",97        model=model,98        tile=400,99        tile_pad=40,100        pre_pad=0,101        half=half,102    )103    return upsampler104 105upsampler = set_realesrgan()106device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')107codeformer_net = ARCH_REGISTRY.get("CodeFormer")(108    dim_embd=512,109    codebook_size=1024,110    n_head=8,111    n_layers=9,112    connect_list=["32", "64", "128", "256"],113).to(device)114ckpt_path = "CodeFormer/weights/CodeFormer/codeformer.pth"115checkpoint = torch.load(ckpt_path)["params_ema"]116codeformer_net.load_state_dict(checkpoint)117codeformer_net.eval()118 119os.makedirs('output', exist_ok=True)120 121@spaces.GPU122def inference(image, face_align, background_enhance, face_upsample, upscale, codeformer_fidelity):123    """Run a single prediction on the model"""124    try: # global try125        # take the default setting for the demo126        only_center_face = False127        draw_box = False128        detection_model = "retinaface_resnet50"129 130        face_align = face_align if face_align is not None else True131        background_enhance = background_enhance if background_enhance is not None else True132        face_upsample = face_upsample if face_upsample is not None else True133        upscale = upscale if (upscale is not None and upscale > 0) else 2134 135        has_aligned = not face_align136        upscale = 1 if has_aligned else upscale137        138        if isinstance(image, dict):139            image_path = image.get("name")140        elif isinstance(image, str):141            image_path = image142        else:143            image_path = None144            raise gr.Error("Invalid input image.")145        146        if not os.path.exists(image_path):147            raise gr.Error("Invalid input image.")148 149        print('Inp:', image_path, background_enhance, face_upsample, upscale, codeformer_fidelity)150        151        img = imread_unicode_safe(image_path)152 153        if img is None:154            raise gr.Error("Failed to read input image.")155        156        print('\timage size:', img.shape)157 158        upscale = int(upscale) # convert type to int159        if upscale > 4: # avoid memory exceeded due to too large upscale160            upscale = 4 161        if upscale > 2 and max(img.shape[:2])>1000: # avoid memory exceeded due to too large img resolution162            upscale = 2 163        if min(img.shape[:2]) > 1100 or max(img.shape[:2])>1500: # avoid memory exceeded due to too large img resolution164            upscale = 1165            background_enhance = False166            face_upsample = False167 168        h, w = img.shape[:2]169        if h * w > 4_000_000: # avoid memory exceeded due to too large img resolution170            raise gr.Error(171                "Image resolution is too large (>4 megapixels). "172                "To keep the demo responsive and avoid long queue times, this case is skipped. "173                "For such inputs, please deploy this demo locally and remove this limit."174            )175            176        face_helper = FaceRestoreHelper(177            upscale,178            face_size=512,179            crop_ratio=(1, 1),180            det_model=detection_model,181            save_ext="png",182            use_parse=True,183            device=device,184        )185        bg_upsampler = upsampler if background_enhance else None186        face_upsampler = upsampler if face_upsample else None187 188        if has_aligned:189            # the input faces are already cropped and aligned190            img = cv2.resize(img, (512, 512), interpolation=cv2.INTER_LINEAR)191            face_helper.is_gray = is_gray(img, threshold=5)192            if face_helper.is_gray:193                print('\tgrayscale input: True')194            face_helper.cropped_faces = [img]195        else:196            face_helper.read_image(img)197            # get face landmarks for each face198            num_det_faces = face_helper.get_face_landmarks_5(199            only_center_face=only_center_face, resize=640, eye_dist_threshold=5200            )201            print(f'\tdetect {num_det_faces} faces')202            # align and warp each face203            face_helper.align_warp_face()204 205            if min(img.shape[:2]) > 1000 and num_det_faces > 15:206                raise gr.Error(207                    "Too many faces detected (>15) in a high-resolution image. "208                    "To keep the demo responsive and avoid long queue times, this case is skipped. "209                    "For such inputs, please deploy this demo locally and remove this limit."210                )211 212            213        # face restoration for each cropped face214        for idx, cropped_face in enumerate(face_helper.cropped_faces):215            # prepare data216            cropped_face_t = img2tensor(cropped_face / 255., bgr2rgb=True, float32=True)217            normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)218            cropped_face_t = cropped_face_t.unsqueeze(0).to(device)219 220            try:221                with torch.no_grad():222                    output = codeformer_net(223                        cropped_face_t, w=codeformer_fidelity, adain=True224                    )[0]225                    restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))226                del output227                torch.cuda.empty_cache()228            except RuntimeError as error:229                print(f"Failed inference for CodeFormer: {error}")230                restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1))231 232            restored_face = restored_face.astype("uint8")233            face_helper.add_restored_face(restored_face, cropped_face)234 235        # paste_back236        if not has_aligned:237            # upsample the background238            if bg_upsampler is not None:239                # Now only support RealESRGAN for upsampling background240                bg_img = bg_upsampler.enhance(img, outscale=upscale)[0]241            else:242                bg_img = None243            face_helper.get_inverse_affine(None)244            # paste each restored face to the input image245            if face_upsample and face_upsampler is not None:246                restored_img = face_helper.paste_faces_to_input_image(247                    upsample_img=bg_img,248                    draw_box=draw_box,249                    face_upsampler=face_upsampler,250                )251            else:252                restored_img = face_helper.paste_faces_to_input_image(253                    upsample_img=bg_img, draw_box=draw_box254                )255        else:256            restored_img = restored_face257 258        # save restored img259        # save_path = f'output/out.png'260        # imwrite(restored_img, str(save_path))261 262        # restored_img = cv2.cvtColor(restored_img, cv2.COLOR_BGR2RGB)263        # return restored_img264 265 266        #save restored img267        save_path = f"output/{uuid.uuid4().hex}.png"268        imwrite(restored_img, save_path)269        print(f"[SAVE] path={save_path} outputs={len(glob.glob('output/*.png'))}")270        271        threading.Thread(272            target=delayed_remove,273            args=(save_path,30),274            daemon=True275        ).start()276    277        return save_path, None278 279    except gr.Error:280        raise281        282    except Exception as error:283        print('[UNEXPECTED ERROR]', error)284        raise gr.Error("Unexpected error. Please try another image.")285        286 287title = "CodeFormer: Robust Face Restoration and Enhancement Network"288 289description = r"""<center><img src='https://user-images.githubusercontent.com/14334509/189166076-94bb2cac-4f4e-40fb-a69f-66709e3d98f5.png' alt='CodeFormer logo'></center>290<br>291<b>Official Gradio demo</b> for <a href='https://github.com/sczhou/CodeFormer' target='_blank'><b>Towards Robust Blind Face Restoration with Codebook Lookup Transformer (NeurIPS 2022)</b></a><br>292๐Ÿ”ฅ CodeFormer is a robust face restoration algorithm for old photos or AI-generated faces.<br>293๐Ÿค— Try CodeFormer for improved stable-diffusion generation!<br>294"""295 296article = r"""297If CodeFormer is helpful, please help to โญ the <a href='https://github.com/sczhou/CodeFormer' target='_blank'>Github Repo</a>. Thanks! 298[![GitHub Stars](https://img.shields.io/github/stars/sczhou/CodeFormer?style=social)](https://github.com/sczhou/CodeFormer)299 300---301 302๐Ÿ“ **Citation**303 304If our work is useful for your research, please consider citing:305```bibtex306@inproceedings{zhou2022codeformer,307    author = {Zhou, Shangchen and Chan, Kelvin C.K. and Li, Chongyi and Loy, Chen Change},308    title = {Towards Robust Blind Face Restoration with Codebook Lookup TransFormer},309    booktitle = {NeurIPS},310    year = {2022}311}312```313 314๐Ÿ“‹ **License**315 316This project is licensed under <a rel="license" href="https://github.com/sczhou/CodeFormer/blob/master/LICENSE">S-Lab License 1.0</a>. 317Redistribution and use for non-commercial purposes should follow this license.318 319๐Ÿ“ง **Contact**320 321If you have any questions, please feel free to reach me out at <b>shangchenzhou@gmail.com</b>.322 323๐Ÿค— **Find Me:**324<style type="text/css">325td {326    padding-right: 0px !important;327}328 329.gradio-container-4-37-2 .prose table, .gradio-container-4-37-2 .prose tr, .gradio-container-4-37-2 .prose td, .gradio-container-4-37-2 .prose th {330    border: 0px solid #ffffff;331    border-bottom: 0px solid #ffffff;332}333 334</style>335 336<table>337<tr>338    <td><a href="https://github.com/sczhou"><img style="margin:-0.8em 0 2em 0" src="https://img.shields.io/github/followers/sczhou?style=social" alt="Github Follow"></a></td>339    <td><a href="https://twitter.com/ShangchenZhou"><img style="margin:-0.8em 0 2em 0" src="https://img.shields.io/twitter/follow/ShangchenZhou?label=%40ShangchenZhou&style=social" alt="Twitter Follow"></a></td>340</tr>341</table>342 343<center><img src='https://api.infinitescript.com/badgen/count?name=sczhou/CodeFormer&ltext=Visitors&color=6dc9aa' alt='visitors'></center>344"""345 346with gr.Blocks() as demo:347    gr.Markdown(title)348    gr.Markdown(description)349    with gr.Row():350        with gr.Column():351            input_img = gr.Image(type="filepath", label="Input")352            face_align = gr.Checkbox(value=True, label="Pre_Face_Align")353            background_enhance = gr.Checkbox(value=True, label="Background_Enhance")354            face_enhance = gr.Checkbox(value=True, label="Face_Upsample")355            upscale_factor = gr.Number(value=2, label="Rescaling_Factor (up to 4)")356            codeformer_fidelity = gr.Slider(0, 1, value=0.5, step=0.01, label='Codeformer_Fidelity (0 for better quality, 1 for better identity)')357            submit = gr.Button('Enhance Image')358        with gr.Column():359            output_img = gr.Image(type="filepath", label="Output")360            note = gr.Markdown("**Please download the output within 30 seconds.**")361            362    inps = [input_img, face_align, background_enhance, face_enhance, upscale_factor, codeformer_fidelity]363    outs = [output_img, note]364    submit.click(fn=inference, inputs=inps, outputs=outs)365            366    ex = gr.Examples([367        ['01.png', True, True, True, 2, 0.7],368        ['02.jpg', True, True, True, 2, 0.7],369        ['03.jpg', True, True, True, 2, 0.7],370        ['04.jpg', True, True, True, 2, 0.1],371        ['05.jpg', True, True, True, 2, 0.1],372        ['06.png', False, True, True, 1, 0.5]373      ],374        inputs=inps,375        cache_examples=False)376    377    gr.Markdown(article)378    379DEBUG = os.getenv('DEBUG') == '1'380demo.queue(api_open=False, max_size=10, default_concurrency_limit=2)381demo.launch(debug=DEBUG)