import numpy as np import torch def channels_layer(images, channels, function): if channels == "rgb": img = images[:, :, :, :3] elif channels == "rgba": img = images[:, :, :, :4] elif channels == "rg": img = images[:, :, :, [0, 1]] elif channels == "rb": img = images[:, :, :, [0, 2]] elif channels == "ra": img = images[:, :, :, [0, 3]] elif channels == "gb": img = images[:, :, :, [1, 2]] elif channels == "ga": img = images[:, :, :, [1, 3]] elif channels == "ba": img = images[:, :, :, [2, 3]] elif channels == "r": img = images[:, :, :, 0] elif channels == "g": img = images[:, :, :, 1] elif channels == "b": img = images[:, :, :, 2] elif channels == "a": img = images[:, :, :, 3] else: raise ValueError("Unsupported channels") result = torch.from_numpy(function(img.numpy())) if channels == "rgb": images[:, :, :, :3] = result elif channels == "rgba": images[:, :, :, :4] = result elif channels == "rg": images[:, :, :, [0, 1]] = result elif channels == "rb": images[:, :, :, [0, 2]] = result elif channels == "ra": images[:, :, :, [0, 3]] = result elif channels == "gb": images[:, :, :, [1, 2]] = result elif channels == "ga": images[:, :, :, [1, 3]] = result elif channels == "ba": images[:, :, :, [2, 3]] = result elif channels == "r": images[:, :, :, 0] = result elif channels == "g": images[:, :, :, 1] = result elif channels == "b": images[:, :, :, 2] = result elif channels == "a": images[:, :, :, 3] = result return images class ImageNoiseBeta: def __init__(self): pass @classmethod def INPUT_TYPES(cls): return { "required": { "images": ("IMAGE",), "a": ("INT", { "default": 1, "min": 1, }), "b": ("INT", { "default": 1, "min": 1, }), "monochromatic": (["false", "true"],), "invert": (["false", "true"],), "channels": (["rgb", "rgba", "rg", "rb", "ra", "gb", "ga", "ba", "r", "g", "b", "a"],), }, } RETURN_TYPES = ("IMAGE",) FUNCTION = "node" CATEGORY = "image/noise" def noise(self, images, a, b, monochromatic, invert): if monochromatic and images.shape[3] > 1: noise = np.random.beta(a, b, images.shape[:3]) else: noise = np.random.beta(a, b, images.shape) if monochromatic and images.shape[3] > 1: noise = noise[..., np.newaxis].repeat(images.shape[3], -1) if invert: noise = images - noise else: noise = images + noise noise = noise.astype(images.dtype) return noise def node(self, images, a, b, monochromatic, invert, channels): tensor = images.clone().detach() monochromatic = True if monochromatic == "true" else False invert = True if invert == "true" else False return (channels_layer(tensor, channels, lambda x: self.noise( x, a, b, monochromatic, invert )),) class ImageNoiseBinomial: def __init__(self): pass @classmethod def INPUT_TYPES(cls): return { "required": { "images": ("IMAGE",), "n": ("INT", { "default": 128, "min": 1, "max": 255, }), "p": ("FLOAT", { "default": 0.5, "max": 1.0, "step": 0.01 }), "monochromatic": (["false", "true"],), "invert": (["false", "true"],), "channels": (["rgb", "rgba", "rg", "rb", "ra", "gb", "ga", "ba", "r", "g", "b", "a"],), }, } RETURN_TYPES = ("IMAGE",) FUNCTION = "node" CATEGORY = "image/noise" def noise(self, images, n, p, monochromatic, invert): if monochromatic and images.shape[3] > 1: noise = np.random.binomial(n, p, images.shape[:3]) else: noise = np.random.binomial(n, p, images.shape) noise = noise.astype(images.dtype) noise /= 255 if monochromatic and images.shape[3] > 1: noise = noise[..., np.newaxis].repeat(images.shape[3], -1) if invert: noise = images - noise else: noise = images + noise noise = np.clip(noise, 0.0, 1.0) return noise def node(self, images, n, p, monochromatic, invert, channels): tensor = images.clone().detach() monochromatic = True if monochromatic == "true" else False invert = True if invert == "true" else False return (channels_layer(tensor, channels, lambda x: self.noise( x, n, p, monochromatic, invert )),) class ImageNoiseBytes: def __init__(self): pass @classmethod def INPUT_TYPES(cls): return { "required": { "images": ("IMAGE",), "monochromatic": (["false", "true"],), "invert": (["false", "true"],), "channels": (["rgb", "rgba", "rg", "rb", "ra", "gb", "ga", "ba", "r", "g", "b", "a"],), }, } RETURN_TYPES = ("IMAGE",) FUNCTION = "node" CATEGORY = "image/noise" def noise(self, images, monochromatic, invert): if monochromatic and images.shape[3] > 1: noise = np.random.bytes(np.prod(images.shape[:3])) noise = np.frombuffer(noise, np.uint8) noise = np.reshape(noise, images.shape[:3]) else: noise = np.random.bytes(np.prod(images.shape)) noise = np.frombuffer(noise, np.uint8) noise = np.reshape(noise, images.shape) noise = noise.astype(images.dtype) noise /= 255 if monochromatic and images.shape[3] > 1: noise = noise[..., np.newaxis].repeat(images.shape[3], -1) if invert: noise = images - noise else: noise = images + noise noise = np.clip(noise, 0.0, 1.0) return noise def node(self, images, monochromatic, invert, channels): tensor = images.clone().detach() monochromatic = True if monochromatic == "true" else False invert = True if invert == "true" else False return (channels_layer(tensor, channels, lambda x: self.noise( x, monochromatic, invert )),) class ImageNoiseGaussian: def __init__(self): pass @classmethod def INPUT_TYPES(cls): return { "required": { "images": ("IMAGE",), "strength": ("FLOAT", { "default": 0.5, "step": 0.01 }), "monochromatic": (["false", "true"],), "invert": (["false", "true"],), "channels": (["rgb", "rgba", "rg", "rb", "ra", "gb", "ga", "ba", "r", "g", "b", "a"],), }, } RETURN_TYPES = ("IMAGE",) FUNCTION = "node" CATEGORY = "image/noise" def noise(self, images, strength, monochromatic, invert): if monochromatic and images.shape[3] > 1: noise = np.random.normal(0, 1, images.shape[:3]) else: noise = np.random.normal(0, 1, images.shape) noise = np.abs(noise) noise /= noise.max() if monochromatic and images.shape[3] > 1: noise = noise[..., np.newaxis].repeat(images.shape[3], -1) if invert: noise = images - noise * strength else: noise = images + noise * strength noise = np.clip(noise, 0.0, 1.0) noise = noise.astype(images.dtype) return noise def node(self, images, strength, monochromatic, invert, channels): tensor = images.clone().detach() monochromatic = True if monochromatic == "true" else False invert = True if invert == "true" else False return (channels_layer(tensor, channels, lambda x: self.noise( x, strength, monochromatic, invert )),) NODE_CLASS_MAPPINGS = { "ImageNoiseBeta": ImageNoiseBeta, "ImageNoiseBinomial": ImageNoiseBinomial, "ImageNoiseBytes": ImageNoiseBytes, "ImageNoiseGaussian": ImageNoiseGaussian }