# -*- coding: utf-8 -*-
##------------------------------------------
## DLFS GUI program Ver 0.02
## Disentangled Lifespan Face Synthesis (ICCV 2021)
## DLFSで、人間の年齢による顔の変化をシミュレーションする
##
## 2024.08.08 Masahiro Izutsu
##------------------------------------------
## dlfs_gui.py
import warnings
warnings.simplefilter('ignore')
# Color Escape Code ---------------------------
GREEN = '\033[1;32m'
RED = '\033[1;31m'
NOCOLOR = '\033[0m'
YELLOW = '\033[1;33m'
CYAN = '\033[1;36m'
BLUE = '\033[1;34m'
from torch.cuda import is_available
gpu_d = is_available() # GPU 確認
# インポート&初期設定
import os
import argparse
import numpy as np
import cv2
from PIL import Image, ImageTk
import PySimpleGUI as sg
import my_logging
import my_imagetool
import my_dialog
if gpu_d:
import dlfs_demo
# 定数定義
SOURCE_IMAGE = './images/14.jpg'
RESULT_IMAGE = './results/result.mp4'
IMAGE_DIR = './images'
KEY_ORGIMAGE = '-Org-'
KEY_PRSIMAGE = '-Prs-'
KEY_MALE = '-Male-'
KEY_FEMALE = '-Female-'
KEY_IMAGESEL = '-Image-'
KEY_EXIT = '-Exit-'
KEY_TXTORG = '-Source-'
KEY_TXTPRS = '-Process-'
KEY_CREATE = '-Create-'
IMG_CANCAS_SIZE = 256
# タイトル
title = 'DLFS GUI program Ver. 0.02'
sub_title = '' if gpu_d else ' <view mode>'
# Parses arguments for the application
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--model', type = str, default='males_model', choices=['males_model', 'females_model'], help = 'females_model / males_model')
parser.add_argument("--source_image", default=SOURCE_IMAGE, help="path to source image")
parser.add_argument("--result_image", default=RESULT_IMAGE, help="path to output")
parser.add_argument("--cpu", dest="cpu", action="store_true", help="cpu mode.")
parser.add_argument('--log', metavar = 'LOG', default = '3', help = 'Log level(-1/0/1/2/3/4/5) Default value is \'3\'')
return parser
# 基本情報の表示
def display_info(opt, title):
print('\n' + GREEN + title + ': Starting application...' + NOCOLOR)
print('\n - ' + YELLOW + 'model : ' + NOCOLOR, args.model)
print(' - ' + YELLOW + 'source_image : ' + NOCOLOR, opt.source_image)
print(' - ' + YELLOW + 'result_image : ' + NOCOLOR, opt.result_image)
print(' - ' + YELLOW + 'cpu : ' + NOCOLOR, opt.cpu)
print(' - ' + YELLOW + 'log : ' + NOCOLOR, opt.log)
print(' ')
# ソースファイル名とモデル名を含んだ出力ファイル名を得る
def get_outpath(source_image, result_image, model):
base_dir_pair = os.path.split(source_image)
s_name, ext = os.path.splitext(base_dir_pair[1])
base_dir_pair = os.path.split(result_image)
name, ext = os.path.splitext(base_dir_pair[1])
result_image = base_dir_pair[0] + '/' + model + '_' + s_name + ext
return result_image
# カレントディレクトリ配下のディレクトリからファイルを選択
def get_image_file(tgt_dir, msg = ''):
# カレントディレクトリ配下の指定のみ有効
import re
image_file = ''
cpath = os.getcwd()
cpath = re.sub(r'\\', '/', cpath)
while True:
image_file = my_dialog.select_image_file(msg, tgt_dir)
if len(image_file) == 0:
break
parir = os.path.split(image_file)
parir = os.path.split(parir[0])
if cpath == parir[0]:
break
return image_file
# ファイル名の整形
def get_filename(image_path):
base_dir_pair = os.path.split(image_path)
name = base_dir_pair[1]
base_dir_pair = os.path.split(base_dir_pair[0])
name = './' + name + '/' + base_dir_pair[1]
return name
# PIL リサイズ
def pil_resize(path, width, height):
image = Image.open(path)
x_ratio = width / image.width
y_ratio = height / image.height
# 画像の幅と高さ両方に小さい方の比率を掛けてリサイズ後のサイズを計算
if x_ratio < y_ratio:
resize_size = (width, round(image.height * x_ratio))
else:
resize_size = (round(image.width * y_ratio), height)
resized_image = image.resize(resize_size)
return resized_image
# メイン処理
def main_process(args, logger, opt, dataset, visualize):
model = args.model
base_dir_pair = os.path.split(args.source_image)
img_name, ext = os.path.splitext(base_dir_pair[1])
img_dir = base_dir_pair[0] # 画像ディレクトリ
image_path = args.source_image
save_path = args.result_image
short_image_path = get_filename(image_path)
logger.debug(f'model : {model}')
logger.debug(f'image_dir : {img_dir}')
logger.debug(f'image_path : {image_path}')
logger.debug(f'save_path : {save_path}')
radio0 = True if model == 'males_model' else False
radio1 = True if model == 'females_model' else False
# ウィンドウのテーマ
sg.theme('BlueMono')
# ウィンドウのレイアウト
col_image0 = [
[sg.Canvas(size=(IMG_CANCAS_SIZE, IMG_CANCAS_SIZE), key=KEY_ORGIMAGE)],
[sg.Text(short_image_path, background_color='LightSteelBlue1', size=(32, 1), key = KEY_TXTORG)]
]
col_image1 = [
[sg.Image(size=(IMG_CANCAS_SIZE, IMG_CANCAS_SIZE), key=KEY_PRSIMAGE)],
[sg.Text(save_path, background_color='LightSteelBlue1', size=(32, 1), key = KEY_TXTPRS)]
]
col_radio = [
[sg.Text("model", size=(8, 1)), sg.Radio('male', group_id='model',enable_events = True, default=radio0, key=KEY_MALE), sg.Radio('female', group_id='model',enable_events = True, default=radio1, key=KEY_FEMALE)],
]
col_button = [
[sg.Text("", size=(2, 1)), sg.Button('Image', size=(8, 1), key=KEY_IMAGESEL), sg.Button('Create', size=(8, 1), disabled = not gpu_d, key=KEY_CREATE), sg.Text("", size=(1, 1)), sg.Button('Exit', size=(8, 1), key=KEY_EXIT)],
]
layout = [[sg.Text(title + sub_title, size=(34, 1), justification='center', font='Helvetica 18')],
[sg.Column(col_image0), sg.Column(col_image1)],
[sg.Column(col_radio), sg.Column(col_button)],
]
# ウィンドウオブジェクトの作成
window = sg.Window(title, layout, finalize=True, return_keyboard_events=True)
im0_canvas = window[KEY_ORGIMAGE]
tcv_img0 = im0_canvas.TKCanvas
tcv_img0.create_rectangle(0, 0, IMG_CANCAS_SIZE, IMG_CANCAS_SIZE, fill = '#cccccc')
p_image = pil_resize(image_path, IMG_CANCAS_SIZE, IMG_CANCAS_SIZE) # PIL型で読み込み(オリジナル画像)
pht0_image = ImageTk.PhotoImage(image = p_image)
tcv_img0.create_image(IMG_CANCAS_SIZE / 2, IMG_CANCAS_SIZE / 2, image = pht0_image) # Canvasの中心に表示
# 処理動画
cap = cv2.VideoCapture(save_path)
cap_open = cap.isOpened()
new_make_f = False
# イベントのループ
while True:
event, values = window.read(timeout=30)
if new_make_f:
logger.info(f'{CYAN}New image → {save_path}{NOCOLOR}')
if gpu_d:
logger.debug(f'model : {model}')
logger.debug(f'image path : {image_path}')
logger.debug(f'out path : {out_path}')
opt.name = model
dlfs_demo.dlfs_process(model, image_path, save_path, opt, dataset, visualizer, disp_f = False)
cap = cv2.VideoCapture(save_path)
cap_open = cap.isOpened()
new_make_f = False
if event == KEY_EXIT or event == sg.WIN_CLOSED or event == 'Escape:27':
break
if event == KEY_CREATE:
if gpu_d:
if cap_open:
cap.release()
cap_open = False
new_make_f = True
if event == KEY_MALE or event == KEY_FEMALE:
logger.debug(f'{KEY_MALE}, {KEY_FEMALE}')
if values[KEY_MALE]:
model = 'males_model'
elif values[KEY_FEMALE]:
model = 'females_model'
save_path = out_path = get_outpath(image_path, save_path, model)
window[KEY_TXTPRS].update(save_path)
if cap_open:
cap.release()
frame = np.zeros((IMG_CANCAS_SIZE, IMG_CANCAS_SIZE, 3))
frame += 204
img = cv2.imencode('.png', frame)[1].tobytes()
window[KEY_PRSIMAGE].update(img)
cap = cv2.VideoCapture(save_path)
cap_open = cap.isOpened()
if event == KEY_IMAGESEL:
fpath = get_image_file(IMAGE_DIR, msg = IMAGE_DIR + ' ')
if len(fpath) > 0:
# オリジナル画像変更
image_path = fpath
short_image_path = get_filename(image_path)
p_image = pil_resize(image_path, IMG_CANCAS_SIZE, IMG_CANCAS_SIZE) # PIL型で読み込み(オリジナル画像)
pht0_image = ImageTk.PhotoImage(image = p_image)
tcv_img0.create_image(IMG_CANCAS_SIZE / 2, IMG_CANCAS_SIZE / 2, image = pht0_image) # Canvasの中心に表示
save_path = out_path = get_outpath(image_path, save_path, model)
if cap_open:
cap.release()
frame = np.zeros((IMG_CANCAS_SIZE, IMG_CANCAS_SIZE, 3))
frame += 204
img = cv2.imencode('.png', frame)[1].tobytes()
window[KEY_PRSIMAGE].update(img)
cap = cv2.VideoCapture(save_path)
cap_open = cap.isOpened()
short_image_path = get_filename(image_path)
window[KEY_TXTORG].update(short_image_path)
window[KEY_TXTPRS].update(save_path)
if cap_open:
ret, frame = cap.read()
if frame is None:
#最初のフレームに戻る
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
ret, frame = cap.read()
img = cv2.imencode('.png', frame)[1].tobytes()
window[KEY_PRSIMAGE].update(img)
# ウィンドウ終了処理
if cap_open:
cap.release()
window.close()
# main関数エントリーポイント(実行開始
if __name__ == '__main__':
import datetime
parser = parse_args()
args = parser.parse_args()
# アプリケーション・ログ設定
module = os.path.basename(__file__)
module_name = os.path.splitext(module)[0]
logger = my_logging.get_module_logger_sel(module_name, int(args.log))
if len(args.source_image) == 0:
args.source_image = get_image_file(IMAGE_DIR, msg = IMAGE_DIR + ' ')
if len(args.source_image) == 0:
exit(0)
if args.cpu:
gpu_d = False
sub_title = ' <view mode>'
display_info(args, title)
image_path = args.source_image
save_path = get_outpath(args.source_image, args.result_image, args.model)
args.result_image = save_path
model = args.model
logger.debug(f'image path : {image_path}')
logger.debug(f'out path : {save_path}')
opt = None
dataset = None
visualizer = None
if gpu_d:
# 前処理(モデルロード)
opt, dataset, visualizer = dlfs_demo.dlfs_pre_process(model)
if gpu_d and not os.path.isfile(save_path):
logger.debug(f'model : {model}')
logger.debug(f'{CYAN}New image → {save_path}{NOCOLOR}')
opt.name = model
dlfs_demo.dlfs_process(model, image_path, save_path, opt, dataset, visualizer, disp_f = False)
main_process(args, logger, opt, dataset, visualizer)
logger.info('\nFinished.\n')