import sys import os # 依存関係のインストール os.system("git clone https://github.com/sczhou/CodeFormer.git") os.system("cd CodeFormer && pip install -r requirements.txt") os.system("cd CodeFormer && python basicsr/setup.py develop") sys.path.append(os.path.abspath('CodeFormer')) sys.path.append(os.path.abspath('CodeFormer/CodeFormer')) # ウェイトファイルをダウンロード(毎回消えるので毎回必ず実行。) if not os.path.exists('realesr-general-x4v3.pth'): os.system("wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth -P .") if not os.path.exists('GFPGANv1.2.pth'): os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.2.pth -P .") if not os.path.exists('GFPGANv1.3.pth'): os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P .") if not os.path.exists('GFPGANv1.4.pth'): os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth -P .") if not os.path.exists('RestoreFormer.pth'): os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth -P .") if not os.path.exists('CodeFormer.pth'): os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/CodeFormer.pth -P .") import cv2 import torch from flask import Flask, request, jsonify, send_file from basicsr.archs.srvgg_arch import SRVGGNetCompact from gfpgan.utils import GFPGANer from realesrgan.utils import RealESRGANer import uuid import tempfile from torchvision.transforms.functional import normalize from torchvision import transforms from PIL import Image from basicsr.utils import img2tensor, tensor2img from facexlib.utils.face_restoration_helper import FaceRestoreHelper from codeformer.archs.codeformer_arch import CodeFormer app = Flask(__name__) # モデルの初期化 model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu') model_path = 'realesr-general-x4v3.pth' half = True if torch.cuda.is_available() else False upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=half) os.makedirs('output', exist_ok=True) def restore_with_codeformer(img, scale=2, weight=0.5): device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') net = CodeFormer(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9, connect_list=['32', '64', '128', '256']).to(device) net.load_state_dict(torch.load('CodeFormer.pth')['params_ema']) net.eval() img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = Image.fromarray(img) face_helper = FaceRestoreHelper( upscale_factor=scale, face_size=512, crop_ratio=(1, 1), use_parse=True, device=device) face_helper.clean_all() face_helper.read_image(img) face_helper.get_face_landmarks_5(only_center_face=False, resize=640) face_helper.align_warp_face() for idx, cropped_face in enumerate(face_helper.cropped_faces): cropped_face_t = img2tensor(cropped_face / 255.0, bgr2rgb=False, float32=True) normalize(cropped_face_t, [0.5], [0.5], inplace=True) cropped_face_t = cropped_face_t.unsqueeze(0).to(device) with torch.no_grad(): output = net(cropped_face_t, w=weight, adain=True)[0] restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1)) face_helper.add_restored_face(restored_face) restored_img = face_helper.paste_faces_to_input_image() return cv2.cvtColor(restored_img, cv2.COLOR_RGB2BGR) @app.route('/api/restore', methods=['POST']) def restore_image(): try: # リクエストからパラメータを取得 if 'file' not in request.files: return jsonify({'error': 'No file uploaded'}), 400 file = request.files['file'] version = request.form.get('version', 'v1.4') scale = float(request.form.get('scale', 2)) weight = float(request.form.get('weight', 0.5)) # CodeFormer用のweightパラメータ # 一時ファイルに保存 temp_dir = tempfile.mkdtemp() input_path = os.path.join(temp_dir, file.filename) file.save(input_path) # 画像処理 extension = os.path.splitext(os.path.basename(str(input_path)))[1] img = cv2.imread(input_path, cv2.IMREAD_UNCHANGED) if len(img.shape) == 3 and img.shape[2] == 4: img_mode = 'RGBA' elif len(img.shape) == 2: img_mode = None img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) else: img_mode = None h, w = img.shape[0:2] if h < 300: img = cv2.resize(img, (w * 2, h * 2), interpolation=cv2.INTER_LANCZOS4) # バージョンに応じてモデルを選択 if version == 'v1.2': face_enhancer = GFPGANer( model_path='GFPGANv1.2.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler) _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) elif version == 'v1.3': face_enhancer = GFPGANer( model_path='GFPGANv1.3.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler) _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) elif version == 'v1.4': face_enhancer = GFPGANer( model_path='GFPGANv1.4.pth', upscale=2, arch='clean', channel_multiplier=2, bg_upsampler=upsampler) _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) elif version == 'RestoreFormer': face_enhancer = GFPGANer( model_path='RestoreFormer.pth', upscale=2, arch='RestoreFormer', channel_multiplier=2, bg_upsampler=upsampler) _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) elif version == 'CodeFormer': output = restore_with_codeformer(img, scale=scale, weight=weight) elif version == 'RealESR-General-x4v3': face_enhancer = GFPGANer( model_path='realesr-general-x4v3.pth', upscale=2, arch='realesr-general', channel_multiplier=2, bg_upsampler=upsampler, map_location=torch.device('cpu')) _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True) # スケール調整 if scale != 2: interpolation = cv2.INTER_AREA if scale < 2 else cv2.INTER_LANCZOS4 h, w = img.shape[0:2] output = cv2.resize(output, (int(w * scale / 2), int(h * scale / 2)), interpolation=interpolation) # 出力ファイルを保存 output_filename = f'output_{uuid.uuid4().hex}' if img_mode == 'RGBA': output_path = os.path.join('output', f'{output_filename}.png') cv2.imwrite(output_path, output) mimetype = 'image/png' else: output_path = os.path.join('output', f'{output_filename}.jpg') cv2.imwrite(output_path, output) mimetype = 'image/jpeg' # 結果を返す return send_file(output_path, mimetype=mimetype, as_attachment=True, download_name=os.path.basename(output_path)) except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/') def index(): return """