# !/usr/bin/env python # -*- coding: UTF-8 -*- import os import torch from PIL import Image import numpy as np import cv2 import gc import torch from comfy.utils import common_upscale,ProgressBar from huggingface_hub import hf_hub_download import comfy.model_management cur_path = os.path.dirname(os.path.abspath(__file__)) device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" def cf_unload(): comfy.model_management.unload_all_models() comfy.model_management.soft_empty_cache() def cf_prompt_clip(cf_clip,prompt): tokens = cf_clip.tokenize(prompt) tokens["t5xxl"] = cf_clip.tokenize(prompt)["t5xxl"] prompt_embeds = cf_clip.encode_from_tokens(tokens, return_pooled=True, return_dict=True).pop("cond") tokens["l"] = cf_clip.tokenize(prompt)["l"] pooled_prompt_embeds = cf_clip.encode_from_tokens(tokens, return_dict=True).pop("pooled_output") prompt_embeds=prompt_embeds.to(device,torch.bfloat16) pooled_prompt_embeds=pooled_prompt_embeds.to(device,torch.bfloat16) text_ids = torch.zeros(prompt_embeds.shape[1], 3).to(device=device, dtype=torch.bfloat16) return prompt_embeds,pooled_prompt_embeds,text_ids def latent_crop( samples, width, height, x, y): s = samples.copy() samples = samples['samples'] x = x // 8 y = y // 8 #enfonce minimum size of 64 if x > (samples.shape[3] - 8): x = samples.shape[3] - 8 if y > (samples.shape[2] - 8): y = samples.shape[2] - 8 new_height = height // 8 new_width = width // 8 to_x = new_width + x to_y = new_height + y s['samples'] = samples[:,:,y:to_y, x:to_x] return s def cleanup(): gc.collect() torch.cuda.empty_cache() def process_image_with_mask(image, mask,width, height,invert=False): if invert: mask = 1.0 - mask mask_tensor=mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])).movedim(1, -1).expand(-1, -1, -1, 3) input_image_resized = tensor2pil_upscale(image, width, height) mask_pil=tensor2pil_upscale(mask_tensor, width, height) return input_image_resized,mask_pil def cv2pil(cv_image): """ 将OpenCV图像转换为PIL图像 :param cv_image: OpenCV图像 :return: PIL图像 """ # 将图像从BGR转换为RGB rgb_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB) # 使用PIL的Image.fromarray方法将NumPy数组转换为PIL图像 pil_image = Image.fromarray(rgb_image) return pil_image def tensor_to_pil(tensor): image_np = tensor.squeeze().mul(255).clamp(0, 255).byte().numpy() image = Image.fromarray(image_np, mode='RGB') return image def tensor2pil_list(image,width,height): B,_,_,_=image.size() if B==1: ref_image_list=[tensor2pil_upscale(image,width,height)] else: img_list = list(torch.chunk(image, chunks=B)) ref_image_list = [tensor2pil_upscale(img,width,height) for img in img_list] return ref_image_list def tensor_upscale(img_tensor, width, height): samples = img_tensor.movedim(-1, 1) img = common_upscale(samples, width, height, "nearest-exact", "center") samples = img.movedim(1, -1) return samples def tensor2pil_upscale(img_tensor, width, height): samples = img_tensor.movedim(-1, 1) img = common_upscale(samples, width, height, "nearest-exact", "center") samples = img.movedim(1, -1) img_pil = tensor_to_pil(samples) return img_pil def tensor2np_upscale(img_tensor, width, height): samples = img_tensor.movedim(-1, 1) img = common_upscale(samples, width, height, "nearest-exact", "center") samples = img.movedim(1, -1) image_np = samples.squeeze().mul(255).clamp(0, 255).byte().numpy() return image_np def tensor2cv(tensor_image,RGB2BGR=True): if len(tensor_image.shape)==4:#bhwc to hwc tensor_image=tensor_image.squeeze(0) if tensor_image.is_cuda: tensor_image = tensor_image.cpu().detach() tensor_image=tensor_image.numpy() #反归一化 maxValue=tensor_image.max() tensor_image=tensor_image*255/maxValue img_cv2=np.uint8(tensor_image)#32 to uint8 if RGB2BGR: img_cv2=cv2.cvtColor(img_cv2,cv2.COLOR_RGB2BGR) return img_cv2 def cvargb2tensor(img): assert type(img) == np.ndarray, 'the img type is {}, but ndarry expected'.format(type(img)) img = torch.from_numpy(img.transpose((2, 0, 1))) return img.float().div(255).unsqueeze(0) # 255也可以改为256 def cv2tensor(img): assert type(img) == np.ndarray, 'the img type is {}, but ndarry expected'.format(type(img)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = torch.from_numpy(img.transpose((2, 0, 1))) return img.float().div(255).unsqueeze(0) # 255也可以改为256 def images_generator(img_list: list,): #get img size sizes = {} for image_ in img_list: if isinstance(image_,Image.Image): count = sizes.get(image_.size, 0) sizes[image_.size] = count + 1 elif isinstance(image_,np.ndarray): count = sizes.get(image_.shape[:2][::-1], 0) sizes[image_.shape[:2][::-1]] = count + 1 else: raise "unsupport image list,must be pil or cv2!!!" size = max(sizes.items(), key=lambda x: x[1])[0] yield size[0], size[1] # any to tensor def load_image(img_in): if isinstance(img_in, Image.Image): img_in=img_in.convert("RGB") i = np.array(img_in, dtype=np.float32) i = torch.from_numpy(i).div_(255) if i.shape[0] != size[1] or i.shape[1] != size[0]: i = torch.from_numpy(i).movedim(-1, 0).unsqueeze(0) i = common_upscale(i, size[0], size[1], "lanczos", "center") i = i.squeeze(0).movedim(0, -1).numpy() return i elif isinstance(img_in,np.ndarray): i=cv2.cvtColor(img_in,cv2.COLOR_BGR2RGB).astype(np.float32) i = torch.from_numpy(i).div_(255) #print(i.shape) return i else: raise "unsupport image list,must be pil,cv2 or tensor!!!" total_images = len(img_list) processed_images = 0 pbar = ProgressBar(total_images) images = map(load_image, img_list) try: prev_image = next(images) while True: next_image = next(images) yield prev_image processed_images += 1 pbar.update_absolute(processed_images, total_images) prev_image = next_image except StopIteration: pass if prev_image is not None: yield prev_image def load_images(img_list: list,): gen = images_generator(img_list) (width, height) = next(gen) images = torch.from_numpy(np.fromiter(gen, np.dtype((np.float32, (height, width, 3))))) if len(images) == 0: raise FileNotFoundError(f"No images could be loaded .") return images def tensor2pil(tensor): image_np = tensor.squeeze().mul(255).clamp(0, 255).byte().numpy() image = Image.fromarray(image_np, mode='RGB') return image def pil2narry(img): narry = torch.from_numpy(np.array(img).astype(np.float32) / 255.0).unsqueeze(0) return narry def equalize_lists(list1, list2): """ 比较两个列表的长度,如果不一致,则将较短的列表复制以匹配较长列表的长度。 参数: list1 (list): 第一个列表 list2 (list): 第二个列表 返回: tuple: 包含两个长度相等的列表的元组 """ len1 = len(list1) len2 = len(list2) if len1 == len2: pass elif len1 < len2: print("list1 is shorter than list2, copying list1 to match list2's length.") list1.extend(list1 * ((len2 // len1) + 1)) # 复制list1以匹配list2的长度 list1 = list1[:len2] # 确保长度一致 else: print("list2 is shorter than list1, copying list2 to match list1's length.") list2.extend(list2 * ((len1 // len2) + 1)) # 复制list2以匹配list1的长度 list2 = list2[:len1] # 确保长度一致 return list1, list2 def file_exists(directory, filename): # 构建文件的完整路径 file_path = os.path.join(directory, filename) # 检查文件是否存在 return os.path.isfile(file_path) def download_weights(file_dir,repo_id,subfolder="",pt_name=""): if subfolder: file_path = os.path.join(file_dir,subfolder, pt_name) sub_dir=os.path.join(file_dir,subfolder) if not os.path.exists(sub_dir): os.makedirs(sub_dir) if not os.path.exists(file_path): file_path = hf_hub_download( repo_id=repo_id, subfolder=subfolder, filename=pt_name, local_dir = file_dir, ) return file_path else: file_path = os.path.join(file_dir, pt_name) if not os.path.exists(file_dir): os.makedirs(file_dir) if not os.path.exists(file_path): file_path = hf_hub_download( repo_id=repo_id, filename=pt_name, local_dir=file_dir, ) return file_path