import os import numpy as np import torch from PIL import Image, ImageFilter, ImageEnhance, ImageCms, ImageOps, ImageDraw, ImageFont sRGB_profile = ImageCms.createProfile("sRGB") Lab_profile = ImageCms.createProfile("LAB") # Tensor to PIL def tensor2pil(image): return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)) # PIL to Tensor def pil2tensor(image): return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0) def adjust_shadows(luminance_array, shadow_intensity, hdr_intensity): # Darken shadows more as shadow_intensity increases, scaled by hdr_intensity return np.clip(luminance_array - luminance_array * shadow_intensity * hdr_intensity * 0.5, 0, 255) def adjust_highlights(luminance_array, highlight_intensity, hdr_intensity): # Brighten highlights more as highlight_intensity increases, scaled by hdr_intensity return np.clip(luminance_array + (255 - luminance_array) * highlight_intensity * hdr_intensity * 0.5, 0, 255) def apply_adjustment(base, factor, intensity_scale): """Apply positive adjustment scaled by intensity.""" # Ensure the adjustment increases values within [0, 1] range, scaling by intensity adjustment = base + (base * factor * intensity_scale) # Ensure adjustment stays within bounds return np.clip(adjustment, 0, 1) def multiply_blend(base, blend): """Multiply blend mode.""" return np.clip(base * blend, 0, 255) def overlay_blend(base, blend): """Overlay blend mode.""" # Normalize base and blend to [0, 1] for blending calculation base = base / 255.0 blend = blend / 255.0 return np.where(base < 0.5, 2 * base * blend, 1 - 2 * (1 - base) * (1 - blend)) * 255 def adjust_shadows_non_linear(luminance, shadow_intensity, max_shadow_adjustment=1.5): lum_array = np.array(luminance, dtype=np.float32) / 255.0 # Normalize # Apply a non-linear darkening effect based on shadow_intensity shadows = lum_array ** (1 / (1 + shadow_intensity * max_shadow_adjustment)) return np.clip(shadows * 255, 0, 255).astype(np.uint8) # Re-scale to [0, 255] def adjust_highlights_non_linear(luminance, highlight_intensity, max_highlight_adjustment=1.5): lum_array = np.array(luminance, dtype=np.float32) / 255.0 # Normalize # Brighten highlights more aggressively based on highlight_intensity highlights = 1 - (1 - lum_array) ** (1 + highlight_intensity * max_highlight_adjustment) return np.clip(highlights * 255, 0, 255).astype(np.uint8) # Re-scale to [0, 255] def merge_adjustments_with_blend_modes(luminance, shadows, highlights, hdr_intensity, shadow_intensity, highlight_intensity): # Ensure the data is in the correct format for processing base = np.array(luminance, dtype=np.float32) # Scale the adjustments based on hdr_intensity scaled_shadow_intensity = shadow_intensity ** 2 * hdr_intensity scaled_highlight_intensity = highlight_intensity ** 2 * hdr_intensity # Create luminance-based masks for shadows and highlights shadow_mask = np.clip((1 - (base / 255)) ** 2, 0, 1) highlight_mask = np.clip((base / 255) ** 2, 0, 1) # Apply the adjustments using the masks adjusted_shadows = np.clip(base * (1 - shadow_mask * scaled_shadow_intensity), 0, 255) adjusted_highlights = np.clip(base + (255 - base) * highlight_mask * scaled_highlight_intensity, 0, 255) # Combine the adjusted shadows and highlights adjusted_luminance = np.clip(adjusted_shadows + adjusted_highlights - base, 0, 255) # Blend the adjusted luminance with the original luminance based on hdr_intensity final_luminance = np.clip(base * (1 - hdr_intensity) + adjusted_luminance * hdr_intensity, 0, 255).astype(np.uint8) return Image.fromarray(final_luminance) def apply_gamma_correction(lum_array, gamma): """ Apply gamma correction to the luminance array. :param lum_array: Luminance channel as a NumPy array. :param gamma: Gamma value for correction. """ if gamma == 0: return np.clip(lum_array, 0, 255).astype(np.uint8) epsilon = 1e-7 # Small value to avoid dividing by zero gamma_corrected = 1 / (1.1 - gamma) adjusted = 255 * ((lum_array / 255) ** gamma_corrected) return np.clip(adjusted, 0, 255).astype(np.uint8) # create a wrapper function that can apply a function to multiple images in a batch while passing all other arguments to the function def apply_to_batch(func): def wrapper(self, image, *args, **kwargs): images = [] for img in image: images.append(func(self, img, *args, **kwargs)) batch_tensor = torch.cat(images, dim=0) return (batch_tensor,) return wrapper # 领域降噪 def calculate_noise_count(img_obj, w, h, width, height): count = 0 for _w_ in [w - 1, w, w + 1]: for _h_ in [h - 1, h, h + 1]: if _w_ > width - 1: continue if _h_ > height - 1: continue if _w_ == w and _h_ == h: continue if img_obj[_w_, _h_] < 230: # 这里因为是灰度图像,设置小于230为非白色 count += 1 return count # 领域降噪 def row_noise(pim, height, weight, w): for h in range(height): if calculate_noise_count(pim, w, h, weight, height) < 4: pim[w, h] = 255 def mexx_image_filter(img, image_filter, write_text = '画画的Baby', font_name = 'YangRenDongZhuShiTi-Light-2.ttf', padding_height = 120, font_size = 80): if image_filter == "线稿-LINE0": # 转换为灰度图 gray_image = img.convert("L") array = np.array(gray_image).astype(np.float32) # 根据灰度变化来模拟人类视觉的明暗程度 depth = 10 # 预设虚拟深度值为10 范围为0-100 # 提取x y方向梯度值 解构赋给grad_x, grad_y grad_x, grad_y = np.gradient(array) # 利用像素之间的梯度值和虚拟深度值对图像进行重构 grad_x = grad_x * depth / 100 grad_y = grad_y * depth / 100 # 梯度归一化 定义z深度为1. 将三个梯度绝对值转化为相对值,在三维中是相对于斜对角线A的值 dis = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.0) uni_x = grad_x / dis uni_y = grad_y / dis uni_z = 1.0 / dis # 光源俯视角度和光源方位角度 vec_el = np.pi / 2.2 vec_az = np.pi / 4 # 光源对x、y、z轴的影响 dx = np.cos(vec_el) * np.cos(vec_az) dy = np.cos(vec_el) * np.sin(vec_az) dz = np.sin(vec_el) # 光源归一化 out = 255 * (uni_x * dx + uni_y * dy + uni_z * dz) out = out.clip(0, 255) img = Image.fromarray(out.astype(np.uint8)) return img.convert("RGB") if image_filter == "线稿-LINE1": gray_image = img.convert("L") im = gray_image.filter(ImageFilter.GaussianBlur(radius=0.75)) # 高斯模糊 75% a = np.asarray(im).astype(np.float32) depth = 10. # 设定虚拟深度 grad = np.gradient(a) grad_x, grad_y = grad grad_x = grad_x * depth / 100. grad_y = grad_y * depth / 100. # 梯度向量计算 A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.) uni_x = grad_x / A uni_y = grad_y / A uni_z = 1. / A vec_el = np.pi / 2.2 vec_az = np.pi / 4. dx = np.cos(vec_el) * np.cos(vec_az) dy = np.cos(vec_el) * np.sin(vec_az) dz = np.sin(vec_el) b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z) b = b.clip(0, 255) # 二值化处理,要么为0,(黑色边缘)要么为255(白色背景) im2 = Image.fromarray(b.astype(np.uint8)) im2 = im2.filter(ImageFilter.SHARPEN) weight, height = im2.size # 降噪 pim = im2.load() map(row_noise, [(pim, height, weight, w,) for w in range(weight)]) # 填充新图像的像素数据 for i in range(im2.size[0]): for j in range(im2.size[1]): im2.putpixel((i, j), pim[i, j]) return im2.convert("RGB") if image_filter == "线稿-LINE2": # 转换为灰度图 gray_image = img.convert("L") # 应用高斯模糊(可选,根据需要决定是否使用) blurred_image = gray_image.filter(ImageFilter.GaussianBlur(0.75)) # 应用边缘检测 edge_image = blurred_image.filter(ImageFilter.FIND_EDGES) # 锐化边缘 edge_enhance_image2 = edge_image.filter(ImageFilter.EDGE_ENHANCE) inverted_image = ImageOps.invert(edge_enhance_image2) return inverted_image.convert("RGB") if image_filter == "线稿-LINE3": # 转换为灰度图 gray_image = img.convert("L") # 应用高斯模糊(可选,根据需要决定是否使用) blurred_image = gray_image.filter(ImageFilter.GaussianBlur(0.75)) # 应用边缘检测 edge_image = blurred_image.filter(ImageFilter.CONTOUR) # 锐化边缘 sharpen_image2 = edge_image.filter(ImageFilter.SHARPEN) return sharpen_image2.convert("RGB") if image_filter == "线稿-LINE3.1": # 转换为灰度图 gray_image = img.convert("L") # 应用高斯模糊(可选,根据需要决定是否使用) blurred_image = gray_image.filter(ImageFilter.GaussianBlur(0.75)) # 应用边缘检测 edge_image = blurred_image.filter(ImageFilter.CONTOUR) # 创建边缘图像,例如使用边缘检测滤镜 # 定义一个锐化的卷积核 kernel = (-1, -1, -1, -1, 9, -1, -1, -1, -1) # 创建自定义滤镜 custom_filter = ImageFilter.Kernel((3, 3), kernel) return edge_image.filter(custom_filter).convert("RGB") if image_filter == "线稿-LINE3.2": # 转换为灰度图 gray_image = img.convert("L") # 应用高斯模糊(可选,根据需要决定是否使用) blurred_image = gray_image.filter(ImageFilter.GaussianBlur(0.75)) # 应用边缘检测 edge_image = blurred_image.filter(ImageFilter.FIND_EDGES) # 创建边缘图像,例如使用边缘检测滤镜 blurred_image2 = edge_image.filter(ImageFilter.SMOOTH_MORE) inverted_image = ImageOps.invert(blurred_image2) return inverted_image.filter(ImageFilter.EDGE_ENHANCE).convert("RGB") if image_filter == "线稿-LINE4": # 转换为灰度图 gray_image = img.convert("L") # 应用边缘检测 edge_image = gray_image.filter(ImageFilter.CONTOUR) # 锐化边缘 edge_enhance_image2 = edge_image.filter(ImageFilter.EDGE_ENHANCE) return edge_enhance_image2.convert("RGB") if image_filter == "线稿-LINE5": # 转换为灰度图 gray_image = img.convert("L") # 应用边缘检测 edge_image = gray_image.filter(ImageFilter.CONTOUR) # 对比度 contrast_enhancer = ImageEnhance.Sharpness(edge_image) enhanced_image = contrast_enhancer.enhance(1.2) return enhanced_image.convert("RGB") elif image_filter == "边缘检测-FIND_EDGES": return img.filter(ImageFilter.FIND_EDGES) elif image_filter == "轮廓-CONTOUR": return img.filter(ImageFilter.CONTOUR) elif image_filter == "灰度-L": gray_image = img.convert("L") return gray_image.convert("RGB") elif image_filter == "锐化-SHARPEN": return img.filter(ImageFilter.SHARPEN) elif image_filter == "锐化-UNSHARP_MASK": return img.filter(ImageFilter.UnsharpMask(2)) elif image_filter == "边缘增强-EDGE_ENHANCE": return img.filter(ImageFilter.EDGE_ENHANCE) elif image_filter == "边缘增强-EDGE_ENHANCE_MORE": return img.filter(ImageFilter.EDGE_ENHANCE_MORE) elif image_filter == "浮雕-EMBOSS": return img.filter(ImageFilter.EMBOSS) elif image_filter == "平滑-SMOOTH": return img.filter(ImageFilter.SMOOTH) elif image_filter == "平滑-SMOOTH_MORE": return img.filter(ImageFilter.SMOOTH_MORE) elif image_filter == "细节-DETAIL": return img.filter(ImageFilter.DETAIL) elif image_filter == "模糊-BLUR": return img.filter(ImageFilter.BLUR) elif image_filter == "模糊-BOX_BLUR": return img.filter(ImageFilter.BoxBlur(2)) elif image_filter == "模糊-GAUSSIAN_BLUR": return img.filter(ImageFilter.GaussianBlur(0.75)) elif image_filter == "反相-INVERT": return ImageOps.invert(img) elif image_filter == "去燥-中值滤波器": return img.filter(ImageFilter.MedianFilter(size=3)) elif image_filter == "翻转_FLIP_LEFT_RIGHT": return img.transpose(Image.FLIP_LEFT_RIGHT) elif image_filter == "翻转_FLIP_TOP_BOTTOM": return img.transpose(Image.FLIP_TOP_BOTTOM) elif image_filter == "旋转_ROTATE_45": return img.rotate(45) elif image_filter == "旋转_ROTATE_90": return img.rotate(90) elif image_filter == "旋转_ROTATE_180": return img.rotate(180) elif image_filter == "旋转_ROTATE_270": return img.rotate(270) elif image_filter == "对比度_0.8": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(0.8) return enhanced_image elif image_filter == "对比度_1.2": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(1.2) return enhanced_image elif image_filter == "对比度_1.5": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(1.5) return enhanced_image elif image_filter == "对比度_2.0": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(2.0) return enhanced_image elif image_filter == "对比度_3.0": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(3.0) return enhanced_image elif image_filter == "对比度_5.0": contrast_enhancer = ImageEnhance.Contrast(img) enhanced_image = contrast_enhancer.enhance(5.0) return enhanced_image elif image_filter == "色彩_0.5": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(0.5) return enhanced_image elif image_filter == "色彩_0.8": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(0.8) return enhanced_image elif image_filter == "色彩_0.9": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(0.9) return enhanced_image elif image_filter == "色彩_1.1": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(1.1) return enhanced_image elif image_filter == "色彩_1.2": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(1.2) return enhanced_image elif image_filter == "色彩_1.5": contrast_enhancer = ImageEnhance.Color(img) enhanced_image = contrast_enhancer.enhance(1.5) return enhanced_image elif image_filter == "框": border_size = 20 # 获取原始图片的尺寸 img_width, img_height = img.size # 计算相框的尺寸(原始图片的尺寸加上边框的厚度) frame_width = img_width + 2 * border_size frame_height = img_height + 2 * border_size # 创建一个新的图像对象作为相框 frame = Image.new('RGB', (frame_width, frame_height), 'white') # 相框背景为白色 draw = ImageDraw.Draw(frame) # 创建绘图对象 # 将原始图片粘贴到相框中(居中) x = border_size y = border_size frame.paste(img, (x, y)) return frame.convert("RGB") elif image_filter == "留白": text = write_text text_color = "black" # 获取原始图片的尺寸 img_width, img_height = img.size # 创建一个新的图像对象,宽度和高度分别为原始图片宽度和原始高度加上留白高度 new_height = img_height + padding_height new_img = Image.new('RGB', (img_width, new_height), 'white') # 新图像背景为白色 # 将原始图片粘贴到新图像上(留白在上方) new_img.paste(img, (0, padding_height)) # 准备绘制文字 draw = ImageDraw.Draw(new_img) current_directory = os.path.dirname(os.path.realpath(__file__)) font_file = current_directory + "/font/" + font_name font = ImageFont.truetype(font_file, font_size) # 计算文字的位置(位于留白区域的中间) bbox = draw.textbbox((0, 0), text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] text_x = (img_width - text_width) / 2 text_y = (padding_height - text_height) / 2 # 在留白区域写上文字 draw.text((text_x, text_y), text, fill=text_color, font=font) return new_img.convert("RGB") return img class PilEffects: @classmethod def INPUT_TYPES(self): list = ["NO", "线稿-LINE0", "线稿-LINE1", "线稿-LINE2", "线稿-LINE3", "线稿-LINE3.1", "线稿-LINE3.2", "线稿-LINE4", "线稿-LINE5", "边缘检测-FIND_EDGES", "轮廓-CONTOUR", "灰度-L", "细节-DETAIL", "平滑-SMOOTH", "平滑-SMOOTH_MORE", "锐化-SHARPEN", "锐化-UNSHARP_MASK", "边缘增强-EDGE_ENHANCE", "边缘增强-EDGE_ENHANCE_MORE", "模糊-BLUR", "模糊-BOX_BLUR", "模糊-GAUSSIAN_BLUR", "反相-INVERT", "去燥-中值滤波器", "浮雕-EMBOSS", "翻转_FLIP_LEFT_RIGHT", "翻转_FLIP_TOP_BOTTOM", "旋转_ROTATE_45", "旋转_ROTATE_90", "旋转_ROTATE_180", "旋转_ROTATE_270", "对比度_0.8", "对比度_1.2", "对比度_1.5", "对比度_2.0", "对比度_3.0", "对比度_5.0", "色彩_0.5", "色彩_0.8","色彩_0.9","色彩_1.1", "色彩_1.2", "色彩_1.5", "框" ] return {'required': {'image': ('IMAGE', {'default': None}), "image_filter": (list, {"default": "NO"}) }} RETURN_TYPES = ('IMAGE',) RETURN_NAMES = ('result_img',) FUNCTION = 'apply_pil1' CATEGORY = 'ComfyUI_Mexx' @apply_to_batch def apply_pil1(self, image, image_filter="NO", write_text="画画的Baby"): # Load the image img = tensor2pil(image) result_img = mexx_image_filter(img, image_filter, write_text) return pil2tensor(result_img) class PilTitle: @classmethod def INPUT_TYPES(self): list = ["NO", "留白" ] font_names = ["YangRenDongZhuShiTi-Light-2.ttf", "JinNianYeYaoJiaYouYa-2.ttf", "CEFFontsCJKMono-Regular.ttf", "庞门正道粗书体6.0.ttf", "白路飞云手写体.ttf" ] return {'required': {'image': ('IMAGE', {'default': None}), "image_filter": (list, {"default": "留白"}), "padding_height": ("INT", {"default": 100}), "font_size": ("INT", {"default": 60}), "font_name": (font_names, {"default": "YangRenDongZhuShiTi-Light-2.ttf"}), "write_text": ("STRING", {"default": "画画的Baby", "multiline": True}), }} RETURN_TYPES = ('IMAGE',) RETURN_NAMES = ('result_img',) FUNCTION = 'apply_pil2' CATEGORY = 'ComfyUI_Mexx' @apply_to_batch def apply_pil2(self, image, image_filter="NO", write_text="画画的Baby", font_name = 'YangRenDongZhuShiTi-Light-2.ttf', padding_height = 120, font_size = 80): # Load the image img = tensor2pil(image) result_img = mexx_image_filter(img, image_filter, write_text, font_name, padding_height, font_size) return pil2tensor(result_img) class PilMergeImage: @classmethod def INPUT_TYPES(self): merge_type_list = ["上下", "左右", "平行四边形"] return {'required': {'merge_type': (merge_type_list, {"default": "左右"}), 'image': ('IMAGE', {'default': None}), 'image2': ('IMAGE', {'default': None}), }, 'optional': { 'image3': ('IMAGE', {'default': None}), 'image4': ('IMAGE', {'default': None}), 'image5': ('IMAGE', {'default': None}), 'image6': ('IMAGE', {'default': None}), }} RETURN_TYPES = ('IMAGE',) RETURN_NAMES = ('result_img',) FUNCTION = 'apply_pil3' CATEGORY = 'ComfyUI_Mexx' @apply_to_batch def apply_pil3(self, image, image2, image3 = None, image4 = None, image5 = None, image6 = None, merge_type="左右"): print(f"PIL Merge Image Start") images = [] # Load the image img1 = tensor2pil(image) images.append(img1) print(f"Image1: {img1.size}") img2 = tensor2pil(image2) images.append(img2) print(f"Image2: {img2.size}") if image3 is not None: img3 = tensor2pil(image3) images.append(img3) print(f"Image3: {img3.size}") if image4 is not None: img4 = tensor2pil(image4) images.append(img4) print(f"Image4: {img4.size}") if image5 is not None: img5 = tensor2pil(image5) images.append(img5) print(f"Image5: {img5.size}") if image6 is not None: img6 = tensor2pil(image6) images.append(img6) print(f"Image6: {img6.size}") # 确保所有图片尺寸相同 for img in images: if img.size != images[0].size: raise ValueError("All images must be the same size") # 获取图片的宽度和高度 width, height = images[0].size print(f"PIL Merge Image: {width}, {height}") if merge_type == "左右": # 计算每张图片的宽度部分 part_width = width // len(images) print(f"PIL Merge part_width: {part_width}") # 创建一个新的图片,用于合成 combined_image = Image.new('RGB', (width, height)) # 依次将每张图片的相应部分粘贴到合成图片上 for i, image in enumerate(images): part = image.crop((i * part_width, 0, (i + 1) * part_width, height)) combined_image.paste(part, (i * part_width, 0)) print(f"PIL Merge i = {i}") print(f"result_img: {combined_image.size}") return pil2tensor(combined_image) if merge_type == "上下": # 计算每张图片的宽度部分 part_height = height // len(images) # 创建一个新的图片,用于合成 combined_image = Image.new('RGB', (width, height)) # 依次将每张图片的相应部分粘贴到合成图片上 for i, image in enumerate(images): part = image.crop((0, i * part_height, width, (i + 1) * part_height)) combined_image.paste(part, (0, i * part_height)) print(f"PIL Merge i = {i}") print(f"result_img: {combined_image.size}") return pil2tensor(combined_image) if merge_type == "平行四边形": # 定义平行四边形的四个顶点坐标(相对于图片左上角) # 例如,这里定义了一个从左上角开始的平行四边形 points = [ (0, 0), (img1.width // 2, 0), (img1.width, img1.height), (img1.width // 2, img1.height) ] # 创建一个和图片同样大小的透明遮罩 mask = Image.new('L', img1.size, 0) draw = ImageDraw.Draw(mask) # 绘制平行四边形遮罩 draw.polygon(points, fill=255) # 将图2的平行四边形区域应用遮罩 img2 = img2.copy() img2.putalpha(mask) # 将图1和图2合成 combined_image = Image.composite(img2, img1, mask) return pil2tensor(combined_image) raise ValueError("Merge Type Error") class PilRemoveBlackDots: @classmethod def INPUT_TYPES(self): return {'required': {'image': ('IMAGE', {'default': None}), 'threshold': ('INT', {'default': 128}), 'dot_size': ('INT', {'default': 2}), }} RETURN_TYPES = ('IMAGE',) RETURN_NAMES = ('result_img',) FUNCTION = 'apply_pil4' CATEGORY = 'ComfyUI_Mexx' @apply_to_batch def apply_pil4(self, image, threshold, dot_size): img = tensor2pil(image) # 加载像素数据 pixels = img.load() width, height = img.size # 遍历图像中的每个像素 for x in range(width): for y in range(height): r, g, b = pixels[x, y] # 计算灰色程度,如果接近灰色,则将其转换为白色 if r > threshold and g > threshold and b > threshold: pixels[x, y] = (255, 255, 255) # 将图像转换为灰度模式 img = img.convert('L') # 加载像素数据 pixels = img.load() # 遍历图像中的每个像素 for x in range(width): for y in range(height): # 如果像素值低于某个阈值,则认为是黑点 if pixels[x, y] < threshold: # 检查周围的像素,如果黑点很小,则去除 if all(pixels[max(x-i, 0), max(y-j, 0)] > 128 for i in range(dot_size) for j in range(dot_size)): pixels[x, y] = 255 # 遍历图像中的每个像素 for x in range(width): for y in range(height): # 如果像素值低于某个阈值,则认为是黑点 if pixels[x, y] < threshold: # 检查周围的像素,如果黑点很小,则去除 if all(pixels[max(x-i, 0), max(y-j, 0)] > 128 for i in range(dot_size) for j in range(dot_size)): pixels[x, y] = 255 # 遍历图像中的每个像素 for x in range(width): for y in range(height): # 如果像素值低于某个阈值,则认为是黑点 if pixels[x, y] < threshold: # 检查周围的像素,如果黑点很小,则去除 if all(pixels[max(x-i, 0), max(y-j, 0)] > 128 for i in range(dot_size) for j in range(dot_size)): pixels[x, y] = 255 return pil2tensor(img.convert('RGB')) def adjust_brightness(image, brightness_factor): enhancer = ImageEnhance.Brightness(image) adjusted_image = enhancer.enhance(brightness_factor) return adjusted_image def calculate_brightness_factor(target_brightness, current_brightness): return target_brightness / current_brightness def get_average_brightness(image): grayscale_image = image.convert("L") histogram = grayscale_image.histogram() pixels = sum(histogram) brightness = scale = len(histogram) total_brightness = sum(i * w for i, w in enumerate(histogram)) return total_brightness / pixels def apply_dithering(image): return image.convert("P", palette=Image.ADAPTIVE, colors=256).convert("RGB") def apply_noise_reduction(image, strength): return image.filter(ImageFilter.GaussianBlur(radius=strength)) def apply_gradient_smoothing(image, strength): return image.filter(ImageFilter.SMOOTH_MORE if strength > 1 else ImageFilter.SMOOTH) def blend_images(image1, image2, alpha): return Image.blend(image1, image2, alpha) def temporal_smoothing(frames, window_size): num_frames = len(frames) smoothed_frames = [] for i in range(num_frames): start = max(0, i - window_size // 2) end = min(num_frames, i + window_size // 2 + 1) window_frames = frames[start:end] smoothed_frame = np.mean(window_frames, axis=0) smoothed_frames.append(smoothed_frame) return smoothed_frames def resize_and_crop(pil_img, target_width, target_height): """Resize and crop an image to fit exactly the specified dimensions.""" original_width, original_height = pil_img.size aspect_ratio = original_width / original_height target_aspect_ratio = target_width / target_height if target_aspect_ratio > aspect_ratio: # Target is wider than the image scale_factor = target_width / original_width scaled_height = int(original_height * scale_factor) scaled_width = target_width else: # Target is taller than the image scale_factor = target_height / original_height scaled_height = target_height scaled_width = int(original_width * scale_factor) # Resize the image resized_img = pil_img.resize((scaled_width, scaled_height), Image.BILINEAR) # Crop the image if scaled_width != target_width or scaled_height != target_height: left = (scaled_width - target_width) // 2 top = (scaled_height - target_height) // 2 right = left + target_width bottom = top + target_height cropped_img = resized_img.crop((left, top, right, bottom)) else: cropped_img = resized_img return cropped_img NODE_CLASS_MAPPINGS = { 'PIL Effects (Mexx)': PilEffects, 'PIL TITLE (Mexx)': PilTitle, 'PIL Merge Image (Mexx)': PilMergeImage, 'PIL Remove Black Dots (Mexx)': PilRemoveBlackDots } NODE_DISPLAY_NAME_MAPPINGS = { 'PIL_Effects': 'PIL Effects (Mexx)', 'PIL_TITLE': 'PIL TITLE (Mexx)', 'PIL_MergeImage': 'PIL Merge Image (Mexx)', 'PIL_RemoveBlackDots': 'PIL Remove Black Dots (Mexx)' }