diff --git a/README.md b/README.md index ea361d6..a7c8e46 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Both images have the workflow attached, and are included with the repo. Feel fre - CannyEdgeDetection: Applies Canny edge detection to the input image - Chromatic Aberration: Shifts the color channels in an image, creating a glitch aesthetic - $\color{#00A7B5}\textbf{ColorCorrect:}$ Adjusts the color balance, temperature, hue, brightness, contrast, saturation, and gamma of an image + - $\color{#00A7B5}\textbf{ColorTint:}$ Applies a customizable tint to the input image, with various color modes such as sepia, RGB, CMY and several composite colors - Dissolve: Creates a grainy blend of two images using random pixels based on a dissolve factor. - DodgeAndBurn: Adjusts image brightness using dodge and burn effects based on a mask and intensity. - FilmGrain: Adds a film grain effect to the image, along with options to control the temperature, and vignetting @@ -34,7 +35,6 @@ Both images have the workflow attached, and are included with the repo. Feel fre - $\color{#00A7B5}\textbf{PixelSort:}$ Rearranges the pixels in the input image based on their values, and input mask. Creates a cool glitch like effect. - Pixelize: Applies a pixelization effect, simulating the reducing of resolution - $\color{#00A7B5}\textbf{Quantize:}$ Set and dither the amount of colors in an image from 0-256, reducing color information - - Sepia: Applies a mellow tone mapping, yielding an archival or vintage appearance - Sharpen: Enhances the details in an image by applying a sharpening filter - $\color{#00A7B5}\textbf{Solarize:}$ Inverts image colors based on a threshold for a striking, high-contrast effect - Vignette: Applies a vignette effect, putting the corners of the image in shadow diff --git a/post_processing/color_tint.py b/post_processing/color_tint.py new file mode 100644 index 0000000..8d93fcc --- /dev/null +++ b/post_processing/color_tint.py @@ -0,0 +1,66 @@ +import torch + +class ColorTint: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "image": ("IMAGE",), + "strength": ("FLOAT", { + "default": 1.0, + "min": 0.1, + "max": 1.0, + "step": 0.1 + }), + "mode": (["sepia", "red", "green", "blue", "cyan", "magenta", "yellow", "purple", "orange", "warm", "cool", "lime", "navy", "vintage", "rose", "teal", "maroon", "peach", "lavender", "olive"],), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "color_tint" + + CATEGORY = "postprocessing/Color Adjustments" + + def color_tint(self, image: torch.Tensor, strength: float, mode: str = "sepia"): + if strength == 0: + return (image,) + + sepia_weights = torch.tensor([0.2989, 0.5870, 0.1140]).view(1, 1, 1, 3).to(image.device) + + mode_filters = { + "sepia": torch.tensor([1.0, 0.8, 0.6]), + "red": torch.tensor([1.0, 0.6, 0.6]), + "green": torch.tensor([0.6, 1.0, 0.6]), + "blue": torch.tensor([0.6, 0.8, 1.0]), + "cyan": torch.tensor([0.6, 1.0, 1.0]), + "magenta": torch.tensor([1.0, 0.6, 1.0]), + "yellow": torch.tensor([1.0, 1.0, 0.6]), + "purple": torch.tensor([0.8, 0.6, 1.0]), + "orange": torch.tensor([1.0, 0.7, 0.3]), + "warm": torch.tensor([1.0, 0.9, 0.7]), + "cool": torch.tensor([0.7, 0.9, 1.0]), + "lime": torch.tensor([0.7, 1.0, 0.3]), + "navy": torch.tensor([0.3, 0.4, 0.7]), + "vintage": torch.tensor([0.9, 0.85, 0.7]), + "rose": torch.tensor([1.0, 0.8, 0.9]), + "teal": torch.tensor([0.3, 0.8, 0.8]), + "maroon": torch.tensor([0.7, 0.3, 0.5]), + "peach": torch.tensor([1.0, 0.8, 0.6]), + "lavender": torch.tensor([0.8, 0.6, 1.0]), + "olive": torch.tensor([0.6, 0.7, 0.4]), + } + + scale_filter = mode_filters[mode].view(1, 1, 1, 3).to(image.device) + + grayscale = torch.sum(image * sepia_weights, dim=-1, keepdim=True) + tinted = grayscale * scale_filter + + result = tinted * strength + image * (1 - strength) + return (result,) + +NODE_CLASS_MAPPINGS = { + "ColorTint": ColorTint +} diff --git a/post_processing/sepia.py b/post_processing/sepia.py deleted file mode 100644 index 8debe3d..0000000 --- a/post_processing/sepia.py +++ /dev/null @@ -1,48 +0,0 @@ -import torch - -class Sepia: - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "image": ("IMAGE",), - "strength": ("FLOAT", { - "default": 1.0, - "min": 0.1, - "max": 1.0, - "step": 0.1 - }), - "mode": (["sepia", "blue-pia", "green-pia"],), - }, - } - - RETURN_TYPES = ("IMAGE",) - FUNCTION = "sepia" - - CATEGORY = "postprocessing/Color Adjustments" - - def sepia(self, image: torch.Tensor, strength: float, mode: str = "sepia"): - if strength == 0: - return (image,) - - sepia_weights = torch.tensor([0.2989, 0.5870, 0.1140]).view(1, 1, 1, 3).to(image.device) - - if mode == "sepia": - sepia_filter = torch.tensor([1.0, 0.8, 0.6]).view(1, 1, 1, 3).to(image.device) - elif mode == "blue-pia": - sepia_filter = torch.tensor([0.6, 0.8, 1.0]).view(1, 1, 1, 3).to(image.device) - elif mode == "green-pia": - sepia_filter = torch.tensor([0.6, 1.0, 0.6]).view(1, 1, 1, 3).to(image.device) - - grayscale = torch.sum(image * sepia_weights, dim=-1, keepdim=True) - sepia = grayscale * sepia_filter - - result = sepia * strength + image * (1 - strength) - return (result,) - -NODE_CLASS_MAPPINGS = { - "Sepia": Sepia -} diff --git a/post_processing_nodes.py b/post_processing_nodes.py index 2d9fb62..9af490a 100644 --- a/post_processing_nodes.py +++ b/post_processing_nodes.py @@ -366,6 +366,67 @@ class ColorCorrect: return (result, ) +class ColorTint: + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "image": ("IMAGE",), + "strength": ("FLOAT", { + "default": 1.0, + "min": 0.1, + "max": 1.0, + "step": 0.1 + }), + "mode": (["sepia", "red", "green", "blue", "cyan", "magenta", "yellow", "purple", "orange", "warm", "cool", "lime", "navy", "vintage", "rose", "teal", "maroon", "peach", "lavender", "olive"],), + }, + } + + RETURN_TYPES = ("IMAGE",) + FUNCTION = "color_tint" + + CATEGORY = "postprocessing/Color Adjustments" + + def color_tint(self, image: torch.Tensor, strength: float, mode: str = "sepia"): + if strength == 0: + return (image,) + + sepia_weights = torch.tensor([0.2989, 0.5870, 0.1140]).view(1, 1, 1, 3).to(image.device) + + mode_filters = { + "sepia": torch.tensor([1.0, 0.8, 0.6]), + "red": torch.tensor([1.0, 0.6, 0.6]), + "green": torch.tensor([0.6, 1.0, 0.6]), + "blue": torch.tensor([0.6, 0.8, 1.0]), + "cyan": torch.tensor([0.6, 1.0, 1.0]), + "magenta": torch.tensor([1.0, 0.6, 1.0]), + "yellow": torch.tensor([1.0, 1.0, 0.6]), + "purple": torch.tensor([0.8, 0.6, 1.0]), + "orange": torch.tensor([1.0, 0.7, 0.3]), + "warm": torch.tensor([1.0, 0.9, 0.7]), + "cool": torch.tensor([0.7, 0.9, 1.0]), + "lime": torch.tensor([0.7, 1.0, 0.3]), + "navy": torch.tensor([0.3, 0.4, 0.7]), + "vintage": torch.tensor([0.9, 0.85, 0.7]), + "rose": torch.tensor([1.0, 0.8, 0.9]), + "teal": torch.tensor([0.3, 0.8, 0.8]), + "maroon": torch.tensor([0.7, 0.3, 0.5]), + "peach": torch.tensor([1.0, 0.8, 0.6]), + "lavender": torch.tensor([0.8, 0.6, 1.0]), + "olive": torch.tensor([0.6, 0.7, 0.4]), + } + + scale_filter = mode_filters[mode].view(1, 1, 1, 3).to(image.device) + + grayscale = torch.sum(image * sepia_weights, dim=-1, keepdim=True) + tinted = grayscale * scale_filter + + result = tinted * strength + image * (1 - strength) + return (result,) + class Dissolve: def __init__(self): pass @@ -984,49 +1045,6 @@ class Quantize: return (result,) -class Sepia: - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "image": ("IMAGE",), - "strength": ("FLOAT", { - "default": 1.0, - "min": 0.1, - "max": 1.0, - "step": 0.1 - }), - "mode": (["sepia", "blue-pia", "green-pia"],), - }, - } - - RETURN_TYPES = ("IMAGE",) - FUNCTION = "sepia" - - CATEGORY = "postprocessing/Color Adjustments" - - def sepia(self, image: torch.Tensor, strength: float, mode: str = "sepia"): - if strength == 0: - return (image,) - - sepia_weights = torch.tensor([0.2989, 0.5870, 0.1140]).view(1, 1, 1, 3).to(image.device) - - if mode == "sepia": - sepia_filter = torch.tensor([1.0, 0.8, 0.6]).view(1, 1, 1, 3).to(image.device) - elif mode == "blue-pia": - sepia_filter = torch.tensor([0.6, 0.8, 1.0]).view(1, 1, 1, 3).to(image.device) - elif mode == "green-pia": - sepia_filter = torch.tensor([0.6, 1.0, 0.6]).view(1, 1, 1, 3).to(image.device) - - grayscale = torch.sum(image * sepia_weights, dim=-1, keepdim=True) - sepia = grayscale * sepia_filter - - result = sepia * strength + image * (1 - strength) - return (result,) - class Sharpen: def __init__(self): pass @@ -1250,6 +1268,7 @@ NODE_CLASS_MAPPINGS = { "CannyEdgeDetection": CannyEdgeDetection, "ChromaticAberration": ChromaticAberration, "ColorCorrect": ColorCorrect, + "ColorTint": ColorTint, "Dissolve": Dissolve, "DodgeAndBurn": DodgeAndBurn, "FilmGrain": FilmGrain, @@ -1260,7 +1279,6 @@ NODE_CLASS_MAPPINGS = { "PixelSort": PixelSort, "Pixelize": Pixelize, "Quantize": Quantize, - "Sepia": Sepia, "Sharpen": Sharpen, "Solarize": Solarize, "Vignette": Vignette,