GarmentCode / GarmentCode /pattern_fitter.py
qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
raw
history blame
7.52 kB
"""
Fitting one sewing pattern design to a set of various body shapes
"""
from datetime import datetime
from pathlib import Path
import yaml
import shutil
import time
import traceback
import argparse
# Custom
from pygarment.data_config import Properties
from assets.garment_programs.meta_garment import MetaGarment
from assets.bodies.body_params import BodyParameters
def get_command_args():
"""command line arguments to control the run"""
# https://stackoverflow.com/questions/40001892/reading-named-command-arguments
parser = argparse.ArgumentParser()
parser.add_argument('design_file', help='Path to design parameters file to be used to fit to the bodies', type=str)
parser.add_argument('--batch_id', '-b', help='id of a sampling batch', type=int, default=None)
parser.add_argument('--size', '-s', help='size of a sample', type=int, default=10)
parser.add_argument('--name', '-n', help='Name of the dataset', type=str, default='design_fit')
parser.add_argument('--replicate', '-re', help='Name of the dataset to re-generate. If set, other arguments are ignored', type=str, default=None)
args = parser.parse_args()
print('Commandline arguments: ', args)
return args
def _create_data_folder(properties, path=Path('')):
""" Create a new directory to put dataset in
& generate appropriate name & update dataset properties
"""
if 'data_folder' in properties: # will this work?
# => regenerating from existing data
properties['name'] = properties['data_folder'] + '_regen'
data_folder = properties['name']
else:
data_folder = properties['name']
# make unique
data_folder += '_' + datetime.now().strftime('%y%m%d-%H-%M-%S')
properties['data_folder'] = data_folder
path_with_dataset = path / data_folder
path_with_dataset.mkdir(parents=True)
default_folder = path_with_dataset / 'default_body'
body_folder = path_with_dataset / 'random_body'
default_folder.mkdir(parents=True, exist_ok=True)
body_folder.mkdir(parents=True, exist_ok=True)
return path_with_dataset, default_folder, body_folder
def _gather_body_options(body_path: Path):
objs_path = body_path / 'measurements'
bodies = []
for file in objs_path.iterdir():
# Get name
b_name = file.stem.split('_')[0]
bodies.append({})
# Get obj options
bodies[-1]['objs'] = dict(
straight=f'meshes/{b_name}_straight.obj',
apart=f'meshes/{b_name}_apart.obj', )
# Get measurements
bodies[-1]['mes'] = f'measurements/{b_name}.yaml'
return bodies
def body_sample(idx, bodies: dict, path: Path, straight=True):
body_i = bodies[idx]
mes_file = body_i['mes']
obj_file = body_i['objs']['straight'] if straight else body_i['objs']['apart']
body = BodyParameters(path / mes_file)
body.params['body_sample'] = (path / obj_file).stem
return body
def _save_sample(piece, body, new_design, folder, verbose=False):
pattern = piece.assembly()
# Save as json file
folder = pattern.serialize(
folder,
tag='',
to_subfolder=True,
with_3d=False, with_text=False, view_ids=False)
body.save(folder)
with open(Path(folder) / 'design_params.yaml', 'w') as f:
yaml.dump(
{'design': new_design},
f,
default_flow_style=False,
sort_keys=False
)
if verbose:
print(f'Saved {piece.name}')
def generate(path, properties, sys_paths, verbose=False):
"""Generates a synthetic dataset of patterns with given properties
Params:
path : path to folder to put a new dataset into
props : an instance of DatasetProperties class
requested properties of the dataset
"""
path = Path(path)
gen_config = properties['generator']['config']
gen_stats = properties['generator']['stats']
body_samples_path = Path(sys_paths['body_samples_path']) / properties['body_samples']
body_options = _gather_body_options(body_samples_path)
# create data folder
data_folder, default_path, body_sample_path = _create_data_folder(properties, path)
default_sample_data = default_path / 'data'
body_sample_data = body_sample_path / 'data'
# generate data
start_time = time.time()
# Load design
with open(properties['design_file'], 'r') as f:
design = yaml.safe_load(f)['design']
# On default body
default_body = BodyParameters(Path(sys_paths['bodies_default_path']) / (properties['body_default'] + '.yaml'))
piece_default = MetaGarment(properties['body_default'], default_body, design)
_save_sample(piece_default, default_body, design, default_sample_data, verbose=verbose)
for i in range(properties['size']):
# log properties every time
properties.serialize(data_folder / 'dataset_properties.yaml')
try:
# On random body shape
rand_body = body_sample(
i + properties['body_sample_start_id'],
body_options,
body_samples_path,
straight='Pants' != design['meta']['bottom']['v'])
name = rand_body.params['body_sample']
piece_shaped = MetaGarment(name, rand_body, design)
# Save samples
_save_sample(piece_shaped, rand_body, design, body_sample_data, verbose=verbose)
except KeyboardInterrupt: # Return immediately with whatever is ready
return default_path, body_sample_path
except BaseException as e:
print(f'{name} failed')
traceback.print_exc()
print(e)
continue
elapsed = time.time() - start_time
gen_stats['generation_time'] = f'{elapsed:.3f} s'
# log properties
properties.serialize(data_folder / 'dataset_properties.yaml')
return default_path, body_sample_path
def gather_visuals(path, verbose=False):
vis_path = Path(path) / 'patterns_vis'
vis_path.mkdir(parents=True, exist_ok=True)
for p in path.rglob("*.png"):
try:
shutil.copy(p, vis_path)
except shutil.SameFileError:
if verbose:
print('File {} already exists'.format(p.name))
pass
if __name__ == '__main__':
system_props = Properties('./system.json')
args = get_command_args()
if args.replicate is not None:
props = Properties(
Path(system_props['datasets_path']) / args.replicate / 'dataset_properties.yaml',
True)
else:
props = Properties()
props.set_basic(
design_file=args.design_file,
body_default='mean_all',
body_samples='5000_body_shapes_and_measures',
body_sample_start_id=0,
name=f'{args.name}_{args.size}' if not args.batch_id else f'{args.name}_{args.size}_{args.batch_id}',
size=args.size,
to_subfolders=True)
props.set_section_config('generator')
# Generator
default_path, body_sample_path = generate(
system_props['datasets_path'], props, system_props, verbose=False)
# Gather the pattern images separately
gather_visuals(default_path)
gather_visuals(body_sample_path)
# At the end -- it takes some time to gather the info
props.add_sys_info()
print('Data generation completed!')