inpaint.py 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import argparse, os, sys, glob
  2. from omegaconf import OmegaConf
  3. from PIL import Image
  4. from tqdm import tqdm
  5. import numpy as np
  6. import torch
  7. from main import instantiate_from_config
  8. from ldm.models.diffusion.ddim import DDIMSampler
  9. def make_batch(image, mask, device):
  10. image = np.array(Image.open(image).convert("RGB"))
  11. image = image.astype(np.float32)/255.0
  12. image = image[None].transpose(0,3,1,2)
  13. image = torch.from_numpy(image)
  14. mask = np.array(Image.open(mask).convert("L"))
  15. mask = mask.astype(np.float32)/255.0
  16. mask = mask[None,None]
  17. mask[mask < 0.5] = 0
  18. mask[mask >= 0.5] = 1
  19. mask = torch.from_numpy(mask)
  20. masked_image = (1-mask)*image
  21. batch = {"image": image, "mask": mask, "masked_image": masked_image}
  22. for k in batch:
  23. batch[k] = batch[k].to(device=device)
  24. batch[k] = batch[k]*2.0-1.0
  25. return batch
  26. if __name__ == "__main__":
  27. parser = argparse.ArgumentParser()
  28. parser.add_argument(
  29. "--indir",
  30. type=str,
  31. nargs="?",
  32. help="dir containing image-mask pairs (`example.png` and `example_mask.png`)",
  33. )
  34. parser.add_argument(
  35. "--outdir",
  36. type=str,
  37. nargs="?",
  38. help="dir to write results to",
  39. )
  40. parser.add_argument(
  41. "--steps",
  42. type=int,
  43. default=50,
  44. help="number of ddim sampling steps",
  45. )
  46. opt = parser.parse_args()
  47. masks = sorted(glob.glob(os.path.join(opt.indir, "*_mask.png")))
  48. images = [x.replace("_mask.png", ".png") for x in masks]
  49. print(f"Found {len(masks)} inputs.")
  50. config = OmegaConf.load("models/ldm/inpainting_big/config.yaml")
  51. model = instantiate_from_config(config.model)
  52. model.load_state_dict(torch.load("models/ldm/inpainting_big/last.ckpt")["state_dict"],
  53. strict=False)
  54. device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
  55. model = model.to(device)
  56. sampler = DDIMSampler(model)
  57. os.makedirs(opt.outdir, exist_ok=True)
  58. with torch.no_grad():
  59. with model.ema_scope():
  60. for image, mask in tqdm(zip(images, masks)):
  61. outpath = os.path.join(opt.outdir, os.path.split(image)[1])
  62. batch = make_batch(image, mask, device=device)
  63. # encode masked image and concat downsampled mask
  64. c = model.cond_stage_model.encode(batch["masked_image"])
  65. cc = torch.nn.functional.interpolate(batch["mask"],
  66. size=c.shape[-2:])
  67. c = torch.cat((c, cc), dim=1)
  68. shape = (c.shape[1]-1,)+c.shape[2:]
  69. samples_ddim, _ = sampler.sample(S=opt.steps,
  70. conditioning=c,
  71. batch_size=c.shape[0],
  72. shape=shape,
  73. verbose=False)
  74. x_samples_ddim = model.decode_first_stage(samples_ddim)
  75. image = torch.clamp((batch["image"]+1.0)/2.0,
  76. min=0.0, max=1.0)
  77. mask = torch.clamp((batch["mask"]+1.0)/2.0,
  78. min=0.0, max=1.0)
  79. predicted_image = torch.clamp((x_samples_ddim+1.0)/2.0,
  80. min=0.0, max=1.0)
  81. inpainted = (1-mask)*image+mask*predicted_image
  82. inpainted = inpainted.cpu().numpy().transpose(0,2,3,1)[0]*255
  83. Image.fromarray(inpainted.astype(np.uint8)).save(outpath)