-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathimage_layering.py
95 lines (74 loc) · 3.21 KB
/
image_layering.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import torch
import numpy as np
from PIL import Image
import subprocess
import sys
try:
import blend_modes
except ModuleNotFoundError:
# install pixelsort in current venv
subprocess.check_call([sys.executable, "-m", "pip", "install", "blend-modes"])
import blend_modes
import torch
import numpy as np
from PIL import Image
class Layering:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"base_image": ("IMAGE",),
"add_layer1": ("IMAGE",)},
"optional": {
"add_layer2": ("IMAGE", {"default": None}),
"add_layer3": ("IMAGE", {"default": None}),
# "key_color": ("TUPLE", {"default": (255, 255, 255)}),
# "alpha1": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
# "alpha2": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
# "alpha3": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_blend"
CATEGORY = "trNodes"
def tensor_to_pil(self, img):
if img is not None:
i = 255. * img.cpu().numpy().squeeze()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
return img
def alpha_cutout(self, img, threshold=80, dist=10):
arr = np.array(np.asarray(img)) # 获取图像数据,使用了numpy
r, g, b, a = np.rollaxis(arr, axis=-1)
mask = ((r > threshold)
& (g > threshold)
& (b > threshold)
& (np.abs(r - g) < dist) # 将接近白色背景的也替换掉
& (np.abs(r - b) < dist)
& (np.abs(g - b) < dist)
)
arr[mask, 3] = 0
img = Image.fromarray(arr, mode='RGBA') # 转换为图像格式
return img
def create_transparent_image(self, image, key_color, alpha):
transparent_image = Image.new('RGBA', image.size, (0, 0, 0, 0))
for x in range(image.width):
for y in range(image.height):
pixel = image.getpixel((x, y))
if pixel != key_color:
transparent_image.putpixel((x, y), (*pixel[:3], int(255 * alpha)))
return transparent_image
def apply_blend(self, base_image, add_layer1, alpha1=1.0, add_layer2=None, alpha2=1.0, add_layer3=None, alpha3=1.0):
base_image = self.tensor_to_pil(base_image[0]).convert('RGBA')
add_layers = [(add_layer1, alpha1), (add_layer2, alpha2), (add_layer3, alpha3)]
add_layers = [(self.tensor_to_pil(layer[0]).convert('RGBA'), alpha) for layer, alpha in add_layers if layer is not None]
for image, alpha in add_layers:
image = image.resize(base_image.size, Image.ANTIALIAS)
transparent_image = self.alpha_cutout(image)
base_image = Image.alpha_composite(base_image, transparent_image)
base_image = base_image.convert('RGB')
# convert to tensor
out_image = np.array(base_image).astype(np.float32) / 255.0
out_image = torch.from_numpy(out_image).unsqueeze(0)
return (out_image,)