# -*- coding: utf-8 -*-
##--------------------------------------------------
## Stable Diffusion with diffusers(042) Ver 0.00
## GUI interface
## 2025.06.17 Masahiro Izutsu
##--------------------------------------------------
## sd_042.py
## Ver 0.00 2025.06.17 GUI 対応版
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'
# インポート&初期設定
import os
import numpy as np
import random
import cv2
import PySimpleGUI as sg
import sd_041 as sd
import my_logging
# 定数定義
DEF_THEME = 'BlueMono'
CANVAS_SIZE = 512
KEY_CANCEL = '-Cancel-'
KEY_IMAGE = '-Image-'
KEY_OUTPATH = '-Output-'
KEY_MODEL = '-Model-'
KEY_MODELSEL = '-Model_sel-'
KEY_PROMPT_JP = '-PromptJP-'
KEY_PROMPT = '-Prompt-'
KEY_WIDTH = '-Width-'
KEY_HEIGHT = '-Height-'
KEY_SEED_INPUT = '-Seed_input-'
KEY_SEED = '-Seed-'
KEY_STEP = '-Step-'
KEY_SCALE = '-Scale-'
KEY_CPU = '-CPU-'
KEY_GPU = '-GPU-'
KEY_DEVICE = '-Device-'
KEY_EXIT = '-Exit-'
KEY_GENERATE = '-Generate-'
KEY_LOOP = '-Loop-'
SKEY_RESULT_PATH = '-result_path-'
SKEY_RESULT_FILE = '-result_file-'
SKEY_MODEL_DIR = '-model_dir-'
DEF_IMAGE = './sd_results/sd_00000_12345678.png'
# タイトル
title = 'Stable Diffusion with diffusers(042) Ver 0.00'
# ウィジェットのデータの取得
def get_paramlist(window, values, param):
param[KEY_MODEL] = window[KEY_MODEL].DisplayText
param[KEY_WIDTH] = int(values[KEY_WIDTH])
param[KEY_HEIGHT] = int(values[KEY_HEIGHT])
param[KEY_SEED] = sd._get_seed_value2(values[KEY_SEED_INPUT])
param[KEY_STEP] = int(values[KEY_STEP])
param[KEY_SCALE] = float(values[KEY_SCALE])
param[KEY_DEVICE] = 'cpu' if values[KEY_CPU] == True else 'cuda'
param[KEY_PROMPT_JP] = values[KEY_PROMPT_JP]
param[KEY_PROMPT] = sd._get_prompt2(param[KEY_PROMPT_JP])
param[KEY_LOOP] = values[KEY_LOOP]
'''
logger.debug(f'{param[KEY_MODEL]}')
logger.debug(f'{param[KEY_PROMPT]}')
logger.debug(f'{param[KEY_WIDTH]}')
logger.debug(f'{param[KEY_HEIGHT]}')
logger.debug(f'{param[KEY_SEED]}')
logger.debug(f'{param[KEY_STEP]}')
logger.debug(f'{param[KEY_SCALE]}')
logger.debug(f'{param[KEY_DEVICE]}')
logger.debug(f'{param[KEY_LOOP]}')
'''
# 生成画像のファイル名からシード値を得る
def path2seed(filepath):
s = os.path.splitext(os.path.basename(filepath))[0]
n = s.rfind('_')
return int(s[n + 1:])
# 画像生成
def generate_image(param):
model = param[SKEY_MODEL_DIR] + '/' + param[KEY_MODEL]
prompt = param[KEY_PROMPT]
width = param[KEY_WIDTH]
height = param[KEY_HEIGHT]
seed = param[KEY_SEED]
num_inference_steps = param[KEY_STEP]
guidance_scale = param[KEY_SCALE]
device = param[KEY_DEVICE]
out_path = param[SKEY_RESULT_PATH] + '/' + sd.make_filename_by_seq(param[SKEY_RESULT_PATH], param[SKEY_RESULT_FILE], seq_digit = 5, ex = seed)
param[KEY_OUTPATH] = out_path
logger.debug(f'model: {model}')
logger.debug(f'prompt: {prompt}')
logger.debug(f'width: {width}')
logger.debug(f'height: {height}')
logger.debug(f'seed: {seed}')
logger.debug(f'num_inference_steps: {num_inference_steps}')
logger.debug(f'guidance_scale: {guidance_scale}')
logger.debug(f'device: {device}')
logger.debug(f'out_path: {out_path}')
image = sd.image_generation(model, prompt, seed, num_inference_steps, guidance_scale, width, height, device)
image.save(out_path)
logger.info(f'result_file: {out_path}')
# ** main関数 **
def main(opt, logger):
# ------------------------------------------
# キャンバスをクリア
def clear_canvas(key, frame, msg, color):
frame[:,:,] = 0xf0
img = cv2_putText(img = frame, text = msg, org = (CANVAS_SIZE//2, CANVAS_SIZE//2), fontFace = font_face, fontScale = 16, color = color, mode = 2)
img = cv2.imencode('.png', frame)[1].tobytes()
window[key].update(img)
# キャンバスへ画像の表示
def update_canvas(key, frame, imgfile):
if os.path.isfile(imgfile):
frame = cv2.imread(imgfile)
frame = cv2.resize(frame, dsize = (CANVAS_SIZE, CANVAS_SIZE))
img = cv2.imencode('.png', frame)[1].tobytes()
window[key].update(img)
else:
clear_canvas(key, frame, 'Generate Image', (0,0,0))
# ------------------------------------------
# パラメータ設定
device = sd._get_device(opt, logger)
result_path = sd._get_result_path(opt, logger)
result_file = sd._get_result_file(opt, logger)
prompt = sd._get_prompt(opt, logger)
model_path = sd._get_model_path(opt, logger)
height, width = sd._get_image_size(opt, logger)
seed = path2seed(DEF_IMAGE) # 初期ファイル名に含まれるシード値
num_inference_steps = sd._get_inference_steps(opt, logger)
guidance_scale = sd._get_guidance_scale(opt, logger)
param = {}
param[KEY_OUTPATH] = DEF_IMAGE
param[KEY_PROMPT_JP] = opt.prompt
param[KEY_PROMPT] = prompt
param[KEY_MODEL] = opt.model_path
param[KEY_WIDTH] = width
param[KEY_HEIGHT] = height
param[KEY_SEED_INPUT] = opt.seed
param[KEY_SEED] = seed
param[KEY_STEP] = num_inference_steps
param[KEY_SCALE] = guidance_scale
param[KEY_DEVICE] = device
param[KEY_LOOP] = 1
param[SKEY_RESULT_PATH] = result_path
param[SKEY_RESULT_FILE] = result_file
param[SKEY_MODEL_DIR] = opt.model_dir
# 出力フォルダ
os.makedirs(result_path, exist_ok = True)
# フォント取得
from my_puttext import get_font, cv2_putText
font_face = get_font()
# ウィンドウのテーマ
sg.theme(DEF_THEME)
canvas_img = sg.Image(size = (CANVAS_SIZE, CANVAS_SIZE), key=KEY_IMAGE)
# ウィンドウのレイアウト
layout = [[sg.Text('Stable Diffusion with diffusers', size=(30, 1), justification='center', font='Helvetica 20')],
[canvas_img],
[sg.Text("Output File", size=(14, 1)), sg.Text(param[KEY_OUTPATH], size=(48,1), key=KEY_OUTPATH)],
[sg.Text("Model", size=(14, 1)), sg.Text(param[KEY_MODEL], size=(38,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_MODEL),sg.Button('Model', size=(6, 1), key=KEY_MODELSEL)],
[sg.Text("Prompt input", size=(14, 1)), sg.Multiline(param[KEY_PROMPT_JP], size=(52,4), key=KEY_PROMPT_JP)],
[sg.Text("Prompt", size=(14, 1)), sg.Multiline(param[KEY_PROMPT], size=(52,4), text_color='#008800', background_color='LightSteelBlue1', key=KEY_PROMPT)],
[sg.Text("Image size (pixel)", size=(14, 1)), sg.Text("Width: ", size=(4, 1)), sg.Input(param[KEY_WIDTH], size=(10,1), key=KEY_WIDTH), sg.Text("Height: ", size=(4, 1)), sg.Input(param[KEY_HEIGHT], size=(10,1), key=KEY_HEIGHT)],
[sg.Text("Seed (-1=Random)", size=(14, 1)), sg.Input(param[KEY_SEED_INPUT], size=(20,1), key=KEY_SEED_INPUT), sg.Text(param[KEY_SEED], size=(20,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_SEED)],
[sg.Text("Detail (Steps)", size=(14, 1)), sg.Slider((10, 150), float(param[KEY_STEP]), 1, orientation='h', size=(42, 5), key=KEY_STEP)],
[sg.Text("Guidance Scale", size=(14, 1)), sg.Slider((1, 50), float(param[KEY_SCALE]), 0.1, orientation='h', size=(42, 5), key=KEY_SCALE)],
[sg.Text("Device", size=(14, 1)), sg.Radio('CPU', group_id='device', default=(device == 'cpu'), key=KEY_CPU), sg.Radio("GPU", group_id='device', default=(device == 'cuda'), key=KEY_GPU)],
[sg.Text("Generate loop", size=(14, 1)), sg.Spin(values=[i for i in range(1, 50)], initial_value=int(param[KEY_LOOP]), key=KEY_LOOP), sg.Text("", size=(4, 1)), sg.Button('Generate', size=(10, 1), key=KEY_GENERATE), sg.Text("", size=(10, 1)), sg.Button('Exit', size=(10, 1), key=KEY_EXIT)]
]
# ウィンドウオブジェクトの作成
window = sg.Window(title, layout, finalize=True, return_keyboard_events=True)
# キャンバス初期化
frame = np.zeros((CANVAS_SIZE, CANVAS_SIZE, 3), np.uint8)
update_canvas(KEY_IMAGE, frame, param[KEY_OUTPATH])
new_make_f = False
# イベントのループ
while True:
event, values = window.read(timeout = 30)
# 処理動画作成
if new_make_f:
# 処理プロセス
generate_image(param)
update_canvas(KEY_IMAGE, frame, param[KEY_OUTPATH])
window[KEY_OUTPATH].update(param[KEY_OUTPATH])
window[KEY_GENERATE].update(disabled = False)
window[KEY_EXIT].update(disabled = False)
new_make_f = False
# 終了
if event == KEY_EXIT or event == sg.WIN_CLOSED:
break
# Genarate ボタン
if event == KEY_GENERATE:
logger.debug(f'{event}')
window[KEY_GENERATE].update(disabled = True)
window[KEY_EXIT].update(disabled = True)
get_paramlist(window, values, param)
clear_canvas(KEY_IMAGE, frame, 'Generating ...', (240,0,0))
window[KEY_OUTPATH].update('')
window[KEY_PROMPT].update(param[KEY_PROMPT])
window[KEY_SEED].update(param[KEY_SEED])
new_make_f = True
# ウィンドウ終了処理
window.close()
# main関数エントリーポイント(実行開始)
if __name__ == "__main__":
import datetime
parser = sd.parse_args()
opt = 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(opt.log))
sd.display_info(opt, title)
start_time = datetime.datetime.now() # 時間計測開始
main(opt, logger)
# 経過時間
end_time = datetime.datetime.now()
print(start_time.strftime('\nprocessing start >>\t %Y/%m/%d %H:%M:%S'))
print(end_time.strftime('processing end >>\t %Y/%m/%d %H:%M:%S'))
print('processing time >>\t', end_time - start_time)
logger.info('\nFinished.\n')
※ 上記ソースコードは表示の都合上、半角コード '}' が 全角 '}'になっていることに注意