Adds AsciiArt effect
makes image composed of ascii characters
This commit is contained in:
@@ -19,6 +19,7 @@ Both images have the workflow attached, and are included with the repo. Feel fre
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
- ArithmeticBlend: Blends two images using arithmetic operations like addition, subtraction, and difference.
|
- ArithmeticBlend: Blends two images using arithmetic operations like addition, subtraction, and difference.
|
||||||
|
- AsciiArt: Transforms an image into being composed of ASCII characters
|
||||||
- Blend: Blends two images together with a variety of different modes
|
- Blend: Blends two images together with a variety of different modes
|
||||||
- Blur: Applies a Gaussian blur to the input image, softening the details
|
- Blur: Applies a Gaussian blur to the input image, softening the details
|
||||||
- CannyEdgeMask: Creates a mask using canny edge detection
|
- CannyEdgeMask: Creates a mask using canny edge detection
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
import numpy as np
|
||||||
|
import torch
|
||||||
|
|
||||||
|
class AsciiArt:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
"char_size": ("INT", {
|
||||||
|
"default": 12,
|
||||||
|
"min": 0,
|
||||||
|
"max": 64,
|
||||||
|
"step": 2,
|
||||||
|
}),
|
||||||
|
"font_size": ("INT", {
|
||||||
|
"default": 12,
|
||||||
|
"min": 0,
|
||||||
|
"max": 64,
|
||||||
|
"step": 2,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
FUNCTION = "apply_ascii_art_effect"
|
||||||
|
|
||||||
|
CATEGORY = "postprocessing/Effects"
|
||||||
|
|
||||||
|
def apply_ascii_art_effect(self, image: torch.Tensor, char_size: int, font_size: int):
|
||||||
|
batch_size, height, width, channels = image.shape
|
||||||
|
result = torch.zeros_like(image)
|
||||||
|
|
||||||
|
for b in range(batch_size):
|
||||||
|
img_b = image[b] * 255.0
|
||||||
|
img_b = Image.fromarray(img_b.numpy().astype('uint8'), 'RGB')
|
||||||
|
result_b = ascii_art_effect(img_b, char_size, font_size)
|
||||||
|
result_b = torch.tensor(np.array(result_b)) / 255.0
|
||||||
|
result[b] = result_b
|
||||||
|
|
||||||
|
return (result,)
|
||||||
|
|
||||||
|
|
||||||
|
def ascii_art_effect(image: torch.Tensor, char_size: int, font_size: int):
|
||||||
|
chars = " .'`^\",:;I1!i><-+_-?][}{1)(|\/tfjrxnuvczXYUCLQ0OZmwqpbdkhao*#MW&8%B@$"
|
||||||
|
small_image = image.resize((image.size[0] // char_size, image.size[1] // char_size), Image.Resampling.NEAREST)
|
||||||
|
|
||||||
|
def get_char(value):
|
||||||
|
return chars[value * len(chars) // 256]
|
||||||
|
|
||||||
|
ascii_image = Image.new('RGB', image.size, (0, 0, 0))
|
||||||
|
font = ImageFont.truetype("arial.ttf", font_size)
|
||||||
|
draw_image = ImageDraw.Draw(ascii_image)
|
||||||
|
|
||||||
|
for i in range(small_image.height):
|
||||||
|
for j in range(small_image.width):
|
||||||
|
r, g, b = small_image.getpixel((j, i))
|
||||||
|
k = (r + g + b) // 3
|
||||||
|
draw_image.text(
|
||||||
|
(j * char_size, i * char_size),
|
||||||
|
get_char(k),
|
||||||
|
font=font,
|
||||||
|
fill=(r, g, b)
|
||||||
|
)
|
||||||
|
|
||||||
|
return ascii_image
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"AsciiArt": AsciiArt,
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import torch
|
import torch
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
import numpy as np
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
|
||||||
from PIL import Image, ImageEnhance
|
from PIL import Image, ImageEnhance
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
@@ -47,6 +48,73 @@ class ArithmeticBlend:
|
|||||||
def difference(self, img1, img2):
|
def difference(self, img1, img2):
|
||||||
return torch.abs(img1 - img2)
|
return torch.abs(img1 - img2)
|
||||||
|
|
||||||
|
class AsciiArt:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
"char_size": ("INT", {
|
||||||
|
"default": 12,
|
||||||
|
"min": 0,
|
||||||
|
"max": 64,
|
||||||
|
"step": 2,
|
||||||
|
}),
|
||||||
|
"font_size": ("INT", {
|
||||||
|
"default": 12,
|
||||||
|
"min": 0,
|
||||||
|
"max": 64,
|
||||||
|
"step": 2,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
FUNCTION = "apply_ascii_art_effect"
|
||||||
|
|
||||||
|
CATEGORY = "postprocessing/Effects"
|
||||||
|
|
||||||
|
def apply_ascii_art_effect(self, image: torch.Tensor, char_size: int, font_size: int):
|
||||||
|
batch_size, height, width, channels = image.shape
|
||||||
|
result = torch.zeros_like(image)
|
||||||
|
|
||||||
|
for b in range(batch_size):
|
||||||
|
img_b = image[b] * 255.0
|
||||||
|
img_b = Image.fromarray(img_b.numpy().astype('uint8'), 'RGB')
|
||||||
|
result_b = ascii_art_effect(img_b, char_size, font_size)
|
||||||
|
result_b = torch.tensor(np.array(result_b)) / 255.0
|
||||||
|
result[b] = result_b
|
||||||
|
|
||||||
|
return (result,)
|
||||||
|
|
||||||
|
|
||||||
|
def ascii_art_effect(image: torch.Tensor, char_size: int, font_size: int):
|
||||||
|
chars = " .'`^\",:;I1!i><-+_-?][}{1)(|\/tfjrxnuvczXYUCLQ0OZmwqpbdkhao*#MW&8%B@$"
|
||||||
|
small_image = image.resize((image.size[0] // char_size, image.size[1] // char_size), Image.Resampling.NEAREST)
|
||||||
|
|
||||||
|
def get_char(value):
|
||||||
|
return chars[value * len(chars) // 256]
|
||||||
|
|
||||||
|
ascii_image = Image.new('RGB', image.size, (0, 0, 0))
|
||||||
|
font = ImageFont.truetype("arial.ttf", font_size)
|
||||||
|
draw_image = ImageDraw.Draw(ascii_image)
|
||||||
|
|
||||||
|
for i in range(small_image.height):
|
||||||
|
for j in range(small_image.width):
|
||||||
|
r, g, b = small_image.getpixel((j, i))
|
||||||
|
k = (r + g + b) // 3
|
||||||
|
draw_image.text(
|
||||||
|
(j * char_size, i * char_size),
|
||||||
|
get_char(k),
|
||||||
|
font=font,
|
||||||
|
fill=(r, g, b)
|
||||||
|
)
|
||||||
|
|
||||||
|
return ascii_image
|
||||||
|
|
||||||
class Blend:
|
class Blend:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
@@ -1372,6 +1440,7 @@ def pixel_sort(img, mask, horizontal_sort=False, span_limit=None, sort_by='H', r
|
|||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"ArithmeticBlend": ArithmeticBlend,
|
"ArithmeticBlend": ArithmeticBlend,
|
||||||
|
"AsciiArt": AsciiArt,
|
||||||
"Blend": Blend,
|
"Blend": Blend,
|
||||||
"Blur": Blur,
|
"Blur": Blur,
|
||||||
"CannyEdgeMask": CannyEdgeMask,
|
"CannyEdgeMask": CannyEdgeMask,
|
||||||
|
|||||||
Reference in New Issue
Block a user