私的AI研究会 > AI_Program9
これまで検証してきた結果をもとに、Python で生成 AI プログラムを書く
画像生成のプログラムを書く |
Step | プログラム名 | 機能 |
81 | sd_081.py | 「テキストから画像生成(txt2img)」 |
91 | sd_091.py | 「画像から画像生成(img2img)」 |
40 | sd_040.py | 「instruct-pix2pix」で画像を変換する |
42 | sd_042.py | 「controlnet instruct-pix2pix」で画像を変換する |
44 | sd_044.py | 「controlnet inpaint」で画像の一部を変換する |
46 | sd_046.py | 「outpaint」画像の外側を書き加える |
47 | sd_047.py | 「controlnet scribble」手描きの線画から画像を生成 |
48 | sd_048.py | 「controlnet openpose」画像から同じ姿勢の画像を生成 |
python sd_100--pros_sel [081 / 091 / 040 / 042 / 044 / 046 / 047 / 048]・将来的にはプログラム内でダイナミックに変更できるようにする
(base) PS > conda activate sd_test (sd_test) PS > cd workspace_3/sd_test
pros_sel | sd_81 | sd_091 | sd_040 | sd_042 |
機能 | テキストから画像生成 | 画像をテキストで変更 | 画像から画像を変換生成 | 画像から画像を変換生成 |
text2image | image2image | instruct-pix2pix | controlnet instruct-pix2pix | |
advanced 画面 | ![]() | ![]() | ![]() | ![]() |
normal 画面 | ![]() | ![]() | ![]() | ![]() |
pros_sel | sd_044 | sd_046 | sd_047 | sd_048 |
機能 | 画像の一部を変更 | 画像の外側を書き加える | 手描きの線画から画像を生成 | 画像から同じ姿勢の画像を生成 |
controlnet inpaint | outpaint | controlnet scribble | controlnet openpose | |
advanced 画面 | ![]() | ![]() | ![]() | ![]() |
normal 画面 | ![]() | ![]() | ![]() | ![]() |
コマンドオプション | 引数 | 初期値(--pros_sel sd_044 の例) | 意味 | GUI |
--pros_sel | str | 処理するプログラム名(必須指定) | ||
--result_image | str | './sd_results3/sd.png' | 保存するファイルパスとヘッダ名の指定 | 〇 |
--cpu | bool | False | cpu mode. | |
--log | int | 3 | Log level(-1/0/1/2/3/4/5) | |
--model_dir | str | '/StabilityMatrix/Data/Models/StableDiffusion' | モデルフォルダのパス | |
--model_path | str | 'SD1.5/beautifulRealistic_brav5.safetensors' | モデルファイル | 〇 |
--ctrl_model_dir | str | '/StabilityMatrix/Data/Models/ControlNet' | コントロールネット・モデルフォルダのパス | |
--ctrl_model_path | str | 'control_v11p_sd15_inpaint_fp16.safetensors' | コントロールネット・モデルファイル | 〇 |
--image_path | str | 'images/sd_038_test.png' | 入力画像のファイル・パス名 | 〇 |
--ctrl_image_path | str | 'images/sd_038_test_mask.png' | コントロールネット・入力画像のファイル・パス名 | 〇 |
--max_size | int | 0 | 入力画像リサイズの最大値(0=入力画像サイズ) | 〇 |
--prompt | str | '微笑んでいる女性' | 画像生成のためのプロンプト(日本語/英語) | 〇 |
--seed | int | 12345678 | シード値(-1の時はランダムに生成) | 〇 |
--width | int | 512 | 生成画像サイズの幅 | 〇 |
--height | int | 512 | 生成画像サイズの高さ | 〇 |
--step | int | 20 | 生成ステップ数 | 〇 |
--scale | float | 7.0 | ガイダンススケール値 | 〇 |
--image_scale | float | 1.5 | イメージ・ガイダンススケール値 | |
--cc_scale | float | 1.0 | controlnet conditioning scale | |
--strength | float | 0.6 | 変化の強さを表すパラメータ | 〇 |
--neg_prompt | str | '最悪の品質、おかしい人体構造' | 画像生成のためのネガティブ・プロンプト(日本語/英語) | 〇 |
--mode | bool | True | パラメータ設定モード(advanced/norma) |
python sd_100--pros_sel sd_048
(sd_test) PS python sd_100.py --pros_sel sd_048 Stable Diffusion with diffusers(100) Ver 0.05 <sd_048>: Starting application... --pros_sel : sd_048 --result_image : ./sd_results3/sd.png --cpu : False --log : 3 --model_dir : /StabilityMatrix/Data/Models/StableDiffusion --model_path : SD1.5/beautifulRealistic_brav5.safetensors --ctrl_model_dir : /StabilityMatrix/Data/Models/ControlNet --ctrl_model_path : control_v11p_sd15_openpose_fp16.safetensors --image_path : images/sd_048_test1.png --max_size : 0 --prompt : ダンスを踊る女性 --seed : -1 --step : 20 --neg_prompt : 最悪の品質、おかしい人体構造 prompt: Dancing Woman max_size: 0 width: 512, height: 512 neg_prompt: Worst quality, funny body structure ** Start 1 ** Fetching 11 files: 100%|███████████████████████████████| 11/11 [00:00<?, ?it/s] Loading pipeline components...: 100%|████████████| 6/6 [00:00<00:00, 32.07it/s] 100%|██████████████████████████████████████████| 20/20 [00:02<00:00, 6.93it/s] result_file: ./sd_results3/sd_00012_2292601352.png ** Complete ** 00:00:08 ** Start 1 ** Fetching 11 files: 100%|███████████████████████████████| 11/11 [00:00<?, ?it/s] Loading pipeline components...: 100%|████████████| 6/6 [00:00<00:00, 31.88it/s] 100%|██████████████████████████████████████████| 20/20 [00:02<00:00, 7.23it/s] result_file: ./sd_results3/sd_00013_1070611060.png ** Complete ** 00:00:05 Finished.
# -*- coding: utf-8 -*- ##-------------------------------------------------- ## Stable Diffusion with diffusers(100) Ver 0.05 ## img2img GUI interface ## 2025.07.17 Masahiro Izutsu ##-------------------------------------------------- ## sd_100.py ## Ver 0.00 2025.07.17 Trial version ## Ver 0.05 2025.07.20 sd_100.py 統合版対応 # タイトル title = 'Stable Diffusion with diffusers(100) Ver 0.05' import warnings warnings.simplefilter('ignore') # インポート&初期設定 import os import numpy as np import time import csv import cv2 import PySimpleGUI as sg import my_logging import my_thumbnail import my_dialog import my_imagetool import sd_tools as sdt import sd_results as sdr # 定数定義 DEF_THEME = 'BlueMono' CANVAS_SIZE = 512 DEF_SEED_VAL = '12345678' CSV_LOG_FILE = 'result_100.csv' KEY_CANCEL = '-Cancel-' KEY_IMAGE = '-Image-' KEY_INPUT_IMAGE = '-Input_Image-' KEY_IMAGE_SEL = '-Image_sel-' KEY_CTRL_IMAGE_SEL = '-Ctrl_Image_sel-' KEY_MODELSEL = '-Model_sel-' KEY_CTRL_MODELSEL = '-Ctrl_Model_sel-' KEY_SEED_INPUT = '-Seed_input-' #KEY_CPU = '-CPU-' #KEY_GPU = '-GPU-' KEY_ADVANCED = '-Advanced-' KEY_EXIT = '-Exit-' KEY_GENERATE = '-Generate-' KEY_INPUT_TXT = '-Input_text-' KEY_CTRL_MODEL_TXT ='-ctrl_model_text-' KEY_CTRL_IMGPATH_TXT = '--ctrl_image_path_text--' KEY_MAXSIZE_TXT = '-MaxSize_text-' KEY_WIDTH_TXT = '--Image_width_text--' KEY_HEIGHT_TXT = '--Image_height_text--' KEY_STEP_TXT = '-Step_text-' KEY_SCALE_TXT = '-Scale_text-' KEY_STRENGTH_TXT = '-strength_text-' KEY_SEED_CLR = '--seed_clear--' KEY_SEED_SET = '--seed_set--' SKEY_RESULT_PATH = '-result_path-' SKEY_RESULT_FILE = '-result_file-' SKEY_DEF_OUTPATH = '-default_image-' # csv save KEY_PROS_SEL = '--Proscess--' KEY_OUTPATH = '-Output-' KEY_SEED = '-Seed-' KEY_PROMPT_JP = '-PromptJP-' KEY_PROMPT = '-Prompt-' KEY_INPUTPATH = '-Input-' KEY_MAXSIZE = '-MaxSize-' KEY_STEP = '-Step-' KEY_SCALE = '-Scale-' KEY_STRENGTH = '-strength-' KEY_MODEL_DIR = '-model_dir-' KEY_MODEL = '-Model-' KEY_CTRL_IMGPATH = '--ctrl_image_path--' KEY_CTRL_DIR = '-ctrl_model_dir-' KEY_CTRL_MODEL = '-ctrl_model-' KEY_WIDTH = '--Image_width--' KEY_HEIGHT = '--Image_height--' KEY_IMG_SCALE = '--Image_scale--' KEY_CC_SCALE = '--Control_scale--' KEY_DEVICE = '-Device-' KEY_TIME = '-Time-' KEY_LOOP = '-Loop-' KEY_NEG_PROMPT_JP = '-Negative_PromptJP-' KEY_NEG_PROMPT = '-Negative_Prompt-' # ---------- # コマンドライン定義 def_result_image = './sd_results3/sd.png' def_cpu = 'store_true' def_log = '3' def_model_dir = '' def_model_path = '' def_ctrl_model_dir = '' def_ctrl_model_path = '' def_image_path = '' def_control_image_path = '' def_max_size = '' def_prompt = '' def_seed = '' def_width = '' def_height = '' def_step = '' def_scale = '' def_image_scale = '' def_cc_scale = '' def_strength = '' def_neg_prompt = '' def_mode = 'store_false' opt_list = [ ['pros_sel','','sd_100'], # 0 ['result_image', def_result_image, 'path to output image file'], # 1 ['cpu', def_cpu, 'cpu mode'], # 2 ['log', def_log, 'Log level(-1/0/1/2/3/4/5) Default value is \'3\''], # 3 ['model_dir', def_model_dir, 'Model directory'], # 4 ['model_path', def_model_path, 'Model Path'], # 5 ['ctrl_model_dir', def_ctrl_model_dir, 'ControlNet Model directory'], # 6 ['ctrl_model_path', def_ctrl_model_path, 'ControlNet Model Path'], # 7 ['image_path', def_image_path, 'Sourcs image file path'], # 8 ['ctrl_image_path', '', 'Control image file path'], # 9 ['max_size', def_max_size, 'image max size (0=source)'], # 10 ['prompt', def_prompt, 'Prompt text'], # 11 ['seed', def_seed, 'Seed parameter (-1 = rundom)'], # 12 ['width', def_width, 'image size width'], # 13 ['height', def_height, 'image size height'], # 14 ['step', def_step, 'infer step'], # 15 ['scale', def_scale, 'gaidanse scale'], # 16 ['image_scale', def_image_scale, 'image gaidanse scale'], # 17 ['cc_scale', def_cc_scale, 'controlnet conditioning scale'], # 18 ['strength', def_strength, 'strength value'], # 19 ['neg_prompt', def_neg_prompt, 'Negative Prompt text'], # 20 ['mode', def_mode, 'aplication mode'], ] # コマンドオプションを設定する def set_option(opt, sdt_list): for n in range(len(opt_list)): if opt_list[n][1] == '': for n0 in range(len(sd_list)): if opt_list[n][0] == sd_list[n0][0]: opt_list[n][1] = sd_list[n0][1] opt_list[0][2] = sd_list[0][2] if opt.result_image == '': opt.result_image = opt_list[1][1] if opt.log == '': opt.log = opt_list[3][1] if opt.model_dir == '': opt.model_dir = opt_list[4][1] if opt.model_path == '': opt.model_path = opt_list[5][1] if opt.ctrl_model_dir == '': opt.ctrl_model_dir = opt_list[6][1] if opt.ctrl_model_path == '': opt.ctrl_model_path = opt_list[7][1] if opt.image_path == '': opt.image_path = opt_list[8][1] if opt.ctrl_image_path == '': opt.ctrl_image_path = opt_list[9][1] if opt.max_size == '': opt.max_size = opt_list[10][1] if opt.prompt == '': opt.prompt = opt_list[11][1] if opt.seed == '': opt.seed = opt_list[12][1] if opt.width == '': opt.width = opt_list[13][1] if opt.height == '': opt.height = opt_list[14][1] if opt.step == '': opt.step = opt_list[15][1] if opt.scale == '': opt.scale = opt_list[16][1] if opt.image_scale == '': opt.image_scale = opt_list[17][1] if opt.cc_scale == '': opt.cc_scale = opt_list[18][1] if opt.strength == '': opt.strength = opt_list[19][1] if opt.neg_prompt == '': opt.neg_prompt = opt_list[20][1] def set_pros_hedder(pros): opt_list[0][2] = pros sdt.opt_list[0][2] = pros sdr.opt_list[0][2] = pros # ウィジェットのデータの取得(1回目) def get_paramlist(window, values, param): param[KEY_MODEL] = window[KEY_MODEL].DisplayText param[KEY_MAXSIZE] = int(values[KEY_MAXSIZE]) param[KEY_SEED] = sdt.get_random_seed_value(values[KEY_SEED_INPUT]) param[KEY_WIDTH] = int(values[KEY_WIDTH]) param[KEY_HEIGHT] = int(values[KEY_HEIGHT]) param[KEY_STEP] = int(values[KEY_STEP]) param[KEY_SCALE] = float(values[KEY_SCALE]) param[KEY_STRENGTH] = float(values[KEY_STRENGTH]) param[KEY_PROMPT_JP] = values[KEY_PROMPT_JP] param[KEY_PROMPT] = sdt.trans_jp2en(param[KEY_PROMPT_JP]) param[KEY_NEG_PROMPT_JP] = values[KEY_NEG_PROMPT_JP] param[KEY_NEG_PROMPT] = sdt.trans_jp2en(param[KEY_NEG_PROMPT_JP]) param[KEY_CTRL_MODEL] = window[KEY_CTRL_MODEL].DisplayText param[KEY_LOOP] = int(values[KEY_LOOP]) if param[KEY_LOOP] < 1: param[KEY_LOOP] = 1 if param[KEY_LOOP] > 50: param[KEY_LOOP] = 50 # ウィジェットのデータの取得(2回目以降) def get_paramlist2(window, values, param): if int(values[KEY_SEED_INPUT]) > 0: param[KEY_SEED] = param[KEY_SEED] + 1 else: param[KEY_SEED] = sdt.get_random_seed_value(values[KEY_SEED_INPUT]) # マスク画像ファイル名を得る(sd_044) def get_mask_file(imgfile): s = os.path.splitext(imgfile) if len(s[0]) > 5 and s[0][-5:] == '_mask': return '' m_path = s[0] + '_mask' + s[1] mskfile = m_path if os.path.isfile(m_path) else '' logger.debug(f'mask file: {mskfile}') return mskfile # 画像生成 def generate_image(param, logger = None): pros_sel = sdt._get_process_name(opt_list) # pros_sel 処理方法 image_path_save = param[KEY_INPUTPATH] # image_path push # 前処理 if pros_sel == 'sd_048': image_path = param[KEY_INPUTPATH] if not sdt.is_pose(image_path): pose_path = sd.pre_generation(image_path, logger) param[KEY_INPUTPATH] = pose_path param[KEY_CTRL_IMGPATH] = pose_path # ポーズ画像 if pros_sel == 'sd_047': image_path = param[KEY_INPUTPATH] if sdt.get_image_channel(image_path) == 3: img = cv2.imread(image_path) msk = sdt.line_drawing_image(img) src_path, mask_path = sdt.get_source_mask_path(image_path, logger) sdt.image_save(msk, mask_path, dispname = mask_path, wait_s = 1) # 1秒 wait param[KEY_CTRL_IMGPATH] = mask_path # 生成マスク画像 if pros_sel == 'sd_046': image_path = param[KEY_INPUTPATH] src_path, mask_path = sd.pre_generation(image_path, logger) param[KEY_INPUTPATH] = src_path param[KEY_CTRL_IMGPATH] = mask_path if pros_sel == 'sd_044': image_path = param[KEY_INPUTPATH] mask_path = get_mask_file(image_path) param[KEY_CTRL_IMGPATH] = mask_path model = param[KEY_MODEL] if param[KEY_MODEL_DIR] == '' else param[KEY_MODEL_DIR] + '/' + param[KEY_MODEL] image_path = param[KEY_INPUTPATH] prompt = param[KEY_PROMPT] max_size = param[KEY_MAXSIZE] seed = param[KEY_SEED] num_inference_steps = param[KEY_STEP] guidance_scale = param[KEY_SCALE] strength = param[KEY_STRENGTH] device = param[KEY_DEVICE] out_path = param[SKEY_RESULT_PATH] + '/' + sdt.make_filename_by_seq(param[SKEY_RESULT_PATH], param[SKEY_RESULT_FILE], seq_digit = 5, ex = seed) param[KEY_OUTPATH] = out_path ctrl_model_dir = param[KEY_CTRL_DIR] ctrl_model_path = param[KEY_CTRL_MODEL] if param[KEY_CTRL_DIR] == '' else param[KEY_CTRL_DIR] + '/' + param[KEY_CTRL_MODEL] width = param[KEY_WIDTH] height = param[KEY_HEIGHT] cc_scale = param[KEY_CC_SCALE] img_scale = param[KEY_IMG_SCALE] neg_prompt = param[KEY_NEG_PROMPT] logger.debug(f'** pros_sel: {pros_sel}') logger.debug(f'model: {model}') logger.debug(f'prompt: {prompt}') logger.debug(f'image_path: {image_path}') logger.debug(f'max_size: {max_size}') logger.debug(f'seed: {seed}') logger.debug(f'num_inference_steps: {num_inference_steps}') logger.debug(f'guidance_scale: {guidance_scale}') logger.debug(f'strength: {strength}') logger.debug(f'device: {device}') logger.debug(f'loop: {param[KEY_LOOP]}') logger.debug(f'out_path: {out_path}') logger.debug(f'ctrl_model_path: {ctrl_model_path}') logger.debug(f'neg_prompt: {neg_prompt}') if image_path != '': src_image = sdt._get_resize_image(image_path, max_size, logger) # 元画像リサイズ if pros_sel == 'sd_040': image = sd.image_generation(model, src_image, prompt, seed, num_inference_steps, width, height, guidance_scale, img_scale, neg_prompt, device) elif pros_sel == 'sd_042': image = sd.image_generation(model, ctrl_model_path, src_image, prompt, seed, num_inference_steps, width, height, guidance_scale, cc_scale, neg_prompt, device) elif pros_sel == 'sd_044' or pros_sel == 'sd_046': ctrl_image_path = param[KEY_CTRL_IMGPATH] sdt.image_disp(ctrl_image_path, ctrl_image_path, wait_s = 1) # マスク表示 msk_image = sdt._get_resize_image(ctrl_image_path, max_size, logger) img_ctrl = sdt.make_inpaint_condition(src_image, msk_image) # コントロール画像 image = sd.image_generation(model, ctrl_model_path, src_image, msk_image, img_ctrl, prompt, seed, num_inference_steps, width, height, guidance_scale, cc_scale, strength, neg_prompt, device) elif pros_sel == 'sd_047' or pros_sel == 'sd_048': image = sd.image_generation(model, ctrl_model_path, src_image, prompt, seed, num_inference_steps, neg_prompt, device) elif pros_sel == 'sd_091': image = sd.image_generation(model, prompt, src_image, seed, num_inference_steps, guidance_scale, strength, neg_prompt, device) elif pros_sel == 'sd_081': image = sd.image_generation(model, prompt, seed, num_inference_steps, guidance_scale, width, height, neg_prompt, device) image.save(out_path) logger.info(f'result_file: {out_path}') sdt.device_empty_cache(device) # メモリー開放 param[KEY_INPUTPATH] = image_path_save # image_path pop # ** main関数 ** def main(opt, logger = None): # ------------------------------------------ # キャンバスをクリア def clear_canvas(key, msg, color): frame = np.zeros((CANVAS_SIZE, CANVAS_SIZE, 3), np.uint8) frame[:,:,] = 0xf0 return msg_out_canvas(key, frame, msg, color) def msg_out_canvas(key, frame, msg, color): x0,y0,x1,y1 = cv2_putText(img=frame, text=msg, org=(CANVAS_SIZE//2, CANVAS_SIZE//2), fontFace=font_face, fontScale=16, color=color, mode=2,areaf=True) cv2.rectangle(frame,(x0-8, y0), (x1+8, y1), (0xf0,0xf0,0xf0), -1) 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) return frame # キャンバスへ画像の表示 def update_canvas(key, imgfile): if os.path.isfile(imgfile): frame = cv2.imread(imgfile) frame = my_imagetool.frame_square(frame, (240, 240, 240)) frame = cv2.resize(frame, dsize = (CANVAS_SIZE, CANVAS_SIZE)) img = cv2.imencode('.png', frame)[1].tobytes() window[key].update(img) else: frame = clear_canvas(key, 'Generate Image', (0,0,0)) return frame # ウイジェットの更新 def update_widget(): frame = update_canvas(KEY_IMAGE, param[KEY_OUTPATH]) frame_input = update_canvas(KEY_INPUT_IMAGE, param[KEY_INPUTPATH]) window[KEY_OUTPATH].update(param[KEY_OUTPATH]) window[KEY_SEED].update(param[KEY_SEED_INPUT]) # シード値の表示 window[KEY_PROMPT_JP].update(param[KEY_PROMPT_JP]) window[KEY_PROMPT].update(param[KEY_PROMPT]) window[KEY_INPUTPATH].update(param[KEY_INPUTPATH]) window[KEY_MODEL].update(param[KEY_MODEL]) window[KEY_MAXSIZE].update(param[KEY_MAXSIZE]) window[KEY_STEP].update(param[KEY_STEP]) window[KEY_SCALE].update(param[KEY_SCALE]) window[KEY_STRENGTH].update(param[KEY_STRENGTH]) window[KEY_NEG_PROMPT_JP].update(param[KEY_NEG_PROMPT_JP]) window[KEY_NEG_PROMPT].update(param[KEY_NEG_PROMPT]) window[KEY_WIDTH].update(param[KEY_WIDTH]) window[KEY_HEIGHT].update(param[KEY_HEIGHT]) window[KEY_CTRL_MODEL].update(param[KEY_CTRL_MODEL]) window[KEY_CTRL_IMGPATH].update(param[KEY_CTRL_IMGPATH]) return frame # ウイジェットの禁止・許可 def set_enb_dis(disabled): window[KEY_IMAGE_SEL].update(disabled = disabled) window[KEY_MODELSEL].update(disabled = disabled) window[KEY_GENERATE].update(disabled = disabled) window[KEY_LOOP].update(disabled = disabled) window[KEY_EXIT].update(disabled = disabled) # モード変更 def change_mode(advanced): pros_sel = sdt._get_process_name(opt_list) # pros_sel 処理方法 window[KEY_INPUT_IMAGE].update(visible = pros_sel != 'sd_081') window[KEY_INPUT_TXT].update(visible = pros_sel != 'sd_081') window[KEY_INPUTPATH].update(visible = pros_sel != 'sd_081') window[KEY_IMAGE_SEL].update(visible = pros_sel != 'sd_081') window[KEY_CTRL_MODEL_TXT].update(visible = advanced) window[KEY_CTRL_MODEL].update(visible = advanced) window[KEY_CTRL_MODELSEL].update(visible = advanced) # window[KEY_WIDTH_TXT].update(visible = advanced) # window[KEY_WIDTH].update(visible = advanced) # window[KEY_HEIGHT_TXT].update(visible = advanced) # window[KEY_HEIGHT].update(visible = advanced) window[KEY_MAXSIZE_TXT].update(visible = advanced) window[KEY_MAXSIZE].update(visible = advanced) window[KEY_STEP_TXT].update(visible = advanced) window[KEY_STEP].update(visible = advanced) window[KEY_SCALE_TXT].update(visible = advanced) window[KEY_SCALE].update(visible = advanced) enb = pros_sel != 'sd_040' and pros_sel != 'sd_081' window[KEY_STRENGTH_TXT].update(visible = advanced and enb) window[KEY_STRENGTH].update(visible = advanced and enb) enb = pros_sel == 'sd_044' or pros_sel == 'sd_046' or pros_sel == 'sd_047' or pros_sel == 'sd_048' window[KEY_CTRL_IMGPATH_TXT].update(visible = advanced and enb) window[KEY_CTRL_IMGPATH].update(visible = advanced and enb) window[KEY_CTRL_IMAGE_SEL].update(visible = advanced and enb) # ------------------------------------------ # パラメータ設定 pros_sel = sdt._get_process_name(opt_list) # pros_sel 処理方法 advanced = opt.mode device = sdt._get_device(opt, logger) result_path = sdt._get_result_path(opt, logger) result_file = sdt._get_result_file(opt, logger) image_path = sdt._get_source_image_path(opt, logger) prompt = sdt._get_prompt(opt, logger) model_path = sdt._get_model_path(opt, logger) max_size = sdt._get_max_size(opt, logger) height, width = sdt._get_image_size(opt, logger) seed = DEF_SEED_VAL num_inference_steps = sdt._get_inference_steps(opt, logger) guidance_scale = sdt._get_guidance_scale(opt, logger) strength = sdt._get_strength(opt, logger) neg_prompt = sdt._get_negative_prompt(opt, logger) param = sdr.param param[KEY_OUTPATH] = '' param[KEY_PROMPT_JP] = opt.prompt param[KEY_PROMPT] = prompt param[KEY_INPUTPATH] = image_path param[KEY_MODEL] = opt.model_path param[KEY_MAXSIZE] = max_size param[KEY_SEED_INPUT] = opt.seed param[KEY_SEED] = seed param[KEY_STEP] = num_inference_steps param[KEY_SCALE] = guidance_scale param[KEY_STRENGTH] = strength param[KEY_DEVICE] = device param[KEY_LOOP] = 1 param[KEY_TIME] = sdt.elapsed_time_str(0) param[SKEY_RESULT_PATH] = result_path param[SKEY_RESULT_FILE] = result_file param[KEY_MODEL_DIR] = opt.model_dir param[KEY_CTRL_IMGPATH] = sdt._get_control_image_path(opt, logger) param[KEY_CTRL_DIR] = sdt._get_controlnet_model_dir(opt, logger) param[KEY_CTRL_MODEL] = opt.ctrl_model_path param[KEY_WIDTH] = width param[KEY_HEIGHT] = height param[KEY_IMG_SCALE] = sdt._get_image_guidance_scale(opt, logger) param[KEY_CC_SCALE] = sdt._get_controlnet_conditioning_scale(opt, logger) param[KEY_NEG_PROMPT_JP] = opt.neg_prompt param[KEY_NEG_PROMPT] = neg_prompt sdr.logout_data(param, logger) csvfile = param[SKEY_RESULT_PATH]+ '/' + CSV_LOG_FILE # 出力画像ログファイル名 # 出力フォルダ os.makedirs(result_path, exist_ok = True) # フォント取得 from my_puttext import get_font, cv2_putText font_face = get_font() # ウィンドウのテーマ sg.theme(DEF_THEME) canvas_input_img = sg.Image(size = (CANVAS_SIZE, CANVAS_SIZE), key=KEY_INPUT_IMAGE) canvas_img = sg.Image(size = (CANVAS_SIZE, CANVAS_SIZE), key=KEY_IMAGE) # モードボタン初期設定 if advanced: b0 = 'Advance' b1 = 'LightCyan' b2 = 'cornflower blue' else: b0 = 'Normal' b1 = 'cornflower blue' b2 = 'LightCyan' col_left = [ [canvas_input_img], [sg.Text("Input File", size=(14, 1), key=KEY_INPUT_TXT), sg.Text(param[KEY_INPUTPATH], size=(39,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_INPUTPATH), sg.Button('Image', size=(6, 1), key=KEY_IMAGE_SEL)], [sg.Text("Model", size=(14, 1)), sg.Text(param[KEY_MODEL], size=(39,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,2), key=KEY_PROMPT_JP)], [sg.Text("Prompt", size=(14, 1)), sg.Multiline(param[KEY_PROMPT], size=(52,2), text_color='#008800', background_color='LightSteelBlue1', key=KEY_PROMPT)], [sg.Text("Negative Prompt in", size=(14, 1)), sg.Multiline(param[KEY_NEG_PROMPT_JP], size=(52,2), key=KEY_NEG_PROMPT_JP)], [sg.Text("Negative Prompt", size=(14, 1)), sg.Multiline(param[KEY_NEG_PROMPT], size=(52,2), text_color='#008800', background_color='LightSteelBlue1', key=KEY_NEG_PROMPT)], [sg.Text("ControlNet File", size=(14, 1), key=KEY_CTRL_IMGPATH_TXT), sg.Text(param[KEY_CTRL_IMGPATH], size=(39,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_CTRL_IMGPATH), sg.Button('C Image', size=(6, 1), key=KEY_CTRL_IMAGE_SEL)], ] col_right = [ [canvas_img], [sg.Text("Output File", size=(14, 1)), sg.Text(param[KEY_OUTPATH], size=(39,1), key=KEY_OUTPATH), sg.Button(b0, button_color=(b1, b2), size=(6, 1), key=KEY_ADVANCED)], [sg.Text("ControlNet Model", size=(14, 1), key=KEY_CTRL_MODEL_TXT), sg.Text(param[KEY_CTRL_MODEL], size=(39,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_CTRL_MODEL), sg.Button('C Model', size=(6, 1), key=KEY_CTRL_MODELSEL)], [sg.Text("Gen Image Width", size=(14, 1), key=KEY_WIDTH_TXT), sg.Input(param[KEY_WIDTH], size=(10,1), key=KEY_WIDTH), sg.Text("Height", size=(5, 1), key=KEY_HEIGHT_TXT), sg.Input(param[KEY_HEIGHT], size=(10,1), key=KEY_HEIGHT), sg.Text(" Max size", size=(8, 1), key=KEY_MAXSIZE_TXT), sg.Input(param[KEY_MAXSIZE], size=(10,1), key=KEY_MAXSIZE)], [sg.Text("Seed (-1=Random)", size=(14, 1)), sg.Input(param[KEY_SEED_INPUT], size=(18,1), key=KEY_SEED_INPUT), sg.Button('←', size=(4, 1), key=KEY_SEED_SET), sg.Text(param[KEY_SEED], size=(14,1), text_color='#008800', background_color='LightSteelBlue1', key=KEY_SEED), sg.Button('-1', size=(5, 1), key=KEY_SEED_CLR)], [sg.Text("Detail (Steps)", size=(14, 1), key=KEY_STEP_TXT), sg.Slider((10, 150), float(param[KEY_STEP]), 1, orientation='h', size=(42, 5), key=KEY_STEP)], [sg.Text("Guidance Scale", size=(14, 1), key=KEY_SCALE_TXT), sg.Slider((1, 50), float(param[KEY_SCALE]), 0.1, orientation='h', size=(42, 5), key=KEY_SCALE)], [sg.Text("Strength", size=(14, 1), key=KEY_STRENGTH_TXT), sg.Slider((0, 1), float(param[KEY_STRENGTH]), 0.1, orientation='h', size=(42, 5), key=KEY_STRENGTH)], [sg.Text("", size=(14, 1))], [sg.Text("Loop count (1-50)", size=(14, 1)), sg.Input(param[KEY_LOOP], size=(2,1), justification='right', key=KEY_LOOP), sg.Text("", size=(2, 1)), sg.Button('Generate', size=(10, 1), key=KEY_GENERATE), sg.Text("", size=(8, 1)), sg.Button('Exit', size=(10, 1), key=KEY_EXIT)] ] # ウィンドウのレイアウト layout = [[sg.Column(col_left, vertical_alignment='top'), sg.Column(col_right, vertical_alignment='top')]] # ウィンドウオブジェクトの作成 window = sg.Window(title, layout, finalize=True, return_keyboard_events=True, disable_close=True) #「X」無効 # ユーザーイベントの定義 canvas_img.bind('<ButtonPress>', '_click_on') canvas_input_img.bind('<ButtonPress>', '_click_on') # キャンバス初期化 pros_sel = sdt._get_process_name(opt_list) # pros_sel 処理方法 ss = param[KEY_SEED_INPUT] # 最初のシード入力値 bf = sdr.read_result_csv(csvfile, param, logger, '1') if bf: frame = update_widget() param[KEY_SEED] = param[KEY_SEED_INPUT] param[KEY_SEED_INPUT] = ss window[KEY_SEED].update(param[KEY_SEED]) window[KEY_SEED_INPUT].update(param[KEY_SEED_INPUT] ) else: frame = update_canvas(KEY_IMAGE, param[KEY_OUTPATH]) frame_input = update_canvas(KEY_INPUT_IMAGE, param[KEY_INPUTPATH]) param[SKEY_DEF_OUTPATH] = param[KEY_OUTPATH] # 現在の画像パス new_make_f = False window[KEY_PROMPT].update(disabled = True) change_mode(advanced) # イベントのループ while True: event, values = window.read(timeout = 30) # 画像生成 if new_make_f: # 処理プロセス logger.info(f'{sdt.CYAN}** Start {param[KEY_LOOP]} **{sdt.NOCOLOR}') input_img_path = param[KEY_INPUTPATH] start_time = time.time() generate_image(param, logger) param[KEY_TIME] = sdt.elapsed_time_str(time.time() - start_time) sdr.result_csv(csvfile, param, logger) frame = update_canvas(KEY_IMAGE, param[KEY_OUTPATH]) param[SKEY_DEF_OUTPATH] = param[KEY_OUTPATH] # 現在の画像パス window[KEY_OUTPATH].update(param[KEY_OUTPATH]) param[KEY_LOOP] = param[KEY_LOOP] - 1 window[KEY_LOOP].update(param[KEY_LOOP]) if input_img_path != param[KEY_INPUTPATH]: frame_input = update_canvas(KEY_INPUT_IMAGE, param[KEY_INPUTPATH]) window[KEY_INPUTPATH].update(param[KEY_INPUTPATH] ) if param[KEY_LOOP] < 1: param[KEY_LOOP] = 1 window[KEY_LOOP].update(param[KEY_LOOP]) set_enb_dis(False) new_make_f = False else: get_paramlist2(window, values, param) window[KEY_SEED].update(param[KEY_SEED]) logger.info(f'{sdt.CYAN}** Complete **{sdt.NOCOLOR} {param[KEY_TIME]}') # 終了 if event == KEY_EXIT or event == sg.WIN_CLOSED: break # KEY_IMAGE if event == KEY_IMAGE + '_click_on': logger.debug(f'{event}') set_enb_dis(True) def_file = param[SKEY_DEF_OUTPATH] if os.path.isfile(def_file): imgfile = sdr.image_dialog(param, csvfile, def_file, title='Result Image file select', xn=10, yn=3, thumb_size=128, gap=4, logger=logger) if os.path.isfile(imgfile): logger.debug(f'Output select: {imgfile}') bf = sdr.read_result_csv(csvfile, param, logger, imgfile) if bf: frame = update_widget() param[SKEY_DEF_OUTPATH] = param[KEY_OUTPATH] else: sdr.read_result_csv(csvfile, param, logger, def_file) frame = update_widget() param[SKEY_DEF_OUTPATH] = param[KEY_OUTPATH] set_enb_dis(False) # KEY_INPUT_IMAGE if event == KEY_INPUT_IMAGE + '_click_on': logger.debug(f'{event}') set_enb_dis(True) def_file = param[KEY_INPUTPATH] if os.path.isfile(def_file): imgfile = my_thumbnail.image_dialog(def_file, 'Image file select', my_thumbnail.DEF_THEME, 10, 4, ret = '', logger = logger) bf = True if pros_sel == 'sd_044': mskfile = get_mask_file(imgfile) if mskfile != '': param[KEY_CTRL_IMGPATH] = mskfile else: bf = False if bf and os.path.isfile(imgfile): logger.debug(f'Input select: {imgfile}') param[KEY_INPUTPATH] = imgfile update_widget() set_enb_dis(False) # モード・チェンジ if event == KEY_ADVANCED: logger.debug(f'{event} {not advanced}') if advanced: window[KEY_ADVANCED].update('Normal', button_color=('cornflower blue', 'LightCyan')) advanced = False else: window[KEY_ADVANCED].update('Advance', button_color=('LightCyan', 'cornflower blue')) advanced = True change_mode(advanced) # シード値セット・ボタン if event == KEY_SEED_SET: logger.debug(f'{event}') window[KEY_SEED_INPUT].update(param[KEY_SEED]) # シード値クリア・ボタン if event == KEY_SEED_CLR: logger.debug(f'{event}') window[KEY_SEED_INPUT].update('-1') # 画像選択ボタン if event == KEY_IMAGE_SEL: logger.debug(f'{event}') set_enb_dis(True) imgfile = my_dialog.select_image_file(initdir=os.path.dirname(param[KEY_INPUTPATH])) bf = True if pros_sel == 'sd_044': mskfile = get_mask_file(imgfile) if mskfile != '': param[KEY_CTRL_IMGPATH] = mskfile else: bf = False if bf and len(imgfile) > 0: logger.debug(f'Input select: {imgfile}') param[KEY_INPUTPATH] = imgfile update_widget() set_enb_dis(False) # Model ボタン if event == KEY_MODELSEL: logger.debug(f'{event}') set_enb_dis(True) s0 = param[KEY_MODEL] id = s0.find('/') s1 = '/' + s0[:id] if id > 0 else '' s2 = param[KEY_MODEL_DIR] + s1 ttl = 'モデルファイルを選択' types = [("Model file", ".safetensors .pt"), ("model", ".safetensors"), ("pt file", ".pt") ] filename = my_dialog.file_dialog(ttl, types, s2) if len(filename) > 0: s3 = os.path.basename(filename) # ファイル名 s4 = os.path.dirname(filename) # ディレクトリ名 id = s4.find('SD1.5') if id >= 0 and id == len(s4) - 5: # SD1.5 s5 = s4[:id - 1] s3 = 'SD1.5/' + s3 else: # SDXL s5 = s4 param[KEY_MODEL] = s3 s6 = os.path.abspath(param[KEY_MODEL_DIR]) s7 = s6.replace('\\', '/') if s7 == s5: # モデルディレクトリは変更不可 window[KEY_MODEL].update(param[KEY_MODEL]) logger.debug(f'{param[KEY_MODEL_DIR]}/{param[KEY_MODEL]}') else: my_dialog.warning_dialog(ttl, 'モデルディレクトリは変更できません') set_enb_dis(False) # Genarate ボタン if event == KEY_GENERATE: logger.debug(f'{event}') set_enb_dis(True) get_paramlist(window, values, param) frame = msg_out_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]) window[KEY_NEG_PROMPT].update(param[KEY_NEG_PROMPT]) new_make_f = True # ウィンドウ終了処理 window.close() # main関数エントリーポイント(実行開始) if __name__ == "__main__": # コマンドライン入力設定 parser = sdt.parse_args(None, opt_list) opt = parser.parse_args() if opt.pros_sel == 'sd_040': import sd_040 as sd elif opt.pros_sel == 'sd_042': import sd_042 as sd elif opt.pros_sel == 'sd_044': import sd_044 as sd elif opt.pros_sel == 'sd_046': import sd_046 as sd elif opt.pros_sel == 'sd_047': import sd_047 as sd elif opt.pros_sel == 'sd_048': import sd_048 as sd elif opt.pros_sel == 'sd_091': import sd_091 as sd elif opt.pros_sel == 'sd_081': import sd_081 as sd else: exit(0) # オプションリスト変更 sd_list = sd.opt_list set_option(opt, sd_list) title = title + ' <' + opt.pros_sel + '>' set_pros_hedder(opt.pros_sel) # アプリケーション・ログ設定 module = os.path.basename(__file__) module_name = os.path.splitext(module)[0] logger = my_logging.get_module_logger_sel(module_name, int(opt.log)) sdt._get_device(opt) sdt.display_info(opt, title) main(opt, logger) logger.info('\nFinished.\n')※ 上記ソースコードは表示の都合上、半角コード '}' が 全角 '}'になっていることに注意
機能 | 戻り値 | 関数 |
結果を CSV ファイルに残す | - | result_csv(csvfile, param, logger) |
結果ログからパラメータを取得 | bool | read_result_csv(csvfile, param, logger, imgfile = '0', pros_f = False) |
動的パラメータの出力 | - | logout_data(param, logger) |
生成画選択ダイアログ | image_file | image_dialog(param, csvfile, file_path, title='', theme=DEF_THEME, xn=10, yn=3, thumb_size=128, gap=4, file_ext=my_thumbnail.IMAGE_EXT, logger=None) |
# -*- coding: utf-8 -*- ##-------------------------------------------------- ## sd_test basic tools for results Ver 0.05 ## ## 2025.07.21 Masahiro Izutsu ##-------------------------------------------------- ## sd_results.py ## Ver 0.00 2025.07.17 Trial version ## Ver 0.05 2025.07.21 sd_100.py 統合版対応 import warnings warnings.simplefilter('ignore') # タイトル title = 'sd_test basic tools Ver 0.05' # インポート&初期設定 import os import cv2 import csv import PySimpleGUI as sg import tkinter as tk from PIL import Image, ImageTk import my_logging import my_csv import my_thumbnail import sd_tools as sdt # 定数定義 DEF_THEME = 'GrayGrayGray' KEY_SEED_INPUT = '-Seed_input-' SKEY_RESULT_PATH = '-result_path-' SKEY_RESULT_FILE = '-result_file-' SKEY_DEF_OUTPATH = '-default_image-' # csv save KEY_PROS_SEL = '--Proscess--' KEY_OUTPATH = '-Output-' KEY_SEED = '-Seed-' KEY_PROMPT_JP = '-PromptJP-' KEY_PROMPT = '-Prompt-' KEY_INPUTPATH = '-Input-' KEY_MAXSIZE = '-MaxSize-' KEY_STEP = '-Step-' KEY_SCALE = '-Scale-' KEY_STRENGTH = '-strength-' KEY_MODEL_DIR = '-model_dir-' KEY_MODEL = '-Model-' KEY_CTRL_IMGPATH = '--ctrl_image_path--' KEY_CTRL_DIR = '-ctrl_model_dir-' KEY_CTRL_MODEL = '-ctrl_model-' KEY_WIDTH = '--Image_width--' KEY_HEIGHT = '--Image_height--' KEY_IMG_SCALE = '--Image_scale--' KEY_CC_SCALE = '--Control_scale--' KEY_DEVICE = '-Device-' KEY_TIME = '-Time-' KEY_LOOP = '-Loop-' KEY_NEG_PROMPT_JP = '-Negative_PromptJP-' KEY_NEG_PROMPT = '-Negative_Prompt-' # 共通データ param = {} param[KEY_PROS_SEL] = 'sd_resilts' param[KEY_OUTPATH] = './sd_results3/sd_00000_0.png' param[KEY_PROMPT_JP] = '雪の中の場面にする' param[KEY_PROMPT] = 'Make it a scene in the snow' param[KEY_INPUTPATH] = 'images/sd_040_test.png' param[KEY_MODEL_DIR] = '' param[KEY_MODEL] = 'timbrooks/instruct-pix2pix' param[KEY_MAXSIZE] = 0 param[KEY_SEED] = 0 param[KEY_SEED_INPUT] = 0 param[KEY_STEP] = 20 param[KEY_SCALE] = 7.0 param[KEY_STRENGTH] = 0.5 param[KEY_DEVICE] = 'cuda' param[KEY_LOOP] = 1 param[KEY_TIME] = '00:00:09' param[KEY_CTRL_IMGPATH] = '' param[KEY_CTRL_DIR] = '' param[KEY_CTRL_MODEL] = '' param[KEY_WIDTH] = 512 param[KEY_HEIGHT] = 512 param[KEY_IMG_SCALE] = 1.5 param[KEY_CC_SCALE] = 1.0 param[KEY_NEG_PROMPT_JP] = '最悪の品質、おかしい人体構造' param[KEY_NEG_PROMPT] = 'Worst quality, funny body structure' param[SKEY_RESULT_PATH] = '' param[SKEY_RESULT_FILE] = '' param[SKEY_DEF_OUTPATH] = '' opt_list = [ ['pros_sel','','sd_resilts'], # 0 ] # 結果を CSV ファイルに残す def result_csv(csvfile, param, logger): my_csv_treatment = my_csv.CSVtreatment(csvfile, 'utf_8_sig') s = my_csv_treatment.read_csv() if len(s) ==0: data = [] data.append(KEY_PROS_SEL) data.append(KEY_OUTPATH) data.append(KEY_SEED) data.append(KEY_PROMPT_JP) data.append(KEY_PROMPT) data.append(KEY_INPUTPATH) data.append(KEY_MAXSIZE) data.append(KEY_STEP) data.append(KEY_SCALE) data.append(KEY_STRENGTH) data.append(KEY_MODEL_DIR) data.append(KEY_MODEL) data.append(KEY_CTRL_IMGPATH) data.append(KEY_CTRL_DIR) data.append(KEY_CTRL_MODEL) data.append(KEY_WIDTH) data.append(KEY_HEIGHT) data.append(KEY_IMG_SCALE) data.append(KEY_CC_SCALE) data.append(KEY_DEVICE) data.append(KEY_TIME) data.append(KEY_LOOP) data.append(KEY_NEG_PROMPT_JP) data.append(KEY_NEG_PROMPT) my_csv_treatment.write_csv(data) logger.debug(data) data = [] data.append(param[KEY_PROS_SEL]) data.append(param[KEY_OUTPATH]) data.append(str(param[KEY_SEED])) data.append(param[KEY_PROMPT_JP]) data.append(param[KEY_PROMPT]) data.append(param[KEY_INPUTPATH]) data.append(str(param[KEY_MAXSIZE])) data.append(str(param[KEY_STEP])) data.append(str(param[KEY_SCALE])) data.append(str(param[KEY_STRENGTH])) data.append(param[KEY_MODEL_DIR]) data.append(param[KEY_MODEL]) data.append(param[KEY_CTRL_IMGPATH]) data.append(param[KEY_CTRL_DIR]) data.append(param[KEY_CTRL_MODEL]) data.append(param[KEY_WIDTH]) data.append(param[KEY_HEIGHT]) data.append(param[KEY_IMG_SCALE]) data.append(param[KEY_CC_SCALE]) data.append(param[KEY_DEVICE]) data.append(param[KEY_TIME]) data.append(param[KEY_LOOP]) data.append(param[KEY_NEG_PROMPT_JP]) data.append(param[KEY_NEG_PROMPT]) my_csv_treatment.append_csv(data) logger.debug(data) # 結果ログからパラメータを取得 def read_result_csv(csvfile, param, logger, imgfile = '0', pros_f = False): def _get_val(dd, key): return dd.get(key, '') def _get_val_int(dd, key): val = dd.get(key, '') if val != '': val = int(val) return val def _get_val_float(dd, key): val = dd.get(key, '') if val != '': val = float(val) return val param[KEY_PROS_SEL] = sdt._get_process_name(opt_list) bf = False dds = {} dd = {} try: with open(csvfile, 'r', encoding = 'utf_8_sig') as f: reader = csv.DictReader(f) if imgfile == '0': # 最初の行 for dd in reader: bf = True break elif imgfile == '1': # 同じ処理の最後の行 for dd in reader: if param[KEY_PROS_SEL] == dd.get(KEY_PROS_SEL, 'not found'): dds = dd.copy() bf = True continue if dds == {}: bf = False else: dd = dds.copy() else: # 出力ファイルの行 img_path = os.path.basename(imgfile) for dd in reader: out_path = os.path.basename(dd[KEY_OUTPATH]) if out_path == img_path and (pros_f or param[KEY_PROS_SEL] == dd.get(KEY_PROS_SEL, 'not found')): bf = True break except FileNotFoundError as e: pass except csv.Error as e: logger.debug(e) if bf: param[KEY_PROS_SEL] = _get_val(dd, KEY_PROS_SEL) param[KEY_OUTPATH] = _get_val(dd, KEY_OUTPATH) param[KEY_SEED_INPUT] = _get_val_int(dd, KEY_SEED) param[KEY_PROMPT_JP] = _get_val(dd, KEY_PROMPT_JP) param[KEY_PROMPT] = _get_val(dd, KEY_PROMPT) param[KEY_INPUTPATH] = _get_val(dd, KEY_INPUTPATH) param[KEY_MAXSIZE] = _get_val_int(dd, KEY_MAXSIZE) param[KEY_STEP] = _get_val_int(dd, KEY_STEP) param[KEY_SCALE] = _get_val_float(dd, KEY_SCALE) param[KEY_STRENGTH] = _get_val_float(dd, KEY_STRENGTH) param[KEY_MODEL_DIR] = _get_val(dd, KEY_MODEL_DIR) param[KEY_MODEL] = _get_val(dd, KEY_MODEL) param[KEY_CTRL_IMGPATH] = _get_val(dd, KEY_CTRL_IMGPATH) param[KEY_CTRL_DIR] = _get_val(dd, KEY_CTRL_DIR) param[KEY_CTRL_MODEL] = _get_val(dd, KEY_CTRL_MODEL) param[KEY_WIDTH] = _get_val_int(dd, KEY_WIDTH) param[KEY_HEIGHT] = _get_val_int(dd, KEY_HEIGHT) param[KEY_IMG_SCALE] = _get_val_float(dd, KEY_IMG_SCALE) param[KEY_CC_SCALE] = _get_val_float(dd, KEY_CC_SCALE) param[KEY_NEG_PROMPT_JP] = _get_val(dd, KEY_NEG_PROMPT_JP) param[KEY_NEG_PROMPT] = _get_val(dd, KEY_NEG_PROMPT) logout_data(param, logger) elif os.path.isfile(imgfile): param[KEY_OUTPATH] = imgfile param[KEY_SEED_INPUT] = sdt.path2seed(imgfile) # ファイル名に含まれるシード値 logout_data(param, logger) elif bf and dd.get(KEY_PROS_SEL, '') == '': # csvファイルのバージョンチェック os.remove(csvfile) return bf # 動的パラメータの出力 def logout_data(param, logger): logger.debug('---------------------------------------------') logger.debug(param[KEY_OUTPATH]) logger.debug(param[KEY_SEED]) logger.debug(param[KEY_PROMPT_JP]) logger.debug(param[KEY_PROMPT]) logger.debug(param[KEY_INPUTPATH]) logger.debug(param[KEY_MAXSIZE]) logger.debug(param[KEY_STEP]) logger.debug(param[KEY_SCALE]) logger.debug(param[KEY_STRENGTH]) logger.debug(param[KEY_MODEL_DIR]) logger.debug(param[KEY_MODEL]) logger.debug(param[KEY_CTRL_IMGPATH]) logger.debug(param[KEY_CTRL_DIR]) logger.debug(param[KEY_CTRL_MODEL]) logger.debug(param[KEY_WIDTH]) logger.debug(param[KEY_HEIGHT]) logger.debug(param[KEY_IMG_SCALE]) logger.debug(param[KEY_CC_SCALE]) logger.debug(param[KEY_DEVICE]) logger.debug(param[KEY_NEG_PROMPT_JP]) logger.debug(param[KEY_NEG_PROMPT]) logger.debug('---------------------------------------------') # 生成画選択ダイアログ def image_dialog(param, csvfile, file_path, title='', theme=DEF_THEME, xn=10, yn=3, thumb_size=128, gap=4, file_ext=my_thumbnail.IMAGE_EXT, logger=None): pros_sel = sdt._get_process_name(sdt.opt_list) # pros_sel 処理方法 image_file = '' br = read_result_csv(csvfile, param, logger, file_path, True) if not br: print(sdt.RED + '生成画像がありません!' + sdt.NOCOLOR) return image_file KEY_IMG_SEL = '-ImgSel-' KEY_TXTIMG = '-TextImg-' KEY_OK = '-Ok-' KEY_CANCEL = '-Cancel-' KEY_PAGE = '-Page-' KEY_PAGEUP = '-PageUp-' KEY_PAGEDOWN = '-PageDown-' def update_param(file_path, bok): br = read_result_csv(csvfile, param, logger, file_path, True) if br: cc = cf if pros_sel == param[KEY_PROS_SEL] else '#880000' window[KEY_PROS_SEL].update(param[KEY_PROS_SEL], text_color=cc) window[KEY_PROMPT_JP].update(param[KEY_PROMPT_JP]) window[KEY_PROMPT].update(param[KEY_PROMPT]) window[KEY_INPUTPATH].update(param[KEY_INPUTPATH]) window[KEY_MODEL_DIR].update(param[KEY_MODEL_DIR]) window[KEY_MODEL].update(param[KEY_MODEL]) window[KEY_MAXSIZE].update(param[KEY_MAXSIZE]) window[KEY_SEED].update(param[KEY_SEED_INPUT]) # シード値 window[KEY_STEP].update(param[KEY_STEP]) window[KEY_SCALE].update(param[KEY_SCALE]) window[KEY_STRENGTH].update(param[KEY_STRENGTH]) window[KEY_DEVICE].update(param[KEY_DEVICE]) window[KEY_TIME].update(param[KEY_TIME]) window[KEY_CTRL_IMGPATH].update(param[KEY_CTRL_IMGPATH]) window[KEY_CTRL_DIR].update(param[KEY_CTRL_DIR]) window[KEY_CTRL_MODEL].update(param[KEY_CTRL_MODEL]) window[KEY_WIDTH].update(param[KEY_WIDTH]) window[KEY_HEIGHT].update(param[KEY_HEIGHT]) window[KEY_IMG_SCALE].update(param[KEY_IMG_SCALE]) window[KEY_CC_SCALE].update(param[KEY_CC_SCALE]) window[KEY_NEG_PROMPT_JP].update(param[KEY_NEG_PROMPT_JP]) window[KEY_NEG_PROMPT].update(param[KEY_NEG_PROMPT]) if bok: window[KEY_OK].update(disabled = pros_sel != param[KEY_PROS_SEL]) # Thumbnail オブジェクト作成 Thumb = my_thumbnail.Thumbnail(xn, yn, thumb_size, gap, file_ext) image_file = file_path frame = Thumb.initialize(image_file, False) image_file = Thumb.get_sel_filepath() # ウィンドウのテーマ sg.theme(theme) cf = '#008800' # テキストの色 cb = 'LightSteelBlue1' # 背景の色 canvas = sg.Image(size = Thumb.get_canvas_size(), key='CANVAS') # ウィンドウのレイアウト col_top = [ [sg.Text(image_file, background_color='White', size=(32, 1), key = KEY_IMG_SEL), sg.Text('', size=(32, 1), key = KEY_TXTIMG)], [canvas], ] col_btn = [ [ sg.Text("Page: 1/1", size=(12, 1), key=KEY_PAGE), sg.Button('▼', size=(2, 1), key=KEY_PAGEUP), sg.Button('▲', size=(2, 1), key=KEY_PAGEDOWN), sg.Text("", size=(4, 1)), sg.Button('Ok', size=(8, 1), key=KEY_OK, focus=True), sg.Button('Cancel', size=(8, 1), key=KEY_CANCEL), sg.Text("", size=(1, 1)) ] ] col_left = [ [sg.Text("Process", size=(14, 1)), sg.Text(param[KEY_PROS_SEL], size=(47,1), text_color=cf, background_color=cb, key=KEY_PROS_SEL)], [sg.Text("Prompt jp", size=(14, 1)), sg.Multiline(param[KEY_PROMPT_JP], size=(52,3), text_color=cf, background_color=cb, disabled=True, key=KEY_PROMPT_JP)], [sg.Text("Prompt", size=(14, 1)), sg.Multiline(param[KEY_PROMPT], size=(52,2), text_color=cf, background_color=cb, disabled=True, key=KEY_PROMPT)], [sg.Text("Negative Prompt jp", size=(14, 1)), sg.Multiline(param[KEY_NEG_PROMPT_JP], size=(52,3), text_color=cf, background_color=cb, disabled=True, key=KEY_NEG_PROMPT_JP)], [sg.Text("Negative Prompt", size=(14, 1)), sg.Multiline(param[KEY_NEG_PROMPT], size=(52,2), text_color=cf, background_color=cb, disabled=True, key=KEY_NEG_PROMPT)], ] col_center = [ [sg.Text("Model Directory", size=(14, 1)), sg.Text(param[KEY_MODEL_DIR], size=(48,1), text_color=cf, background_color=cb, key=KEY_MODEL_DIR)], [sg.Text("Model", size=(14, 1)), sg.Text(param[KEY_MODEL], size=(48,1), text_color=cf, background_color=cb, key=KEY_MODEL)], [sg.Text("Input Image", size=(14, 1)), sg.Text(param[KEY_INPUTPATH], size=(48,1), text_color=cf, background_color=cb, key=KEY_INPUTPATH)], [sg.Text("Control Image", size=(14, 1)), sg.Text(param[KEY_CTRL_IMGPATH], size=(48,1), text_color=cf, background_color=cb, key=KEY_CTRL_IMGPATH)], [sg.Text("Control Model Dir", size=(14, 1)), sg.Text(param[KEY_CTRL_DIR], size=(48,1), text_color=cf, background_color=cb, key=KEY_CTRL_DIR)], [sg.Text("Control Model", size=(14, 1)), sg.Text(param[KEY_CTRL_MODEL], size=(48,1), text_color=cf, background_color=cb, key=KEY_CTRL_MODEL)], [sg.Text("Device", size=(14, 1)), sg.Text(param[KEY_DEVICE], size=(48,1), text_color=cf, background_color=cb, key=KEY_DEVICE)], [sg.Text("Max size", size=(14, 1)), sg.Text(param[KEY_MAXSIZE], size=(48,1), text_color=cf, background_color=cb, key=KEY_MAXSIZE)], [sg.Text("Time", size=(14, 1)), sg.Text(param[KEY_TIME], size=(48,1), text_color=cf, background_color=cb, key=KEY_TIME)], ] col_right = [ [sg.Text("Seed Value", size=(14, 1)), sg.Text(param[KEY_SEED_INPUT], size=(11,1), text_color=cf, background_color=cb, key=KEY_SEED)], [sg.Text("Steps", size=(14, 1)), sg.Text(param[KEY_STEP], size=(11,1), text_color=cf, background_color=cb, key=KEY_STEP)], [sg.Text("Guidance Scale", size=(14, 1)), sg.Text(param[KEY_SCALE], size=(11,1), text_color=cf, background_color=cb, key=KEY_SCALE)], [sg.Text("Strength", size=(14, 1)), sg.Text(param[KEY_STRENGTH], size=(11,1), text_color=cf, background_color=cb, key=KEY_STRENGTH)], [sg.Text("Image Width", size=(14, 1)), sg.Text(param[KEY_WIDTH], size=(11,1), text_color=cf, background_color=cb, key=KEY_WIDTH)], [sg.Text("Image Height", size=(14, 1)), sg.Text(param[KEY_HEIGHT], size=(11,1), text_color=cf, background_color=cb, key=KEY_HEIGHT)], [sg.Text("Image Scale", size=(14, 1)), sg.Text(param[KEY_IMG_SCALE], size=(11,1), text_color=cf, background_color=cb, key=KEY_IMG_SCALE)], [sg.Text("Control Scale", size=(14, 1)), sg.Text(param[KEY_CC_SCALE], size=(11,1), text_color=cf, background_color=cb, key=KEY_CC_SCALE)], ] layout = [ [sg.Column(col_top, vertical_alignment='top')], [sg.Column(col_left, vertical_alignment='top'), sg.Column(col_center, vertical_alignment='top'), sg.Column(col_right, vertical_alignment='top')], [sg.Column(col_btn, justification='r') ], ] # ウィンドウオブジェクトの作成 window = sg.Window(title, layout, finalize=True, return_keyboard_events=True, use_default_focus=False) img = cv2.imencode('.png', frame)[1].tobytes() window['CANVAS'].update(img) # ユーザーイベントの定義 canvas.bind('<Motion>', '_motion') canvas.bind('<ButtonPress>', '_click_on') canvas.bind('<ButtonRelease>', '_click_off') canvas.bind('<Double-Button>', '_double_click') page_offset, page_max = Thumb.get_page_max() window[KEY_PAGE].update(f'Page: {page_offset + 1}/{page_max}') window[KEY_PAGEUP].update(disabled = not Thumb.check_page_up()) window[KEY_PAGEDOWN].update(disabled = not Thumb.check_page_down()) param_save = param.copy() # パラメータ push new_make_f = False # イベントのループ while True: event, values = window.read() if new_make_f: new_make_f = False if event == KEY_CANCEL or event == sg.WIN_CLOSED: param = param_save.copy() # パラメータ pop image_file = '' break if event == KEY_OK: logger.debug(f'{event} {image_file}') break if event == KEY_PAGEUP: logger.debug(f'{event}') frame = Thumb.page_up() if frame is not None: window[KEY_TXTIMG].update('') img = cv2.imencode('.png', frame)[1].tobytes() window['CANVAS'].update(img) page_offset, page_max = Thumb.get_page_max() window[KEY_PAGE].update(f'Page: {page_offset + 1}/{page_max}') window[KEY_PAGEUP].update(disabled = not Thumb.check_page_up()) window[KEY_PAGEDOWN].update(disabled = not Thumb.check_page_down()) if event == KEY_PAGEDOWN: logger.debug(f'{event}') frame = Thumb.page_down() if frame is not None: window[KEY_TXTIMG].update('') img = cv2.imencode('.png', frame)[1].tobytes() window['CANVAS'].update(img) page_offset, page_max = Thumb.get_page_max() window[KEY_PAGE].update(f'Page: {page_offset + 1}/{page_max}') window[KEY_PAGEUP].update(disabled = not Thumb.check_page_up()) window[KEY_PAGEDOWN].update(disabled = not Thumb.check_page_down()) if event == 'CANVAS_motion': x = canvas.user_bind_event.x y = canvas.user_bind_event.y filename, frame = Thumb.pixel2file(x, y) window[KEY_TXTIMG].update(filename) img = cv2.imencode('.png', frame)[1].tobytes() window['CANVAS'].update(img) update_param(filename, False) if event == 'CANVAS_click_on': image_file, frame = Thumb.select_file() window[KEY_IMG_SEL].update(image_file) img = cv2.imencode('.png', frame)[1].tobytes() window['CANVAS'].update(img) logger.debug(f'{event} {image_file}') update_param(filename, True) if event == 'CANVAS_click_off': pass if event == 'CANVAS_double_click': ftype = my_thumbnail.get_file_type(image_file) if ftype== 0 or ftype == 1 or ftype == 2: sdt.image_disp(image_file, image_file) # ウィンドウ終了処理 window.close() return image_file #-----Test routine----- if __name__ == "__main__": # アプリケーション・ログ設定 module = os.path.basename(__file__) module_name = os.path.splitext(module)[0] logger = my_logging.get_module_logger_sel(module_name, 3) def_file = 'sd_results3/sd_00001_0.png' imgfile = image_dialog('sd_results3/result_100.csv', def_file, 'Results Image file select', my_thumbnail.DEF_THEME, 10, 3, logger = logger) logger.info('\nFinished.\n')※ 上記ソースコードは表示の都合上、半角コード '}' が 全角 '}'になっていることに注意
opt_list = [ ['cpu', 'store_true', 'cpu mode'], ['log', '3', 'Log level(-1/0/1/2/3/4/5) Default value is \'3\''], : ]・初期値が「''(空文字列)」の場合、パラメータは登録するが「基本情報の表示」で表示されない
機能 | 戻り値 | 関数 |
コマンド入力関連 | ||
コマンドライン・オプションの設定 | parser | parse_args(parser, pars_list): |
オプション・リストを変更する | bool | change_option(opt_list, key, val) |
コマンドライン・オプションチェック | res | is_option(opt, key) |
基本情報の表示 | - | display_info(opt, title) |
画像関連 | ||
イメージ変換 PIL → OpenCV | image | pil2cv(image) |
pil2cv_np(image) | ||
イメージ変換 OpenCV → PIL | image | cv2pil(image) |
cv2pil_np(image) | ||
イメージファイルの表示 | - | image_disp(image_path = , dispname = , maxsize = 800, wait_s = 0) |
OpenCV イメージ 結果の保存と表示 | - | image_save(image, save_path = '', dispname = '', maxsize = 1000, wait_s = 0) |
PIL イメージ 結果の保存と表示 | - | image_save2(image, save_path = '', dispname = '', maxsize = 1000, wait_s = 0) |
コントロールイメージ作成 | image | make_inpaint_condition(image, image_mask) |
その他 | ||
モデルを調べる(SD1.5 モデルは SD1.5/フォルダ内にある前提) | bool | is_sd15(model) |
ポーズ・ファイルか調べる | bool | is_pose(filepath) |
フォルダ内で連番のファイル名を得る | filenale | make_filename_by_seq(dirname, filename, seq_digit = 3, ex = '') |
生成画像のファイル名からシード値を得る | seed | path2seed(filepath) |
経過時間(秒)を hh:mm:ssフォーマットに変換 | hh:mm:ss | elapsed_time_str(seconds) |
ランダムなシード値を得る | seed | get_random_seed_value(n) |
日本語から英語に翻訳 | 英語文字列 | trans_jp2en(str) |
メモリー開放 | - | device_empty_cache(device) |
作業フォルダ名を得る | work_path | get_work_path(logger = None) |
ソース・マスク画像ファイル名を得る | src_path, mask_path | get_source_mask_path(image_path, logger = None) |
ポーズ画像画像ファイル名を得る | pose_path | get_pose_path(image_path, logger = None) |
diffusers parameter | ||
log 出力 | - | log_debug(msg, logger) |
log_info(msg, logger) | ||
--device | device | _get_device(opt, logger = None) |
--result_image_path | result_image_path | _get_result_image_path(opt, logger = None) |
--result_path | result_path | _get_result_path(opt, logger = None) |
--result_file | result_file | _get_result_file(opt, logger = None) |
--prompt(日本語) | prompt(英語) | _get_prompt(opt, logger = None) |
--neg_prompt(日本語) | neg_prompt(英語) | _get_negative_prompt(opt, logger = None) |
--model_dir | model_dir | _get_model_dir(opt, logger = None) |
--model_path | model_path | _get_model_path(opt, logger = None) |
--ctrl_model_dir | ctrl_model_dir | _get_controlnet_model_dir(opt, logger = None) |
--ctrl_model_path | ctrl_model_path | _get_controlnet_model_path(opt, logger = None) |
--image_path | image_path | _get_source_image_path(opt, logger = None) |
--image_path から PIL画像オブジェクトを得る | image | _get_source_image(opt, logger = None) |
--ctrl_image_path | ctrl_image_path | _get_control_image_path(opt, logger = None) |
--ctrl_image_path から PIL画像オブジェクトを得る | image | _get_control_image(opt, logger = None) |
パスから画像を読んでリサイズする | image | _get_resize_image(image_path, max_size, logger) |
--height, --width | height, width | _get_image_size(opt, logger = None) |
--max_size | max_size | _get_max_size(opt, logger = None) |
--seed(-1 の時は乱数生成) | seed | _get_seed_value(opt, logger = None) |
--num_inference_steps | num_inference_steps | _get_inference_steps(opt, logger = None) |
--guidance_scale | guidance_scale | _get_guidance_scale(opt, logger = None) |
--image_guidance_scale | image_guidance_scale | _get_image_guidance_scale(opt, logger = None) |
--strength | strength | _get_strength(opt, logger = None) |
--cc_scale | cc_scale | _get_controlnet_conditioning_scale(opt, logger = None) |
# -*- coding: utf-8 -*- ##-------------------------------------------------- ## sd_test basic tools Ver 0.05 ## ## 2025.07.17 Masahiro Izutsu ##-------------------------------------------------- ## sd_tools.py ## Ver 0.00 2025.07.17 Trial version ## Ver 0.05 2025.07.20 sd_100.py 統合版対応 # タイトル title = 'sd_test basic tools Ver 0.05' # 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 re import glob import random import argparse import numpy as np import cv2 from PIL import Image import torch import my_imagetool # 定数定義 IMAGES_WORK_DIR = 'images_work' ## ----- コマンド入力関連 -------------- # 初期値 def_result_image = '' def_cpu = 'store_true' def_log = '3' def_model_dir = '' def_model_path = '' def_ctrl_model_dir = '' def_ctrl_model_path = '' def_image_path = '' def_control_image_path = '' def_max_size = 0 def_prompt = '' def_seed = -1 def_width = 512 def_height = 512 def_step = 30 def_scale = 7.0 def_image_scale = 1.5 def_cc_scale = 1.0 def_strength = 0.5 def_neg_prompt = ' ' def_mode = 'store_false' # コマンドライン・オプション (argparse) 名前/初期値/ヘルプ opt_list = [ ['pros_sel','','sd_tools'], # 0 ['result_image', def_result_image, 'path to output image file'], # 1 ['cpu', def_cpu, 'cpu mode'], # 2 ['log', def_log, 'Log level(-1/0/1/2/3/4/5) Default value is \'3\''], # 3 ['model_dir', def_model_dir, 'Model directory'], # 4 ['model_path', def_model_path, 'Model Path'], # 5 ['ctrl_model_dir', def_ctrl_model_dir, 'ControlNet Model directory'], # 6 ['ctrl_model_path', def_ctrl_model_path, 'ControlNet Model Path'], # 7 ['image_path', def_image_path, 'Sourcs image file path'], # 8 ['ctrl_image_path', '', 'Control image file path'], # 9 ['max_size', def_max_size, 'image max size (0=source)'], # 10 ['prompt', def_prompt, 'Prompt text'], # 11 ['seed', def_seed, 'Seed parameter (-1 = rundom)'], # 12 ['width', def_width, 'image size width'], # 13 ['height', def_height, 'image size height'], # 14 ['step', def_step, 'infer step'], # 15 ['scale', def_scale, 'gaidanse scale'], # 16 ['image_scale', def_image_scale, 'image gaidanse scale'], # 17 ['cc_scale', def_cc_scale, 'controlnet conditioning scale'], # 18 ['strength', def_strength, 'strength value'], # 19 ['neg_prompt', def_neg_prompt, 'Negative Prompt text'], # 20 ['mode', def_mode, 'aplication mode'], ] # コマンドライン・オプションの設定 def parse_args(parser, pars_list): if parser == None: parser = argparse.ArgumentParser() for pars in pars_list: p = '--' + pars[0] if pars[1] == 'store_true' or pars[1] == 'store_false': parser.add_argument(p, dest = pars[0], action = pars[1], help = pars[2]) else: parser.add_argument(p, default = pars[1], help = pars[2]) return parser # オプション・リストを変更する def change_option(opt_list, key, val): bf = False for ol in opt_list: if ol[0] == key: ol[1] = val bf = True return bf def _get_process_name(opt_list): return opt_list[0][2] def _show_opt_list(opt_list): for ol in opt_list: print(ol) # 基本情報の表示 def display_info(opt, title): if title != '': print('\n' + GREEN + title + ': Starting application...' + '\n' + NOCOLOR) opt_dict = vars(opt) # NameSpace型を辞書型に変換 keys = opt_dict.keys() # key一覧取得 for key in keys: if opt_dict[key] != '': s = key + ' ' * 24 s0 = s[:24] print(f' --{YELLOW}{s0} : {NOCOLOR} {opt_dict[key]}') if title != '': print(' ') # コマンドライン・オプションチェック def is_option(opt, key): opt_dict = vars(opt) # NameSpace型を辞書型に変換 res = opt_dict.get(key) if res == '': res = None return res ## ----- 画像関連 ---------------------- # チャネル数の取得 def get_image_channel(image_path): pil_image = Image.open(image_path) ch = 0 if pil_image.mode == 'L' or pil_image.mode == 'P': ch = 1 elif pil_image.mode == 'RGB': ch = 3 elif pil_image.mode == 'RGBA': ch = 4 return ch # イメージ変換 PIL → OpenCV def pil2cv(image): new_image = np.array(image, dtype=np.uint8) if new_image.ndim == 2: # モノクロ pass elif new_image.shape[2] == 3: # カラー new_image = cv2.cvtColor(new_image, cv2.COLOR_RGB2BGR) elif new_image.shape[2] == 4: # 透過 new_image = cv2.cvtColor(new_image, cv2.COLOR_RGBA2BGRA) return new_image def pil2cv_np(image): new_image = np.array(image, dtype=np.uint8) if new_image.ndim == 2: # モノクロ pass elif new_image.shape[2] == 3: # カラー new_image = new_image[:, :, ::-1] elif new_image.shape[2] == 4: # 透過 new_image = new_image[:, :, [2, 1, 0, 3]] return new_image # イメージ変換 OpenCV → PIL def cv2pil(image): new_image = image.copy() if new_image.ndim == 2: # モノクロ pass elif new_image.shape[2] == 3: # カラー new_image = cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB) elif new_image.shape[2] == 4: # 透過 new_image = cv2.cvtColor(new_image, cv2.COLOR_BGRA2RGBA) new_image = Image.fromarray(new_image) return new_image def cv2pil_np(image): new_image = image.copy() if new_image.ndim == 2: # モノクロ pass elif new_image.shape[2] == 3: # カラー new_image = cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB) elif new_image.shape[2] == 4: # 透過 new_image = cv2.cvtColor(new_image, cv2.COLOR_BGRA2RGBA) new_image = Image.fromarray(new_image) return new_image # イメージファイルの表示 def image_disp(image_path = '', dispname = '', maxsize = 800, wait_s = 0): image = cv2.imread(image_path) dispf = dispname != '' my_imagetool.image_disp(image, winname = dispname, dispf = dispf, save_path = '', maxsize = maxsize, wait_s = wait_s) # OpenCV イメージ 結果の保存と表示 def image_save(image, save_path = '', dispname = '', maxsize = 800, wait_s = 0): dispf = dispname != '' my_imagetool.image_disp(image, winname = dispname, dispf = dispf, save_path = save_path, maxsize = maxsize, wait_s = wait_s) # PIL イメージ 結果の保存と表示 def image_save2(image, save_path = '', dispname = '', maxsize = 800, wait_s = 0): image = pil2cv(image) dispf = dispname != '' my_imagetool.image_disp(image, winname = dispname, dispf = dispf, save_path = save_path, maxsize = maxsize, wait_s = wait_s) # コントロールイメージ作成 def make_inpaint_condition(image, image_mask): image = np.array(image.convert("RGB")).astype(np.float32) / 255.0 image_mask = np.array(image_mask.convert("L")).astype(np.float32) / 255.0 assert image.shape[0:1] == image_mask.shape[0:1], "image and image_mask must have the same image size" image[image_mask > 0.5] = -1.0 # set as masked pixel image = np.expand_dims(image, 0).transpose(0, 3, 1, 2) image = torch.from_numpy(image) return image # 線画作成 def line_drawing_image(img): # 画像のコントラストを調整 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) # ガウシアンブラーを適用 gray_blurred = cv2.GaussianBlur(gray, (5, 5), 0) # エッジ検出で線画を生成(反転) edges = cv2.adaptiveThreshold(gray_blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 7) edges = 255 - edges return edges ## ------------------------------------- # モデルを調べる(SD1.5 モデルは SD1.5/フォルダ内にある前提) # in: model モデル名 # out: bool True = SD1.5, False = SDXL def is_sd15(model): return ('SD1.5' in model) # ポーズ・ファイルか調べる def is_pose(filepath): s = os.path.splitext(filepath) return s[0][-5:] == '_pose' # フォルダ内で連番のファイル名を得る(ヘッダ + 連番 で検索) # in: filename ヘッダー名.拡張子 # seq_digit 連番桁数 # ex 追加文字列 # out: 新しいファイル名 def make_filename_by_seq(dirname, filename, seq_digit = 3, ex = ''): filename_without_ext, ext = os.path.splitext(filename) pattern = f"{filename_without_ext}_([0-9]*){ext}" prog = re.compile(pattern) files = glob.glob( os.path.join(dirname, f"{filename_without_ext}_[0-9]*{ext}") ) max_seq = -1 kn = len(filename_without_ext) + seq_digit + 1 # ヘッダ + 連番桁数 + 1 (_) for f in files: fn0, _ = os.path.splitext(os.path.basename(f)) fn1 = fn0[: min(len(fn0), kn)] + ext m = prog.match(os.path.basename(fn1)) # ファイル名 kn まで比較 if m: max_seq = max(max_seq, int(m.group(1))) new_filename = f"{filename_without_ext}_{max_seq+1:0{seq_digit}}_{ex}{ext}" return new_filename # 生成画像のファイル名からシード値を得る def path2seed(filepath): s = os.path.splitext(os.path.basename(filepath))[0] n = s.rfind('_') return int(s[n + 1:]) # 経過時間(秒)を hh:mm:ssフォーマットに変換 def elapsed_time_str(seconds): seconds = int(seconds + 0.5) # 秒数を四捨五入 h = seconds // 3600 # 時の取得 m = (seconds - h * 3600) // 60 # 分の取得 s = seconds - h * 3600 - m * 60 # 秒の取得 return f"{h:02}:{m:02}:{s:02}" # hh:mm:ss形式の文字列で返す # ランダムなシード値を得る def get_random_seed_value(n): seed = int(n) if seed == -1: seed = random.randint(0, 2**32-1) return seed # 日本語から英語に翻訳 def trans_jp2en(str): from translate import Translator if len(str) != len(str.encode('utf-8')): trans = Translator('en','ja').translate prompt = trans(str) # 日本語→英語 else: prompt = str return prompt # メモリー開放 def device_empty_cache(device): if device == 'cuda': torch.cuda.empty_cache() elif device == 'mps': torch.mps.empty_cache() # 作業フォルダ名を得る def get_work_path(logger = None): work_path = os.getcwd().replace(os.sep,'/') + '/' + IMAGES_WORK_DIR log_debug(f'work_path: {work_path}', logger) return work_path # ソース・マスク画像ファイル名を得る def get_source_mask_path(image_path, logger = None): work_path = get_work_path() file = work_path + '/' + os.path.basename(image_path) s = os.path.splitext(file) src_path = s[0] + '_src' + s[1] mask_path = s[0] + '_mask' + s[1] log_debug(f'src_path: {src_path}', logger) log_debug(f'mask_path: {mask_path}', logger) return src_path, mask_path # ポーズ画像画像ファイル名を得る def get_pose_path(image_path, logger = None): work_path = get_work_path() file = work_path + '/' + os.path.basename(image_path) s = os.path.splitext(file) pose_path = s[0] + '_pose' + s[1] log_debug(f'pose_path: {pose_path}', logger) return pose_path ## ----- diffusers parameter ----------- # log 出力 def log_debug(msg, logger): if logger is not None: logger.debug(msg) def log_info(msg, logger): if logger is not None: logger.info(msg) # -- device -- def _get_device(opt, logger = None): gpu_d = torch.cuda.is_available() # GPU 確認 if not opt.cpu and not gpu_d: opt.cpu = True device = 'cpu' if opt.cpu else 'cuda' log_debug(f'device: {device}', logger) return device # -- result_image_path -- def _get_result_image_path(opt, logger = None): result_image_path = opt.result_image log_debug(f'result_image_path: {result_image_path}', logger) return result_image_path # -- result_path -- def _get_result_path(opt, logger = None): result_path = os.path.dirname(opt.result_image) log_debug(f'result_path: {result_path}', logger) return result_path # -- result_file -- def _get_result_file(opt, logger = None): result_file = os.path.basename(opt.result_image) log_debug(f'result_file: {result_file}', logger) return result_file # -- prompt -- def _get_prompt(opt, logger = None): prompt = def_prompt if is_option(opt, 'prompt') == None else trans_jp2en(opt.prompt) log_info(f'prompt: {prompt}', logger) return prompt # -- negative prompt -- def _get_negative_prompt(opt, logger = None): neg_prompt = def_neg_prompt if is_option(opt, 'neg_prompt') == None else trans_jp2en(opt.neg_prompt) log_info(f'neg_prompt: {neg_prompt}', logger) return neg_prompt # -- model_dir -- def _get_model_dir(opt, logger = None): model_dir = def_model_dir if is_option(opt, 'model_dir') == None else opt.model_dir log_debug(f'model_dir: {model_dir}', logger) return model_dir # -- model_path -- def _get_model_path(opt, logger = None): model_dir = _get_model_dir(opt, logger) path = def_model_path if is_option(opt, 'model_path') == None else opt.model_path model_path = path if model_dir == '' else model_dir + '/' + path log_debug(f'model_path: {model_path}', logger) return model_path # -- controlnet model_dir -- def _get_controlnet_model_dir(opt, logger = None): ctrl_model_dir = def_ctrl_model_dir if is_option(opt, 'ctrl_model_dir') == None else opt.ctrl_model_dir log_debug(f'ctrl_model_dir: {ctrl_model_dir}', logger) return ctrl_model_dir # -- controlnet model_path -- def _get_controlnet_model_path(opt, logger = None): ctrl_model_dir = _get_controlnet_model_dir(opt, logger) path = def_ctrl_model_path if is_option(opt, 'ctrl_model_path') == None else opt.ctrl_model_path ctrl_model_path = path if ctrl_model_dir == '' else ctrl_model_dir + '/' + path log_debug(f'controlnet model_path: {ctrl_model_path}', logger) return ctrl_model_path # -- source image path -- def _get_source_image_path(opt, logger = None): image_path = def_image_path if is_option(opt, 'image_path') == None else opt.image_path log_debug(f'image_path: {image_path}', logger) return image_path # -- source image -- def _get_source_image(opt, logger = None): image_path = def_image_path if is_option(opt, 'image_path') == None else opt.image_path max_size = def_max_size if is_option(opt, 'max_size') == None else int(opt.max_size) image = _get_resize_image(image_path, max_size, logger) log_debug(f'image_path: {image_path}', logger) return image # -- control image path -- def _get_control_image_path(opt, logger = None): ctrl_image_path = def_control_image_path if is_option(opt, 'ctrl_image_path') == None else opt.ctrl_image_path log_debug(f'ctrl_image_path: {ctrl_image_path}', logger) return ctrl_image_path # -- control source image -- def _get_control_image(opt, logger = None): ctrl_image_path = def_ctrl_image_path if is_option(opt, 'ctrl_image_path') == None else opt.ctrl_image_path max_size = def_max_size if is_option(opt, 'max_size') == None else int(opt.max_size) image = _get_resize_image(ctrl_image_path, max_size, logger) log_debug(f'ctrl_image_path: {ctrl_image_path}', logger) return image # -- resize image -- def _get_resize_image(image_path, max_size, logger = None): image = Image.open(image_path) w, h = image.size bf, h, w = my_imagetool.check_size(h, w, maxsize = max_size) if bf: image = image.resize((w, h), resample=Image.BICUBIC) log_debug(f'image size: width = {w}, height = {h}', logger) return image # -- height, width -- def _get_image_size(opt, logger = None): width = def_width if is_option(opt, 'width') == None else int(opt.width) height = def_height if is_option(opt, 'height') == None else int(opt.height) log_info(f'width: {width}, height: {height}', logger) return height, width # -- max_size -- def _get_max_size(opt, logger = None): max_size = def_max_size if is_option(opt, 'max_size') == None else int(opt.max_size) log_info(f'max_size: {max_size}', logger) return max_size # -- seed -- def _get_seed_value(opt, logger = None): seed = def_seed if is_option(opt, 'seed') == None else get_random_seed_value(opt.seed) log_info(f'seed: {seed}', logger) return seed # -- num_inference_steps -- def _get_inference_steps(opt, logger = None): num_inference_steps = def_step if is_option(opt, 'step') == None else int(opt.step) log_debug(f'step: {num_inference_steps}', logger) return num_inference_steps # -- guidance_scale -- def _get_guidance_scale(opt, logger = None): guidance_scale = def_scale if is_option(opt, 'def_scale') == None else float(opt.def_scale) log_debug(f'scale: {guidance_scale}', logger) return guidance_scale # -- image guidance_scale -- def _get_image_guidance_scale(opt, logger = None): image_guidance_scale = def_image_scale if is_option(opt, 'image_scale') == None else float(opt.image_scale) log_debug(f'image guidance scale: {image_guidance_scale}', logger) return image_guidance_scale # -- strength -- def _get_strength(opt, logger = None): strength = def_strength if is_option(opt, 'strength') == None else float(opt.strength) log_debug(f'strength: {strength}', logger) return strength # -- controlnet conditioning scale -- def _get_controlnet_conditioning_scale(opt, logger = None): cc_scale = def_cc_scale if is_option(opt, 'cc_scale') == None else float(opt.cc_scale) log_debug(f'controlnet conditioning scale: {cc_scale}', logger) return cc_scale ## ------------------------------------- #-----Test routine----- if __name__ == "__main__": source_path = './images/kamo.jpg' source_path = './images/sd_040_test.png' opt_list = [ ['result_image', './sd_results/sd.png', 'path to output image file'], ['cpu', 'store_true', 'cpu mode'], ['log', '3', 'Log level(-1/0/1/2/3/4/5) Default value is \'3\''], ['model_dir', '/StabilityMatrix/Data/Models/StableDiffusion', 'Model directory'], ['model_path', 'SD1.5/v1-5-pruned-emaonly.safetensors', 'Model Path'], ['prompt', '満開の欄', 'Prompt text'], ['seed', -1, 'Seed parameter (-1 = rundom)'], ['width', 512, 'image size width'], ['height', 512, 'image size height'], ['step', 30, 'infer step'], ['scale', 7.0, 'gaidanse scale'], ] parser = parse_args(None, opt_list) opt = parser.parse_args() display_info(opt, title) #------------ print('*** 画像表示 test ***') image_disp(source_path, source_path) print('*** 線画作成 test ***') img = cv2.imread(source_path) img2 = line_drawing_image(img) image_save(img2, 'test1.png', dispname = title) ''' # OpenCV 保存と表示 img = cv2.imread(source_path) image_save(img, 'test1.png', dispname = title) # PIL 保存と表示 img = Image.open(source_path) image_save2(img, 'test2.png', dispname = title) ''' #------------ print('*** diffusers parameter test ***') print(f'device : {_get_device(opt)}') #------------※ 上記ソースコードは表示の都合上、半角コード '}' が 全角 '}'になっていることに注意
PukiWiki 1.5.2 © 2001-2019 PukiWiki Development Team. Powered by PHP 7.4.33. HTML convert time: 0.094 sec.