Files
HM-RunningHub-ComfyUI_RH_IC…/inference/inference.py
T

214 lines
7.2 KiB
Python

import argparse
import os
from datetime import datetime
from typing import Any, Optional
from omegaconf import OmegaConf
from PIL import Image
import torch
from ic_custom.pipelines.ic_custom_pipeline import ICCustomPipeline
def ensure_divisible_by_value(image_pil: Image.Image, value: int = 8, interpolate: Image.Resampling = Image.Resampling.LANCZOS) -> Image.Image:
"""
Ensure the image dimensions are divisible by value.
Args:
image_pil (Image.Image): The image to ensure divisible by value.
value (int): The value to ensure divisible by.
"""
w, h = image_pil.size
w = (w // value) * value
h = (h // value) * value
image_pil = image_pil.resize((w, h), interpolate)
return image_pil
def resize_paired_image(
reference_image: Image.Image,
target_image: Image.Image,
mask_target: Image.Image,
) -> tuple[Image.Image, Image.Image, Image.Image]:
ref_w, ref_h = reference_image.size
target_w, target_h = target_image.size
# resize the ref image to the same height as the target image and ensure the ratio remains the same
if ref_h != target_h:
scale_ratio = target_h / ref_h
reference_image = reference_image.resize((int(ref_w * scale_ratio), target_h), interpolate=Image.Resampling.LANCZOS)
# Ensure the image dimensions are divisible by 16.
reference_image = ensure_divisible_by_value(reference_image, value=16, interpolate=Image.Resampling.LANCZOS)
target_image = ensure_divisible_by_value(target_image, value=16, interpolate=Image.Resampling.LANCZOS)
mask_target = ensure_divisible_by_value(mask_target, value=16, interpolate=Image.Resampling.NEAREST)
return reference_image, target_image, mask_target
def prepare_input_images(
img_ref_path: str,
img_target_path: Optional[str] = None,
mask_target_path: Optional[str] = None,
) -> tuple[Image.Image, Image.Image, Image.Image]:
img_ref = Image.open(img_ref_path)
# Initialize img_target as a pure white image and mask_target as a pure black image, same size as reference
img_target = Image.new("RGB", img_ref.size, (255, 255, 255))
mask_target = Image.new("RGB", img_ref.size, (0, 0, 0))
if img_target_path is not None:
img_target = Image.open(img_target_path)
if mask_target_path is not None:
mask_target = Image.open(mask_target_path)
img_ref, img_target, mask_target = resize_paired_image(img_ref, img_target, mask_target)
return img_ref, img_target, mask_target
def get_mask_type_ids(mask_type: str) -> int:
if mask_type.lower() == "pos-free":
return 0
elif mask_type.lower() == "pos-aware-precise":
return 1
elif mask_type.lower() == "pos-aware-drawn":
return 2
else:
raise ValueError(f"Invalid mask type: {mask_type}")
def concat_image(
img_ref: Image.Image,
img_target: Image.Image,
output_img: Image.Image,
) -> Image.Image:
concat_img = Image.new("RGB", (img_ref.width + img_target.width + output_img.width, output_img.height))
concat_img.paste(img_ref, (0, 0))
concat_img.paste(img_target, (img_ref.width, 0))
concat_img.paste(output_img, (img_ref.width + img_target.width, 0))
return concat_img
def parse_args() -> Any:
parser = argparse.ArgumentParser(description="IC-Custom Inference.")
parser.add_argument(
"--config",
type=str,
required=True,
help="Path to YAML config file",
)
parser.add_argument(
"--hf_token",
type=str,
required=False,
help="Hugging Face token",
)
parser.add_argument(
"--hf_cache_dir",
type=str,
required=False,
default=os.path.expanduser("~/.cache/huggingface/hub"),
help="Cache directory to save the models, default is ~/.cache/huggingface/hub",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
cfg = OmegaConf.load(args.config)
if args.hf_token is not None:
os.environ["HF_TOKEN"] = args.hf_token
if args.hf_cache_dir is not None:
os.environ["HF_HUB_CACHE"] = args.hf_cache_dir
inference_config = cfg.inference_config
model_config = cfg.model_config
checkpoint_config = cfg.checkpoint_config
os.makedirs(inference_config.output_dir, exist_ok=True)
# import ipdb; ipdb.set_trace()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
weight_dtype = torch.bfloat16
pipeline = ICCustomPipeline(
clip_path=checkpoint_config.clip_path,
t5_path=checkpoint_config.t5_path,
siglip_path=checkpoint_config.siglip_path,
ae_path=checkpoint_config.ae_path,
dit_path=checkpoint_config.dit_path,
redux_path=checkpoint_config.redux_path,
lora_path=checkpoint_config.lora_path,
img_txt_in_path=checkpoint_config.img_txt_in_path,
boundary_embeddings_path=checkpoint_config.boundary_embeddings_path,
task_register_embeddings_path=checkpoint_config.task_register_embeddings_path,
network_alpha=model_config.network_alpha,
double_blocks_idx=model_config.double_blocks,
single_blocks_idx=model_config.single_blocks,
device=device,
weight_dtype=weight_dtype,
)
pipeline.set_pipeline_offload(inference_config.offload)
pipeline.set_show_progress(inference_config.show_progress)
img_ref, img_target, mask_target = prepare_input_images(
img_ref_path=inference_config.img_ref_path,
img_target_path=inference_config.img_target_path,
mask_target_path=inference_config.mask_target_path,
)
img_ip = img_ref.copy()
width, height = img_target.size[0] + img_ref.size[0], img_target.size[1]
cond_w_regions = [img_ref.size[0]]
mask_type_ids = get_mask_type_ids(inference_config.custom_mask_type)
with torch.no_grad():
output_img: Image.Image = pipeline(
prompt=inference_config.prompt,
width=width,
height=height,
guidance=inference_config.guidance,
num_steps=inference_config.num_steps,
seed=inference_config.seed,
img_ref=img_ref,
img_target=img_target,
mask_target=mask_target,
img_ip=img_ip,
cond_w_regions=cond_w_regions,
mask_type_ids=mask_type_ids,
use_background_preservation=inference_config.use_background_preservation,
use_progressive_background_preservation=inference_config.use_progressive_background_preservation,
background_blend_threshold=inference_config.background_blend_threshold,
true_gs=inference_config.true_gs,
neg_prompt=inference_config.neg_prompt,
)[0]
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
save_name = inference_config.img_ref_path.split("/")[-2]
output_dir = os.path.join(inference_config.output_dir, save_name)
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, f"{timestamp}_tgt.png")
output_img.save(output_path)
concat_img = concat_image(img_ref, img_target, output_img)
concat_img.save(os.path.join(output_dir, f"{timestamp}_concat.png"))
print("The output image is saved to: ", f"{output_dir}/{timestamp}_tgt.png")
if __name__ == "__main__":
main()