update RemBgUltra and PixelSpread nodes
@@ -575,6 +575,7 @@ Node options:
|
||||
* detail_range: Edge detail range.
|
||||
* black_point: Edge black sampling threshold.
|
||||
* white_point: Edge white sampling threshold.
|
||||
* process_detail: Set to false here will skip edge processing to save runtime.
|
||||
|
||||
### <a id="table1">PixelSpread</a>
|
||||
Pixel expansion preprocessing on the masked edge of an image can effectively improve the edges of image synthesis.
|
||||
@@ -583,6 +584,7 @@ Pixel expansion preprocessing on the masked edge of an image can effectively imp
|
||||
Node options:
|
||||

|
||||
* invert_mask: Whether to reverse the mask.
|
||||
* mask_grow: Mask expansion amplitude.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -561,6 +561,7 @@
|
||||
* detail_range: 边缘细节范围。
|
||||
* black_point: 边缘黑色采样阈值。
|
||||
* white_point: 边缘黑色采样阈值。
|
||||
* process_detail: 此处设为False将跳过边缘处理以节省运行时间。
|
||||
|
||||
### <a id="table1">PixelSpread</a>
|
||||
对图像的遮罩边缘部分进行像素扩张预处理,可有效改善图像合成的边缘。
|
||||
@@ -569,6 +570,7 @@
|
||||
节点选项说明:
|
||||

|
||||
* invert_mask: 是否反转遮罩。
|
||||
* mask_grow: 遮罩扩张幅度。
|
||||
|
||||
|
||||
### <a id="table1">MaskGrow</a>
|
||||
|
||||
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 392 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 3.6 MiB After Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 126 KiB |
@@ -14,6 +14,7 @@ class PixelSpread:
|
||||
"required": {
|
||||
"image": ("IMAGE", ), #
|
||||
"invert_mask": ("BOOLEAN", {"default": False}), # 反转mask
|
||||
"mask_grow": ("INT", {"default": 0, "min": -999, "max": 999, "step": 1}),
|
||||
},
|
||||
"optional": {
|
||||
"mask": ("MASK",), #
|
||||
@@ -26,15 +27,19 @@ class PixelSpread:
|
||||
CATEGORY = '😺dzNodes/LayerMask'
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def pixel_spread(self, image, invert_mask, mask=None):
|
||||
def pixel_spread(self, image, invert_mask, mask_grow, mask=None):
|
||||
_image = tensor2pil(image)
|
||||
if _image.mode == 'RGBA':
|
||||
_mask = _image.split()[-1]
|
||||
if mask_grow != 0:
|
||||
_mask = expand_mask(image2mask(_mask), mask_grow, 0) # 扩张,模糊
|
||||
else:
|
||||
_mask = Image.new('L', _image.size, 'white')
|
||||
if mask is not None:
|
||||
if invert_mask:
|
||||
mask = 1 - mask
|
||||
if mask_grow != 0:
|
||||
_mask = expand_mask(mask, mask_grow, 0) # 扩张,模糊
|
||||
_mask = mask2image(mask).convert('L')
|
||||
image = pil2tensor(_image.convert('RGB'))
|
||||
_mask = _mask.convert('RGB')
|
||||
|
||||
@@ -34,6 +34,7 @@ class RemBgUltra:
|
||||
"detail_range": ("INT", {"default": 8, "min": 0, "max": 256, "step": 1}),
|
||||
"black_point": ("FLOAT", {"default": 0.01, "min": 0.01, "max": 0.98, "step": 0.01}),
|
||||
"white_point": ("FLOAT", {"default": 0.99, "min": 0.02, "max": 0.99, "step": 0.01}),
|
||||
"process_detail": ("BOOLEAN", {"default": True}),
|
||||
},
|
||||
"optional": {
|
||||
}
|
||||
@@ -44,7 +45,7 @@ class RemBgUltra:
|
||||
FUNCTION = "rembg_ultra"
|
||||
CATEGORY = '😺dzNodes/LayerMask'
|
||||
|
||||
def rembg_ultra(self, image, detail_range, black_point, white_point):
|
||||
def rembg_ultra(self, image, detail_range, black_point, white_point, process_detail):
|
||||
|
||||
rmbgmodel = load_model()
|
||||
orig_image = tensor2pil(image).convert('RGB')
|
||||
@@ -64,19 +65,20 @@ class RemBgUltra:
|
||||
result = (result-mi)/(ma-mi)
|
||||
im_array = (result*255).cpu().data.numpy().astype(np.uint8)
|
||||
_mask = Image.fromarray(np.squeeze(im_array)).convert('L')
|
||||
# ultra edge process
|
||||
d = detail_range * 2 + 1
|
||||
i_dup = copy.deepcopy(image.cpu().numpy().astype(np.float64))
|
||||
a_dup = copy.deepcopy(pil2tensor(_mask.convert('RGB')).cpu().numpy().astype(np.float64))
|
||||
for index, img in enumerate(i_dup):
|
||||
trimap = a_dup[index][:,:,0] # convert to single channel
|
||||
if detail_range > 0:
|
||||
trimap = cv2.GaussianBlur(trimap, (d, d), 0)
|
||||
trimap = fix_trimap(trimap, black_point, white_point)
|
||||
alpha = estimate_alpha_cf(img, trimap, laplacian_kwargs={"epsilon": 1e-6},
|
||||
cg_kwargs={"maxiter": 500})
|
||||
a_dup[index] = np.stack([alpha, alpha, alpha], axis=-1) # convert back to rgb
|
||||
_mask = tensor2pil(torch.from_numpy(a_dup.astype(np.float32))) # alpha
|
||||
if process_detail:
|
||||
# ultra edge process
|
||||
d = detail_range * 2 + 1
|
||||
i_dup = copy.deepcopy(image.cpu().numpy().astype(np.float64))
|
||||
a_dup = copy.deepcopy(pil2tensor(_mask.convert('RGB')).cpu().numpy().astype(np.float64))
|
||||
for index, img in enumerate(i_dup):
|
||||
trimap = a_dup[index][:,:,0] # convert to single channel
|
||||
if detail_range > 0:
|
||||
trimap = cv2.GaussianBlur(trimap, (d, d), 0)
|
||||
trimap = fix_trimap(trimap, black_point, white_point)
|
||||
alpha = estimate_alpha_cf(img, trimap, laplacian_kwargs={"epsilon": 1e-6},
|
||||
cg_kwargs={"maxiter": 500})
|
||||
a_dup[index] = np.stack([alpha, alpha, alpha], axis=-1) # convert back to rgb
|
||||
_mask = tensor2pil(torch.from_numpy(a_dup.astype(np.float32))) # alpha
|
||||
ret_image = RGB2RGBA(orig_image, _mask.convert('L'))
|
||||
return (pil2tensor(ret_image), image2mask(_mask),)
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
490,
|
||||
660
|
||||
],
|
||||
"size": {
|
||||
"0": 330.9508972167969,
|
||||
"1": 298.0813903808594
|
||||
},
|
||||
"size": [
|
||||
330.9508972167969,
|
||||
314
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
@@ -51,7 +51,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 126
|
||||
"1": 150
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
@@ -87,34 +87,10 @@
|
||||
"widgets_values": [
|
||||
10,
|
||||
0.01,
|
||||
0.99
|
||||
0.99,
|
||||
true
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "LayerMask: MaskPreview",
|
||||
"pos": [
|
||||
1247,
|
||||
802
|
||||
],
|
||||
"size": {
|
||||
"0": 309.01806640625,
|
||||
"1": 246
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 75
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LayerMask: MaskPreview"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"type": "PreviewImage",
|
||||
@@ -149,7 +125,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 78
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
@@ -181,8 +157,34 @@
|
||||
"Node name for S&R": "LayerMask: PixelSpread"
|
||||
},
|
||||
"widgets_values": [
|
||||
false
|
||||
false,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "LayerMask: MaskPreview",
|
||||
"pos": [
|
||||
1244,
|
||||
827
|
||||
],
|
||||
"size": {
|
||||
"0": 309.01806640625,
|
||||
"1": 246
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 75
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "LayerMask: MaskPreview"
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 78
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
@@ -484,19 +484,20 @@
|
||||
"Node name for S&R": "LayerMask: PixelSpread"
|
||||
},
|
||||
"widgets_values": [
|
||||
false
|
||||
false,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"type": "LayerMask: RemBgUltra",
|
||||
"pos": [
|
||||
1124,
|
||||
1484
|
||||
1126,
|
||||
1519
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 126
|
||||
"1": 150
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
@@ -533,7 +534,8 @@
|
||||
"widgets_values": [
|
||||
10,
|
||||
0.01,
|
||||
0.99
|
||||
0.99,
|
||||
true
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||