GarmentCode / app.py
qbhf2's picture
modified: app.py
e8212a9
Raw History Blame Contribute Delete
18.1 kB
import gradio as gr
import asyncio
import os
import subprocess
import shutil
import logging
import json
from pathlib import Path
import yaml
import coloredlogs
import re
from custom_utils.setup_env import run_setup_script
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
coloredlogs.install(level='INFO', fmt='%(levelname)s: %(message)s',
level_styles={'info': {'color': 'green'},
'error':{'color':'red'}
}
)
# === Загрузка конфига ===
with open("GarmentCode/gradio_config.yml", "r") as f:
config = yaml.safe_load(f)
# === Вспомогательные функции ===
def organize_images_into_structure(source_folder, new_folder):
os.makedirs(new_folder, exist_ok=True)
for file_name in os.listdir(source_folder):
source_file = os.path.join(source_folder, file_name)
if os.path.isfile(source_file) and file_name.lower().endswith(('.png', '.jpg', '.jpeg')):
folder_name = os.path.splitext(file_name)[0]
subfolder_path = os.path.join(new_folder, folder_name, "outputs")
os.makedirs(subfolder_path, exist_ok=True)
destination_file = os.path.join(subfolder_path, file_name)
shutil.copy(source_file, destination_file)
def update_body_model(selected_key):
return config['body_model_files'].get(selected_key, config['defaults']['body_config'])
def get_design_choices():
design_dir = config['assets_paths']['design_params'] # "assets/design_params/"
design_choices = []
for fname in os.listdir(design_dir):
if fname.endswith(".yaml"):
design_choices.append(os.path.splitext(fname)[0])
return design_choices
def get_sim_props_choices():
sim_props_dir=config['assets_paths']['sim_props']
sim_props_choices_yaml, sim_props_choices_json=[],[]
for fname in os.listdir(sim_props_dir):
if fname.endswith(".yaml"):
sim_props_choices_yaml.append(os.path.splitext(fname)[0])
elif fname.endswith(".json"):
sim_props_choices_json.append(os.path.splitext(fname)[0])
return sim_props_choices_yaml, sim_props_choices_json
def extract_dataset_path(stdout: str) -> str:
# Ищем строку с "Result saved to:"
match = re.search(r"Result saved to: (.+)", stdout)
if match:
path = match.group(1).strip()
# Убираем подкаталог default_body, если он есть в конце пути
if path.endswith('/default_body') or path.endswith('\\default_body'):
path = os.path.dirname(path)
return path
return None
def get_png_path(folder: str):
basename = os.path.basename(folder)
png_path = os.path.join(folder, f"{basename}_pattern.png")
if os.path.isfile(png_path):
logging.info(f"PNG FILE LOCATED AT {png_path}")
return png_path
return None
def zip_folder(folder_path: str) -> str:
folder_path_obj = Path(folder_path)
zip_path = str(folder_path_obj) + '.zip'
shutil.make_archive(str(folder_path_obj), 'zip', folder_path)
return zip_path
def show_button_if_both_uploaded(front_img, back_img):
return gr.update(visible=front_img is not None and back_img is not None)
def update_submenu(clothing_type):
if clothing_type == "Top":
return (
gr.Dropdown(visible=True, label="Front Collar",
choices=["CircleNeckHalf", "CurvyNeckHalf", "VNeckHalf", "SquareNeckHalf",
"TrapezoidNeckHalf", "CircleArcNeckHalf", "Bezier2NeckHalf"],
interactive=True),
gr.Dropdown(visible=True, label="Back Collar",
choices=["CircleNeckHalf", "CurvyNeckHalf", "VNeckHalf", "SquareNeckHalf",
"TrapezoidNeckHalf", "CircleArcNeckHalf", "Bezier2NeckHalf"],
interactive=True)
)
elif clothing_type == "Down":
return (
gr.Dropdown(visible=True, label="Waist Style",
choices=["High Waist", "Low Waist", "Medium Waist"],
interactive=True),
gr.Dropdown(visible=False, interactive=True)
)
elif clothing_type == "Full body":
return (
gr.Dropdown(visible=True, label="Overall Style",
choices=["Slim Fit", "Loose Fit", "Regular Fit"],
interactive=True),
gr.Dropdown(visible=False, interactive=True)
)
else:
return (
gr.Dropdown(visible=False, interactive=True),
gr.Dropdown(visible=False, interactive=True)
)
# === Симуляция/сэмплирование ===
# TODO: recreate fitting. Is it strictly necessary?
async def run_dataset_fitting(design_file: str, size: int, name: str, replicate: bool) -> str:
return
async def run_pattern_sampler(size: int, dataset_name: str, replicate: bool, pattern_config_name: str, body_file:str):
pattern_config_path = f"assets/design_params/{pattern_config_name}.yaml"
body_path = getattr(body_file, 'name', body_file) if body_file else "mean_female"
cmd = [
"python3", "GarmentCode/pattern_sampler.py",
"-s", str(size),
"--name", dataset_name,
"--pattern-config", pattern_config_path,
"--body", body_path
]
if replicate:
cmd.append("--replicate")
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await proc.communicate()
logging.info(stdout.decode())
log = stdout.decode()
if proc.returncode != 0:
logging.error(f"Ошибка при генерации датасета:{stderr.decode()}")
return f"Ошибка при генерации датасета:\n{stderr.decode()}", gr.update(visible=False), None
dataset_path = (extract_dataset_path(log))
zip_folder_path = f"{zip_folder(dataset_path)}"
return stdout.decode(), gr.update(visible=True), dataset_path, zip_folder_path
async def run_pattern_data_sim(dataset_path: str, clothing_spec: str, default_body: bool = False):
dataset_path = dataset_path.replace("datasets/", "", 1)
clothing_spec=clothing_spec+".yaml"
cmd = [
"python3", "GarmentCode/pattern_data_sim.py",
"--data", dataset_path,
"-c", clothing_spec
]
# Добавляем флаг только если default_body=True
if default_body:
cmd.append("--default_body")
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await proc.communicate()
if proc.returncode != 0:
logging.error(f"Ошибка при симуляции: {stderr.decode()}")
return f"Ошибка при симуляции:\n{stderr.decode()}"
dataset_sim_path = "datasets_sim/" + dataset_path
zip_file_path = f"{zip_folder(dataset_sim_path)}"
return zip_file_path
async def simulation(pattern_spec_path:str, sim_props_path:str):
cmd = [
"python3", "GarmentCode/test_garment_sim.py",
"-p", pattern_spec_path,
"-s", sim_props_path,
]
async def create_pattern(
body_config_file, # gr.File или None
design_config_file, # gr.File или None
body_to_use=None, # str или None
design_to_use=None # str или None
):
# Если файл не выбран - используем дефолт из конфига
body_config_path = getattr(body_config_file, 'name', body_config_file) if body_config_file else config['defaults'][
'body_config']
design_config_path = getattr(design_config_file, 'name', design_config_file) if design_config_file else \
config['defaults']['design_config']
logging.info("CREATION OF PATTERN FILES...")
cmd = [
"python3", "test_garmentcode.py",
"--body-config", body_config_path,
"--design-config", design_config_path,
]
if body_to_use:
cmd += ["--body-to-use", body_to_use]
if design_to_use:
cmd += ["--design-to-use", design_to_use]
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await proc.communicate()
if proc.returncode != 0:
logging.error(f"Pattern creation failed:\n{stderr.decode()}")
return f"Pattern creation failed:\n{stderr.decode()}"
result_str = stdout.decode()
folder = None
for line in result_str.splitlines():
if "saved to" in line:
folder = line.split("saved to")[-1].strip()
break
if not folder or not os.path.isdir(folder):
logging.error("Ошибка: не удалось найти папку с результатом.")
return "Ошибка: не удалось найти папку с результатом.", None, None
png_file = get_png_path(folder)
if not png_file:
logging.error("Ошибка: PNG-файл не найден.")
return "Ошибка: PNG-файл не найден.", None, None
zip_path = zip_folder(folder)
logging.info("PATTERN CREATION ENDED SUCCESSFULLY")
return result_str, zip_path, png_file
with gr.Blocks(title="3D Garment Generator", theme=gr.themes.Default(text_size="sm")) as demo:
with gr.Tabs():
with gr.Tab("Генератор одежды"):
front_collar = gr.State()
back_collar = gr.State()
with gr.Row():
with gr.Column(scale=1):
with gr.Accordion("Инференс",open=False):
front_img = gr.Image(label="Добавьте фотографию впереди")
back_img = gr.Image(label="Добавьте фотографию сзади")
create_pattern_btn = gr.Button("Создать паттерн", visible=False)
with gr.Accordion("1. Пресеты", open=False):
gr.Markdown("### Параметры генерации")
with gr.Accordion("Загрузить файлы", open=False):
body_config_file = gr.File(label="Body config (YAML)")
design_config_file = gr.File(label="Design config (YAML)")
system_config_file = gr.File(label="System config (JSON)")
body_to_use_dropdown = gr.Dropdown(
choices=list(config['body_model_files'].keys()),
label="Body key", value="mean_female")
design_to_use_dropdown = gr.Dropdown(
choices=["t-shirt"], label="Design key", value="t-shirt")
create_pattern_btn = gr.Button("Создать паттерн")
result_box = gr.Textbox(label="Результат")
image_result = gr.Image(label="Результат PNG")
with gr.Accordion("2. Параметры генерации", open=True):
clothing_type_dropdown = gr.Dropdown(
label="Тип одежды",
choices=["Top", "Down", "Full body"],
value="Top",
interactive=True
)
front_dropdown = gr.Dropdown(
visible=False,
label="Front Collar",
choices=[],
interactive=True
)
back_dropdown = gr.Dropdown(
visible=False,
label="Back Collar",
choices=[],
interactive=True
)
overall_length = gr.Slider(
1, 50, value=25, label="Длина одежды",
info="Выберите значение от 1 до 50",
interactive=True
)
clothing_type_dropdown.change(
fn=update_submenu,
inputs=clothing_type_dropdown,
outputs=[front_dropdown, back_dropdown]
)
with gr.Accordion("3. Дополнительные инструменты", open=False):
with gr.Accordion("Генерация датасета", open=False):
dataset_size = gr.Slider(1, 5000, value=1, label="Размер датасета",
info="Выберите значение от 1 до 5000", interactive=True)
replicate_checkbox = gr.Checkbox(label="Репликация", value=False)
dataset_name_box = gr.Textbox(label="Название датасета", max_lines=1)
pattern_config_choices = get_design_choices()
pattern_config_file = gr.Radio(
label="Config",
choices=pattern_config_choices,
value=pattern_config_choices[0] if pattern_config_choices else None
)
body_file = gr.File(label="Body config (YAML)")
pattern_sampler_run_button = gr.Button("Сгенерировать паттерны", size="sm")
pattern_result_box = gr.Textbox(label="Лог генерации")
# sim_props_gen_choices_yaml = gr.Radio(label="Properties config",
# choices=get_sim_props_choices()[0],
# interactive=True,
# value=pattern_config_choices[
# 0] if pattern_config_choices else None
#
# )
sim_props_gen_choices_json = gr.Radio(label="Clothing config",
choices=get_sim_props_choices()[0],
interactive=True,
value=pattern_config_choices[
0] if pattern_config_choices else None
)
dataset_path_box = gr.Textbox(visible=False)
default_body_checkbox = gr.Checkbox(label="default body",value=False)
dataset_gen_button = gr.Button("Генерация датасета",
variant="primary", visible=False)
## Button callbacks ##
with gr.Column(scale=3):
viewer = gr.Model3D(
config['body_model_files']['custom_female'],
display_mode="solid", label="3D Рендер",
height=500, container=True, camera_position=(90, None, None),
interactive=False, clear_color=(0.85, 0.85, 0.85, 1)
)
fit_button = gr.Button("Запустить симуляцию", variant="primary", size="sm")
with gr.Row():
save_render_btn = gr.Button("Сохранить рендер")
save_obj_btn = gr.Button("Сохранить OBJ")
clear_button = gr.Button("Очистить")
zip_file = gr.File(label="Download Zip File", file_count="multiple",
file_types=[".zip"], height=50, interactive=False)
create_pattern_btn.click(
fn=create_pattern,
inputs=[body_config_file, design_config_file, body_to_use_dropdown, design_to_use_dropdown],
outputs=[result_box, zip_file, image_result]
)
body_to_use_dropdown.change(
fn=update_body_model,
inputs=body_to_use_dropdown,
outputs=viewer
)
pattern_sampler_run_button.click(
fn=run_pattern_sampler,
inputs=[dataset_size, dataset_name_box, replicate_checkbox, pattern_config_file,
body_file],
outputs=[pattern_result_box, dataset_gen_button, dataset_path_box, zip_file]
)
dataset_gen_button.click(
fn=run_pattern_data_sim,
inputs=[dataset_path_box, sim_props_gen_choices_json, default_body_checkbox],
outputs=[zip_file],
)
front_img.change(
fn=show_button_if_both_uploaded,
inputs=[front_img, back_img],
outputs=create_pattern_btn
)
back_img.change(
fn=show_button_if_both_uploaded,
inputs=[front_img, back_img],
outputs=create_pattern_btn
)
with gr.Tab("SewFormer"):
gr.Markdown("Photo to pattern")
with gr.Tab("Image to Pattern"):
gr.Markdown("JPG to PBR")
if __name__ == "__main__":
run_setup_script()
demo.launch(server_port=7860)