import os import argparse import glob import operator from multiprocessing import Pool, cpu_count from shutil import rmtree from PIL import Image from math import floor parser = argparse.ArgumentParser() parser.add_argument('--step', default=192, type=int) parser.add_argument('--overlap', default=2, type=int) parser.add_argument('--scale', default=4, type=int) parser.add_argument('--in_dir', help='Directory to process') parser.add_argument('--render_dir', help='Directory to output render to') parser.add_argument('--mov', action='store_true', help='whether to create an mp4') parser.add_argument('--out_fn', help='mp4 basename') args = parser.parse_args() def split_crop_dir(fn): crop, x, y, w, h = os.path.basename(fn).split("_") return int(x), int(y), int(w), int(h) def make_movie(merge_dir, out_fn): subprocess.call([ 'ffmpeg', '-hide_banner', '-i', os.path.join(merge_dir, 'frame_%05d.png'), '-y', '-c:v', 'libx264', '-preset', 'slow', '-crf', '19', '-vf', 'fps=25', '-pix_fmt', 'yuv420p', os.path.join(opt.render_dir, out_fn + '.mp4') ]) def merge_files(file, crop_dir_list, ww, hh, overlap, merge_dir): fn = os.path.basename(file) print(fn) canvas = Image.new('RGB', (ww, hh,)) for crop_dir_tuple in crop_dir_list: x, y, w, h, ix, iy = crop_dir_tuple crop_dir = "crop_{}_{}_{}_{}".format(x, y, w, h) image = Image.open("{}/{}/{}".format(args.in_dir, crop_dir, fn)) crop = image.crop((overlap, overlap, image.size[0] - overlap, image.size[1] - overlap)) canvas.paste(crop, ((x - (ix * args.overlap)) * args.scale, (y - (iy * args.overlap)) * args.scale,)) canvas.save("{}/{}".format(merge_dir, fn)) def merge_dir(): overlap = args.overlap * args.scale crop_dirs = glob.glob("{}/crop_*".format(args.in_dir)) merge_dir = "{}/merged".format(args.in_dir) os.makedirs(merge_dir, exist_ok=True) ww = 0 hh = 0 masks = {} crop_dir_list = [] widths = [] heights = [] for crop_dir in crop_dirs: x, y, w, h = split_crop_dir(crop_dir) if x == 0: hh = max(y + h - args.overlap * 2, hh) if y == 0: ww = max(x + w - args.overlap * 2, ww) ix = 0 if x == 0 else 1 # floor(x / args.step) iy = floor(y / args.step) crop_dir_list.append((x, y, w, h, ix, iy)) crop_dir_list = sorted(crop_dir_list, key=operator.itemgetter(0, 1)) ww *= args.scale hh *= args.scale ww -= overlap hh -= overlap print("{}x{}".format(ww, hh)) files = sorted(glob.glob("{}/*.png".format(crop_dirs[0]))) dataset = [] for file in files: dataset.append((file, crop_dir_list, ww, hh, overlap, merge_dir,)) chunksize = 3 with Pool(processes=cpu_count()) as pool: pool.starmap(merge_files, dataset, chunksize) if args.mov: make_movie(merge_dir, opt.out_fn) if __name__ == "__main__": merge_dir()