Spaces:
Sleeping
Sleeping
| """ | |
| 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!') | |