|
|
@ -578,64 +578,44 @@ class LatentFlip: |
|
|
|
class LatentComposite: |
|
|
|
class LatentComposite: |
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
|
def INPUT_TYPES(s): |
|
|
|
def INPUT_TYPES(s): |
|
|
|
return { |
|
|
|
return {"required": { "samples_to": ("LATENT",), |
|
|
|
"required": { |
|
|
|
|
|
|
|
"samples_to": ("LATENT",), |
|
|
|
|
|
|
|
"samples_from": ("LATENT",), |
|
|
|
"samples_from": ("LATENT",), |
|
|
|
"x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
"x": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
"y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
"y": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
"feather": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
"feather": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 8}), |
|
|
|
} |
|
|
|
}} |
|
|
|
} |
|
|
|
|
|
|
|
RETURN_TYPES = ("LATENT",) |
|
|
|
RETURN_TYPES = ("LATENT",) |
|
|
|
FUNCTION = "composite" |
|
|
|
FUNCTION = "composite" |
|
|
|
|
|
|
|
|
|
|
|
CATEGORY = "latent" |
|
|
|
CATEGORY = "latent" |
|
|
|
|
|
|
|
|
|
|
|
def composite(self, samples_to, samples_from, x, y, feather): |
|
|
|
def composite(self, samples_to, samples_from, x, y, composite_method="normal", feather=0): |
|
|
|
output = samples_to.copy() |
|
|
|
x = x // 8 |
|
|
|
destination = samples_to["samples"].clone() |
|
|
|
y = y // 8 |
|
|
|
source = samples_from["samples"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
left, top = (x // 8, y // 8) |
|
|
|
|
|
|
|
right, bottom = (left + source.shape[3], top + source.shape[2],) |
|
|
|
|
|
|
|
feather = feather // 8 |
|
|
|
feather = feather // 8 |
|
|
|
|
|
|
|
samples_out = samples_to.copy() |
|
|
|
|
|
|
|
s = samples_to["samples"].clone() |
|
|
|
|
|
|
|
samples_to = samples_to["samples"] |
|
|
|
# calculate the bounds of the source that will be overlapping the destination |
|
|
|
samples_from = samples_from["samples"] |
|
|
|
# this prevents the source trying to overwrite latent pixels that are out of bounds |
|
|
|
if feather == 0: |
|
|
|
# of the destination |
|
|
|
s[:,:,y:y+samples_from.shape[2],x:x+samples_from.shape[3]] = samples_from[:,:,:samples_to.shape[2] - y, :samples_to.shape[3] - x] |
|
|
|
visible_width, visible_height = (destination.shape[3] - left, destination.shape[2] - top,) |
|
|
|
else: |
|
|
|
|
|
|
|
samples_from = samples_from[:,:,:samples_to.shape[2] - y, :samples_to.shape[3] - x] |
|
|
|
mask = torch.ones_like(source) |
|
|
|
mask = torch.ones_like(samples_from) |
|
|
|
|
|
|
|
for t in range(feather): |
|
|
|
for f in range(feather): |
|
|
|
if y != 0: |
|
|
|
feather_rate = (f + 1.0) / feather |
|
|
|
mask[:,:,t:1+t,:] *= ((1.0/feather) * (t + 1)) |
|
|
|
|
|
|
|
|
|
|
|
if left > 0: |
|
|
|
if y + samples_from.shape[2] < samples_to.shape[2]: |
|
|
|
mask[:, :, :, f] *= feather_rate |
|
|
|
mask[:,:,mask.shape[2] -1 -t: mask.shape[2]-t,:] *= ((1.0/feather) * (t + 1)) |
|
|
|
|
|
|
|
if x != 0: |
|
|
|
if right < destination.shape[3] - 1: |
|
|
|
mask[:,:,:,t:1+t] *= ((1.0/feather) * (t + 1)) |
|
|
|
mask[:, :, :, -f] *= feather_rate |
|
|
|
if x + samples_from.shape[3] < samples_to.shape[3]: |
|
|
|
|
|
|
|
mask[:,:,:,mask.shape[3]- 1 - t: mask.shape[3]- t] *= ((1.0/feather) * (t + 1)) |
|
|
|
if top > 0: |
|
|
|
rev_mask = torch.ones_like(mask) - mask |
|
|
|
mask[:, :, f, :] *= feather_rate |
|
|
|
s[:,:,y:y+samples_from.shape[2],x:x+samples_from.shape[3]] = samples_from[:,:,:samples_to.shape[2] - y, :samples_to.shape[3] - x] * mask + s[:,:,y:y+samples_from.shape[2],x:x+samples_from.shape[3]] * rev_mask |
|
|
|
|
|
|
|
samples_out["samples"] = s |
|
|
|
if bottom < destination.shape[2] - 1: |
|
|
|
return (samples_out,) |
|
|
|
mask[:, :, -f, :] *= feather_rate |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mask = mask[:, :, :visible_height, :visible_width] |
|
|
|
|
|
|
|
inverse_mask = torch.ones_like(mask) - mask |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
source_portion = mask * source[:, :, :visible_height, :visible_width] |
|
|
|
|
|
|
|
destination_portion = inverse_mask * destination[:, :, top:bottom, left:right] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
destination[:, :, top:bottom, left:right] = source_portion + destination_portion |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output["samples"] = destination |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (output,) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LatentCrop: |
|
|
|
class LatentCrop: |
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
|