img2img.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import os
  2. from contextlib import closing
  3. from pathlib import Path
  4. import numpy as np
  5. from PIL import Image, ImageOps, ImageFilter, ImageEnhance, UnidentifiedImageError
  6. import gradio as gr
  7. from modules import images
  8. from modules.infotext_utils import create_override_settings_dict, parse_generation_parameters
  9. from modules.processing import Processed, StableDiffusionProcessingImg2Img, process_images
  10. from modules.shared import opts, state
  11. from modules.sd_models import get_closet_checkpoint_match
  12. import modules.shared as shared
  13. import modules.processing as processing
  14. from modules.ui import plaintext_to_html
  15. import modules.scripts
  16. def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args, to_scale=False, scale_by=1.0, use_png_info=False, png_info_props=None, png_info_dir=None):
  17. output_dir = output_dir.strip()
  18. processing.fix_seed(p)
  19. batch_images = list(shared.walk_files(input_dir, allowed_extensions=(".png", ".jpg", ".jpeg", ".webp", ".tif", ".tiff")))
  20. is_inpaint_batch = False
  21. if inpaint_mask_dir:
  22. inpaint_masks = shared.listfiles(inpaint_mask_dir)
  23. is_inpaint_batch = bool(inpaint_masks)
  24. if is_inpaint_batch:
  25. print(f"\nInpaint batch is enabled. {len(inpaint_masks)} masks found.")
  26. print(f"Will process {len(batch_images)} images, creating {p.n_iter * p.batch_size} new images for each.")
  27. state.job_count = len(batch_images) * p.n_iter
  28. # extract "default" params to use in case getting png info fails
  29. prompt = p.prompt
  30. negative_prompt = p.negative_prompt
  31. seed = p.seed
  32. cfg_scale = p.cfg_scale
  33. sampler_name = p.sampler_name
  34. steps = p.steps
  35. override_settings = p.override_settings
  36. sd_model_checkpoint_override = get_closet_checkpoint_match(override_settings.get("sd_model_checkpoint", None))
  37. batch_results = None
  38. discard_further_results = False
  39. for i, image in enumerate(batch_images):
  40. state.job = f"{i+1} out of {len(batch_images)}"
  41. if state.skipped:
  42. state.skipped = False
  43. if state.interrupted or state.stopping_generation:
  44. break
  45. try:
  46. img = images.read(image)
  47. except UnidentifiedImageError as e:
  48. print(e)
  49. continue
  50. # Use the EXIF orientation of photos taken by smartphones.
  51. img = ImageOps.exif_transpose(img)
  52. if to_scale:
  53. p.width = int(img.width * scale_by)
  54. p.height = int(img.height * scale_by)
  55. p.init_images = [img] * p.batch_size
  56. image_path = Path(image)
  57. if is_inpaint_batch:
  58. # try to find corresponding mask for an image using simple filename matching
  59. if len(inpaint_masks) == 1:
  60. mask_image_path = inpaint_masks[0]
  61. else:
  62. # try to find corresponding mask for an image using simple filename matching
  63. mask_image_dir = Path(inpaint_mask_dir)
  64. masks_found = list(mask_image_dir.glob(f"{image_path.stem}.*"))
  65. if len(masks_found) == 0:
  66. print(f"Warning: mask is not found for {image_path} in {mask_image_dir}. Skipping it.")
  67. continue
  68. # it should contain only 1 matching mask
  69. # otherwise user has many masks with the same name but different extensions
  70. mask_image_path = masks_found[0]
  71. mask_image = images.read(mask_image_path)
  72. p.image_mask = mask_image
  73. if use_png_info:
  74. try:
  75. info_img = img
  76. if png_info_dir:
  77. info_img_path = os.path.join(png_info_dir, os.path.basename(image))
  78. info_img = images.read(info_img_path)
  79. geninfo, _ = images.read_info_from_image(info_img)
  80. parsed_parameters = parse_generation_parameters(geninfo)
  81. parsed_parameters = {k: v for k, v in parsed_parameters.items() if k in (png_info_props or {})}
  82. except Exception:
  83. parsed_parameters = {}
  84. p.prompt = prompt + (" " + parsed_parameters["Prompt"] if "Prompt" in parsed_parameters else "")
  85. p.negative_prompt = negative_prompt + (" " + parsed_parameters["Negative prompt"] if "Negative prompt" in parsed_parameters else "")
  86. p.seed = int(parsed_parameters.get("Seed", seed))
  87. p.cfg_scale = float(parsed_parameters.get("CFG scale", cfg_scale))
  88. p.sampler_name = parsed_parameters.get("Sampler", sampler_name)
  89. p.steps = int(parsed_parameters.get("Steps", steps))
  90. model_info = get_closet_checkpoint_match(parsed_parameters.get("Model hash", None))
  91. if model_info is not None:
  92. p.override_settings['sd_model_checkpoint'] = model_info.name
  93. elif sd_model_checkpoint_override:
  94. p.override_settings['sd_model_checkpoint'] = sd_model_checkpoint_override
  95. else:
  96. p.override_settings.pop("sd_model_checkpoint", None)
  97. if output_dir:
  98. p.outpath_samples = output_dir
  99. p.override_settings['save_to_dirs'] = False
  100. p.override_settings['save_images_replace_action'] = "Add number suffix"
  101. if p.n_iter > 1 or p.batch_size > 1:
  102. p.override_settings['samples_filename_pattern'] = f'{image_path.stem}-[generation_number]'
  103. else:
  104. p.override_settings['samples_filename_pattern'] = f'{image_path.stem}'
  105. proc = modules.scripts.scripts_img2img.run(p, *args)
  106. if proc is None:
  107. p.override_settings.pop('save_images_replace_action', None)
  108. proc = process_images(p)
  109. if not discard_further_results and proc:
  110. if batch_results:
  111. batch_results.images.extend(proc.images)
  112. batch_results.infotexts.extend(proc.infotexts)
  113. else:
  114. batch_results = proc
  115. if 0 <= shared.opts.img2img_batch_show_results_limit < len(batch_results.images):
  116. discard_further_results = True
  117. batch_results.images = batch_results.images[:int(shared.opts.img2img_batch_show_results_limit)]
  118. batch_results.infotexts = batch_results.infotexts[:int(shared.opts.img2img_batch_show_results_limit)]
  119. return batch_results
  120. def img2img(id_task: str, request: gr.Request, mode: int, prompt: str, negative_prompt: str, prompt_styles, init_img, sketch, init_img_with_mask, inpaint_color_sketch, inpaint_color_sketch_orig, init_img_inpaint, init_mask_inpaint, mask_blur: int, mask_alpha: float, inpainting_fill: int, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, denoising_strength: float, selected_scale_tab: int, height: int, width: int, scale_by: float, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, img2img_batch_inpaint_mask_dir: str, override_settings_texts, img2img_batch_use_png_info: bool, img2img_batch_png_info_props: list, img2img_batch_png_info_dir: str, *args):
  121. override_settings = create_override_settings_dict(override_settings_texts)
  122. is_batch = mode == 5
  123. if mode == 0: # img2img
  124. image = init_img
  125. mask = None
  126. elif mode == 1: # img2img sketch
  127. image = sketch
  128. mask = None
  129. elif mode == 2: # inpaint
  130. image, mask = init_img_with_mask["image"], init_img_with_mask["mask"]
  131. mask = processing.create_binary_mask(mask)
  132. elif mode == 3: # inpaint sketch
  133. image = inpaint_color_sketch
  134. orig = inpaint_color_sketch_orig or inpaint_color_sketch
  135. pred = np.any(np.array(image) != np.array(orig), axis=-1)
  136. mask = Image.fromarray(pred.astype(np.uint8) * 255, "L")
  137. mask = ImageEnhance.Brightness(mask).enhance(1 - mask_alpha / 100)
  138. blur = ImageFilter.GaussianBlur(mask_blur)
  139. image = Image.composite(image.filter(blur), orig, mask.filter(blur))
  140. elif mode == 4: # inpaint upload mask
  141. image = init_img_inpaint
  142. mask = init_mask_inpaint
  143. else:
  144. image = None
  145. mask = None
  146. image = images.fix_image(image)
  147. mask = images.fix_image(mask)
  148. if selected_scale_tab == 1 and not is_batch:
  149. assert image, "Can't scale by because no image is selected"
  150. width = int(image.width * scale_by)
  151. height = int(image.height * scale_by)
  152. assert 0. <= denoising_strength <= 1., 'can only work with strength in [0.0, 1.0]'
  153. p = StableDiffusionProcessingImg2Img(
  154. sd_model=shared.sd_model,
  155. outpath_samples=opts.outdir_samples or opts.outdir_img2img_samples,
  156. outpath_grids=opts.outdir_grids or opts.outdir_img2img_grids,
  157. prompt=prompt,
  158. negative_prompt=negative_prompt,
  159. styles=prompt_styles,
  160. batch_size=batch_size,
  161. n_iter=n_iter,
  162. cfg_scale=cfg_scale,
  163. width=width,
  164. height=height,
  165. init_images=[image],
  166. mask=mask,
  167. mask_blur=mask_blur,
  168. inpainting_fill=inpainting_fill,
  169. resize_mode=resize_mode,
  170. denoising_strength=denoising_strength,
  171. image_cfg_scale=image_cfg_scale,
  172. inpaint_full_res=inpaint_full_res,
  173. inpaint_full_res_padding=inpaint_full_res_padding,
  174. inpainting_mask_invert=inpainting_mask_invert,
  175. override_settings=override_settings,
  176. )
  177. p.scripts = modules.scripts.scripts_img2img
  178. p.script_args = args
  179. p.user = request.username
  180. if shared.opts.enable_console_prompts:
  181. print(f"\nimg2img: {prompt}", file=shared.progress_print_out)
  182. with closing(p):
  183. if is_batch:
  184. assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
  185. processed = process_batch(p, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, args, to_scale=selected_scale_tab == 1, scale_by=scale_by, use_png_info=img2img_batch_use_png_info, png_info_props=img2img_batch_png_info_props, png_info_dir=img2img_batch_png_info_dir)
  186. if processed is None:
  187. processed = Processed(p, [], p.seed, "")
  188. else:
  189. processed = modules.scripts.scripts_img2img.run(p, *args)
  190. if processed is None:
  191. processed = process_images(p)
  192. shared.total_tqdm.clear()
  193. generation_info_js = processed.js()
  194. if opts.samples_log_stdout:
  195. print(generation_info_js)
  196. if opts.do_not_show_images:
  197. processed.images = []
  198. return processed.images, generation_info_js, plaintext_to_html(processed.info), plaintext_to_html(processed.comments, classname="comments")