|
|
import gradio as gr |
|
|
import os |
|
|
import tempfile |
|
|
import numpy as np |
|
|
import axengine as axe |
|
|
import cv2 |
|
|
from utils.restoration_helper import RestoreHelper |
|
|
|
|
|
restore_helper = RestoreHelper( |
|
|
upscale_factor=1, |
|
|
face_size=512, |
|
|
crop_ratio=(1, 1), |
|
|
det_model="../model/yolov5l-face.axmodel", |
|
|
res_model="../model/codeformer.axmodel", |
|
|
bg_model="../model/realesrgan-x2.axmodel", |
|
|
save_ext='png', |
|
|
use_parse=True |
|
|
) |
|
|
|
|
|
def face(img_path, session): |
|
|
|
|
|
output_names = [x.name for x in session.get_outputs()] |
|
|
input_name = session.get_inputs()[0].name |
|
|
|
|
|
ori_image = cv2.imread(img_path) |
|
|
h, w = ori_image.shape[:2] |
|
|
image = cv2.resize(ori_image, (512, 512)) |
|
|
image = (image[..., ::-1] /255.0).astype(np.float32) |
|
|
|
|
|
mean = [0.5, 0.5, 0.5] |
|
|
std = [0.5, 0.5, 0.5] |
|
|
image = ((image - mean) / std).astype(np.float32) |
|
|
|
|
|
|
|
|
img = np.transpose(np.expand_dims(np.ascontiguousarray(image), axis=0), (0,3,1,2)) |
|
|
|
|
|
|
|
|
sr = session.run(output_names, {input_name: img}) |
|
|
|
|
|
|
|
|
sr = np.transpose(sr[0].squeeze(0), (1,2,0)) |
|
|
sr = (sr*std + mean).astype(np.float32) |
|
|
|
|
|
|
|
|
ndarr = np.clip((sr*255.0), 0, 255.0).astype(np.uint8) |
|
|
out_image = cv2.resize(ndarr[..., ::-1], (w, h)) |
|
|
|
|
|
return out_image |
|
|
|
|
|
def full_image(img_path, restore_helper=restore_helper): |
|
|
|
|
|
restore_helper.clean_all() |
|
|
img = cv2.imread(img_path, cv2.IMREAD_COLOR) |
|
|
|
|
|
restore_helper.read_image(img) |
|
|
|
|
|
num_det_faces = restore_helper.get_face_landmarks_5( |
|
|
only_center_face=False, resize=640, eye_dist_threshold=5) |
|
|
|
|
|
restore_helper.align_warp_face() |
|
|
|
|
|
for idx, cropped_face in enumerate(restore_helper.cropped_faces): |
|
|
|
|
|
cropped_face_t = (cropped_face.astype(np.float32) / 255.0) * 2.0 - 1.0 |
|
|
cropped_face_t = np.transpose( |
|
|
np.expand_dims(np.ascontiguousarray(cropped_face_t[...,::-1]), axis=0), |
|
|
(0,3,1,2) |
|
|
) |
|
|
|
|
|
|
|
|
try: |
|
|
ort_outs = restore_helper.rs_sessison.run( |
|
|
restore_helper.rs_output, |
|
|
{restore_helper.rs_input: cropped_face_t} |
|
|
) |
|
|
restored_face = ort_outs[0] |
|
|
restored_face = (restored_face.squeeze().transpose(1, 2, 0) * 0.5 + 0.5) * 255 |
|
|
restored_face = np.clip(restored_face[...,::-1], 0, 255).astype(np.uint8) |
|
|
except Exception as error: |
|
|
print(f'\tFailed inference for CodeFormer: {error}') |
|
|
restored_face = (cropped_face_t.squeeze().transpose(1, 2, 0) * 0.5 + 0.5) * 255 |
|
|
restored_face = np.clip(restored_face, 0, 255).astype(np.uint8) |
|
|
|
|
|
restored_face = restored_face.astype('uint8') |
|
|
restore_helper.add_restored_face(restored_face, cropped_face) |
|
|
|
|
|
|
|
|
|
|
|
bg_img = restore_helper.background_upsampling(img) |
|
|
restore_helper.get_inverse_affine(None) |
|
|
|
|
|
restored_img = restore_helper.paste_faces_to_input_image(upsample_img=bg_img, draw_box=False) |
|
|
|
|
|
return restored_img |
|
|
|
|
|
|
|
|
def colorize_image(input_img_path: str, model_name: str, progress=gr.Progress()): |
|
|
if not input_img_path: |
|
|
raise gr.Error("未上传图片") |
|
|
|
|
|
|
|
|
progress(0.3, desc="加载图像...") |
|
|
|
|
|
|
|
|
if model_name == "Face": |
|
|
out = face(input_img_path, session=restore_helper.rs_sessison) |
|
|
else: |
|
|
out = full_image(input_img_path, restore_helper=restore_helper) |
|
|
|
|
|
progress(0.9, desc="保存结果...") |
|
|
|
|
|
|
|
|
output_path = os.path.join(tempfile.gettempdir(), "restore_output.jpg") |
|
|
cv2.imwrite(output_path, out) |
|
|
|
|
|
progress(1.0, desc="完成!") |
|
|
return output_path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
custom_css = """ |
|
|
body, .gradio-container { |
|
|
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; |
|
|
} |
|
|
.model-buttons .wrap { |
|
|
display: flex; |
|
|
gap: 10px; |
|
|
} |
|
|
.model-buttons .wrap label { |
|
|
background-color: #f0f0f0; |
|
|
padding: 10px 20px; |
|
|
border-radius: 8px; |
|
|
cursor: pointer; |
|
|
text-align: center; |
|
|
font-weight: 600; |
|
|
border: 2px solid transparent; |
|
|
flex: 1; |
|
|
} |
|
|
.model-buttons .wrap label:hover { |
|
|
background-color: #e0e0e0; |
|
|
} |
|
|
.model-buttons .wrap input[type="radio"]:checked + label { |
|
|
background-color: #4CAF50; |
|
|
color: white; |
|
|
border-color: #45a049; |
|
|
} |
|
|
""" |
|
|
|
|
|
with gr.Blocks(title="人脸修复工具") as demo: |
|
|
gr.Markdown("## 🎨 人脸修复演示DEMO") |
|
|
|
|
|
with gr.Row(equal_height=True): |
|
|
|
|
|
with gr.Column(scale=1, min_width=300): |
|
|
gr.Markdown("### 📤 输入") |
|
|
input_image = gr.Image( |
|
|
type="filepath", |
|
|
label="上传图片", |
|
|
sources=["upload"], |
|
|
height=300 |
|
|
) |
|
|
|
|
|
gr.Markdown("### 🔧 选择修复模式") |
|
|
model_choice = gr.Radio( |
|
|
choices=["Face", "Full image"], |
|
|
value="Face", |
|
|
label=None, |
|
|
elem_classes="model-buttons" |
|
|
) |
|
|
|
|
|
run_btn = gr.Button("🚀 开始修复", variant="primary") |
|
|
|
|
|
|
|
|
with gr.Column(scale=1, min_width=600): |
|
|
gr.Markdown("### 🖼️ 修复结果") |
|
|
output_image = gr.Image( |
|
|
label="修复后图片", |
|
|
interactive=False, |
|
|
height=600 |
|
|
) |
|
|
download_btn = gr.File(label="📥 下载修复图片") |
|
|
|
|
|
|
|
|
def on_colorize(img_path, model, progress=gr.Progress()): |
|
|
if img_path is None: |
|
|
raise gr.Error("请先上传图片!") |
|
|
try: |
|
|
result_path = colorize_image(img_path, model, progress=progress) |
|
|
return result_path, result_path |
|
|
except Exception as e: |
|
|
raise gr.Error(f"处理失败: {str(e)}") |
|
|
|
|
|
run_btn.click( |
|
|
fn=on_colorize, |
|
|
inputs=[input_image, model_choice], |
|
|
outputs=[output_image, download_btn] |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft(), css=custom_css) |