Merge pull request #3 from judian17/main

Adjusted fill process node outputs and added a new "fill process noscaling" node that only crops without scaling.
This commit is contained in:
judian17
2025-06-04 21:23:00 +08:00
committed by GitHub
9 changed files with 434 additions and 23 deletions
File diff suppressed because one or more lines are too long
+10
View File
@@ -53,6 +53,16 @@ Please first install [ComfyUI](https://github.com/comfyanonymous/ComfyUI/tree/ma
python main.py
```
## 🚀 Usage Examples
Using this [workflow](workflows/InsertAnything.json), the source image and ref_image are cropped and scaled to a standard size of 768*768 to generate the image.
The effect is shown in the figure below.
![insert_anything](assets/insert_anything.png)
The Insert Anything LoRA still performs well at larger resolutions. Therefore, to avoid image quality loss caused by processing images to 768*768, you can also use this [workflow](`workflows/InsertAnything_noscaling.json`) to only crop the image for generation. In this case, you can set the image resolution more freely.
The effect is shown in the figure below.
![insert_anything_noscaling](assets/insert_anything_noscaling.png)
+5
View File
@@ -1,10 +1,13 @@
from .insert_anything_node import MaskOption, ReduxProcess, FillProcess, CropBack
from .no_scaling import FillProcessNoScaling, CropBackNoScaling
NODE_CLASS_MAPPINGS = {
"MaskOption": MaskOption,
"ReduxProcess": ReduxProcess,
"FillProcess": FillProcess,
"CropBack": CropBack,
"FillProcessNoScaling": FillProcessNoScaling,
"CropBackNoScaling": CropBackNoScaling,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -12,4 +15,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ReduxProcess": "InsertAnything - Redux Process",
"FillProcess": "InsertAnything - Fill Process",
"CropBack": "InsertAnything - Crop Back",
"FillProcessNoScaling": "InsertAnything - Fill Process (No Scaling)",
"CropBackNoScaling": "InsertAnything - Crop Back (No Scaling)",
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 726 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

+72 -22
View File
@@ -315,7 +315,10 @@ class FillProcess:
}
}
RETURN_TYPES = (
"IMAGE", "MASK", "H1", "W1", "H2", "W2", "old_tar_image", "tar_box_yyxx_crop", "IMAGE",
"IMAGE", "MASK", "IMAGE", "BOX", "CROP_PARAMS", "IMAGE", # Adjusted
)
RETURN_NAMES = ( # Adjusted
"image", "mask", "old_tar_image", "tar_box_yyxx_crop", "crop_params", "preview_image",
)
FUNCTION = "FillProcess"
@@ -418,13 +421,29 @@ class FillProcess:
diptych_ref_tar_tensor = torch.from_numpy(diptych_ref_tar.copy()).unsqueeze(0).float() / 255.0
mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).unsqueeze(1).float() / 255.0 # (B, C, H, W) so (1,1,H,W)
mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).float() / 255.0
mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).float() / 255.0 # This was duplicated, using the (1,1,H,W) version above this line. Correcting.
# The line above was: mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).unsqueeze(1).float() / 255.0
# The line below it was: mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).float() / 255.0
# The unsqueeze(1) is for channel, so (B, C, H, W) is (1,1,H,W) for a single channel mask.
# Let's ensure the correct one is used. The one with unsqueeze(1) is typical for masks.
# Re-evaluating: output_mask_diptych_np is (H,W).
# For ComfyUI MASK type, it's often (B, H, W) or (B, 1, H, W).
# If it's (B,H,W) then .unsqueeze(0).float() / 255.0 is fine.
# If it needs to be (B,1,H,W) then .unsqueeze(0).unsqueeze(1).float() / 255.0 is correct.
# The original code had both, the second one overwriting the first.
# Let's stick to the (B, H, W) convention for mask output unless (B,1,H,W) is strictly needed by other nodes.
# Given `mask_diptych_tensor = torch.from_numpy(output_mask_diptych_np.copy()).unsqueeze(0).float() / 255.0` was the last one, let's assume it's (B,H,W)
# However, the type hint for MASK in ComfyUI is often a 2D tensor (H,W) or (1,H,W) for batch 1.
# Let's assume the output MASK type should be (1, H, W) for consistency with typical ComfyUI mask tensors.
# output_mask_diptych_np is (H,W). So, .unsqueeze(0) makes it (1,H,W). This is fine.
old_tar_image_tensor = torch.from_numpy(old_tar_image_np.astype(np.float32) / 255.0).unsqueeze(0)
crop_params_tuple = (H1, W1, H2, W2)
# tar_box_yyxx_crop is already a tuple (y1,y2,x1,x2)
show_diptych_ref_tar_tensor = torch.from_numpy(show_diptych_ref_tar.copy()).unsqueeze(0).float() / 255.0
return (diptych_ref_tar_tensor, mask_diptych_tensor, H1, W1, H2, W2, old_tar_image_np, tar_box_yyxx_crop, show_diptych_ref_tar_tensor)
return (diptych_ref_tar_tensor, mask_diptych_tensor, old_tar_image_tensor, tar_box_yyxx_crop, crop_params_tuple, show_diptych_ref_tar_tensor)
@@ -435,12 +454,9 @@ class CropBack:
return {
"required": {
"raw_image": ("IMAGE",),
"H1": ("H1",),
"W1": ("W1",),
"H2": ("H2",),
"W2": ("W2",),
"old_tar_image": ("old_tar_image",),
"tar_box_yyxx_crop": ("tar_box_yyxx_crop",),
"old_tar_image": ("IMAGE",), # Changed from custom type to IMAGE
"tar_box_yyxx_crop": ("BOX",), # Assuming BOX is the type for the tuple
"crop_params": ("CROP_PARAMS",) # Assuming CROP_PARAMS for (H1,W1,H2,W2)
}
}
@@ -450,25 +466,59 @@ class CropBack:
def CropBack(
self,
raw_image,
H1, W1, H2, W2,
old_tar_image,
tar_box_yyxx_crop
old_tar_image, # This is now a tensor
tar_box_yyxx_crop, # This is a tuple (y1,y2,x1,x2)
crop_params # This is a tuple (H1,W1,H2,W2)
):
# Unpack crop_params
H1, W1, H2, W2 = crop_params
raw_image = np.array(raw_image)[0]
raw_image = (raw_image * 255).round().astype(np.uint8)
raw_image = Image.fromarray(raw_image)
# Convert old_tar_image tensor to numpy array for crop_back helper
old_tar_image_np = (old_tar_image[0].cpu().numpy() * 255).round().astype(np.uint8)
width, height = raw_image.size
raw_image_np = np.array(raw_image)[0] # raw_image is already a tensor
raw_image_np = (raw_image_np * 255).round().astype(np.uint8)
# Convert raw_image_np to PIL Image for cropping the right half
pil_raw_image = Image.fromarray(raw_image_np)
width, height = pil_raw_image.size
left = width // 2
right = width
top = 0
bottom = height
edited_image = raw_image.crop((left, top, right, bottom))
edited_image_pil = pil_raw_image.crop((left, top, right, bottom))
edited_image = np.array(edited_image)
edited_image = crop_back(edited_image, old_tar_image, np.array([H1, W1, H2, W2]), np.array(tar_box_yyxx_crop))
edited_image_np = np.array(edited_image_pil)
# tar_box_yyxx_crop is already a tuple, convert to numpy array if crop_back expects it
# The crop_back helper function expects tar_image (old_tar_image_np) and tar_box_yyxx_crop as numpy arrays.
# extra_sizes is also expected as a numpy array.
edited_image_final_np = crop_back(edited_image_np, old_tar_image_np,
np.array([H1, W1, H2, W2]),
np.array(tar_box_yyxx_crop))
edited_image = torch.from_numpy(edited_image).unsqueeze(0).float() / 255.0
edited_image_tensor = torch.from_numpy(edited_image_final_np.astype(np.float32) / 255.0).unsqueeze(0)
return (edited_image,)
return (edited_image_tensor,)
raw_image = (raw_image * 255).round().astype(np.uint8)
raw_image = Image.fromarray(raw_image)
# This block is now part of the new structure above.
# raw_image = np.array(raw_image)[0]
# raw_image = (raw_image * 255).round().astype(np.uint8)
# raw_image = Image.fromarray(raw_image)
# width, height = raw_image.size
# left = width // 2
# right = width
# top = 0
# bottom = height
# edited_image = raw_image.crop((left, top, right, bottom))
# edited_image = np.array(edited_image)
# edited_image = crop_back(edited_image, old_tar_image, np.array([H1, W1, H2, W2]), np.array(tar_box_yyxx_crop))
# edited_image = torch.from_numpy(edited_image).unsqueeze(0).float() / 255.0
# return (edited_image,)
pass # Placeholder for the removed block, the logic is now in the new method body
+345
View File
@@ -0,0 +1,345 @@
import torch
import numpy as np
import cv2
from PIL import Image
import math
# Helper functions (copied or adapted from insert_anything_node.py)
def standardize_and_binarize_mask(mask_input):
if isinstance(mask_input, torch.Tensor):
mask_np = mask_input.cpu().numpy()
elif isinstance(mask_input, np.ndarray):
mask_np = mask_input
else:
raise TypeError(f"Mask input type {type(mask_input)} not supported. Expected torch.Tensor or np.ndarray.")
if mask_np.ndim == 3 and mask_np.shape[0] == 1:
mask_np = mask_np.squeeze(0)
elif mask_np.ndim == 4 and mask_np.shape[0] == 1 and mask_np.shape[1] == 1:
mask_np = mask_np.squeeze(0).squeeze(0)
if mask_np.ndim == 3:
if mask_np.shape[-1] == 1:
mask_np = mask_np.squeeze(axis=-1)
elif mask_np.shape[0] == 1:
mask_np = mask_np.squeeze(0)
elif mask_np.shape[-1] > 1:
mask_np = mask_np[..., 0]
if mask_np.ndim != 2:
raise ValueError(f"Mask has unexpected shape {mask_np.shape} after initial processing. Expected 2D mask (H,W). Original input shape was {mask_input.shape if hasattr(mask_input, 'shape') else 'unknown'}.")
if mask_np.dtype == np.float32 or mask_np.dtype == np.float64:
if mask_np.min() >= 0.0 and mask_np.max() <= 1.0:
mask_np = (mask_np * 255).astype(np.uint8)
else:
mask_np = np.clip(mask_np, 0, 255).astype(np.uint8)
elif mask_np.dtype != np.uint8:
mask_np = np.clip(mask_np, 0, 255).astype(np.uint8)
_, mask_np_binarized = cv2.threshold(mask_np, 128, 255, cv2.THRESH_BINARY)
return mask_np_binarized
def get_bbox_from_mask(mask):
h,w = mask.shape[0],mask.shape[1]
if mask.sum() < 10:
return 0,h-1,0,w-1
rows = np.any(mask,axis=1)
cols = np.any(mask,axis=0)
y1,y2 = np.where(rows)[0][[0,-1]]
x1,x2 = np.where(cols)[0][[0,-1]]
return (y1,y2,x1,x2)
def expand_image_mask(image, mask, ratio=1.4):
h,w = image.shape[0], image.shape[1]
H,W = int(h * ratio), int(w * ratio)
h1 = int((H - h) // 2)
h2 = H - h - h1
w1 = int((W -w) // 2)
w2 = W -w - w1
pad_param_image = ((h1,h2),(w1,w2),(0,0)) if image.ndim == 3 else ((h1,h2),(w1,w2))
pad_param_mask = ((h1,h2),(w1,w2))
image_padded = np.pad(image, pad_param_image, 'constant', constant_values=255 if image.ndim == 3 else 0)
mask_padded = np.pad(mask, pad_param_mask, 'constant', constant_values=0)
return image_padded, mask_padded
def pad_to_square(image, pad_value = 255, random_padding = False):
H,W = image.shape[0], image.shape[1]
if H == W:
return image
padd = abs(H - W)
if random_padding:
padd_1 = int(np.random.randint(0,padd+1))
else:
padd_1 = int(padd / 2)
padd_2 = padd - padd_1
if len(image.shape) == 2:
if H > W:
pad_param = ((0, 0), (padd_1, padd_2))
else:
pad_param = ((padd_1, padd_2), (0, 0))
elif len(image.shape) == 3:
if H > W:
pad_param = ((0, 0), (padd_1, padd_2), (0, 0))
else:
pad_param = ((padd_1, padd_2), (0, 0), (0, 0))
else:
raise ValueError("Image must be 2D or 3D.")
image_padded = np.pad(image, pad_param, 'constant', constant_values=pad_value)
return image_padded
def create_highlighted_mask(image_np, mask_np, alpha=0.5, gray_value=128):
if mask_np.max() <= 1.0 and mask_np.dtype != np.uint8:
mask_np_uint8 = (mask_np * 255).astype(np.uint8)
elif mask_np.dtype != np.uint8:
mask_np_uint8 = np.clip(mask_np,0,255).astype(np.uint8)
else:
mask_np_uint8 = mask_np
if mask_np_uint8.max() > 1:
mask_bool = mask_np_uint8 > 128
else:
mask_bool = mask_np_uint8 > 0.5
image_float = image_np.astype(np.float32)
gray_overlay = np.full_like(image_float, gray_value, dtype=np.float32)
result = image_float.copy()
result[mask_bool] = (1 - alpha) * image_float[mask_bool] + alpha * gray_overlay[mask_bool]
return result.astype(np.uint8)
def adjust_to_multiple_of_val(value, multiple):
if multiple <= 0:
return value
if value == 0:
return 0
remainder = value % multiple
if remainder == 0:
return value
return value + (multiple - remainder)
def calculate_adjusted_dimension_and_offset(start_coord, current_length, total_img_length, multiple):
if current_length == 0 or total_img_length == 0:
return start_coord, 0
target_length = adjust_to_multiple_of_val(current_length, multiple)
if start_coord + target_length <= total_img_length:
return start_coord, target_length
new_start_coord_for_target_length = total_img_length - target_length
if new_start_coord_for_target_length >= 0:
return new_start_coord_for_target_length, target_length
max_fit_multiple = math.floor(total_img_length / float(multiple)) * multiple
if max_fit_multiple > 0:
original_center = start_coord + current_length / 2.0
new_center = max_fit_multiple / 2.0
aligned_start_coord = round(original_center - new_center)
aligned_start_coord = max(0, aligned_start_coord)
aligned_start_coord = min(aligned_start_coord, total_img_length - max_fit_multiple)
return int(aligned_start_coord), int(max_fit_multiple)
else:
final_length = min(current_length, total_img_length - start_coord)
final_length = max(1 if current_length > 0 and total_img_length - start_coord > 0 else 0, final_length)
return start_coord, final_length
class FillProcessNoScaling:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"source_image": ("IMAGE", ),
"ref_image": ("IMAGE", ),
"source_mask": ("MASK", ),
"ref_mask": ("MASK", ),
"iterations": ("INT", {"default": 2, "min": 0, "max": 100}),
"expand_pixels": ("INT", {"default": 0, "min": 0, "max": 1024}),
}
}
RETURN_TYPES = ("IMAGE", "MASK", "IMAGE", "BOX", "IMAGE")
RETURN_NAMES = ("image", "mask", "old_tar_image", "tar_box_yyxx_crop", "preview_image")
FUNCTION = "process"
def process(self, source_image, ref_image, source_mask, ref_mask, iterations, expand_pixels):
source_image_np = (source_image[0].cpu().numpy() * 255).astype(np.uint8)
source_mask_np = standardize_and_binarize_mask(source_mask)
ref_image_np = (ref_image[0].cpu().numpy() * 255).astype(np.uint8)
ref_mask_np = standardize_and_binarize_mask(ref_mask)
img_h, img_w = source_image_np.shape[:2]
if iterations > 0:
kernel = np.ones((7, 7), np.uint8)
dilated_source_mask_np = cv2.dilate(source_mask_np, kernel, iterations=iterations)
else:
dilated_source_mask_np = source_mask_np.copy()
y1_exp, y2_exp, x1_exp, x2_exp = get_bbox_from_mask(dilated_source_mask_np)
initial_x1 = max(0, x1_exp - expand_pixels)
initial_y1 = max(0, y1_exp - expand_pixels)
initial_x2 = min(img_w - 1, x2_exp + expand_pixels)
initial_y2 = min(img_h - 1, y2_exp + expand_pixels)
if initial_x1 >= initial_x2 or initial_y1 >= initial_y2:
initial_x1, initial_y1, initial_x2, initial_y2 = x1_exp,y1_exp,x2_exp,y2_exp
if initial_x1 >= initial_x2 or initial_y1 >= initial_y2:
initial_x1, initial_y1, initial_x2, initial_y2 = 0, 0, img_w - 1, img_h - 1
initial_bbox_w = initial_x2 - initial_x1 + 1
initial_bbox_h = initial_y2 - initial_y1 + 1
final_x1, final_bbox_w = calculate_adjusted_dimension_and_offset(initial_x1, initial_bbox_w, img_w, 8)
final_y1, final_bbox_h = calculate_adjusted_dimension_and_offset(initial_y1, initial_bbox_h, img_h, 8)
if initial_bbox_w > 0 and final_bbox_w == 0 and (img_w - final_x1) > 0 :
final_bbox_w = min(initial_bbox_w, img_w - final_x1)
final_bbox_w = max(1, final_bbox_w)
if initial_bbox_h > 0 and final_bbox_h == 0 and (img_h - final_y1) > 0:
final_bbox_h = min(initial_bbox_h, img_h - final_y1)
final_bbox_h = max(1, final_bbox_h)
if final_bbox_w <= 0 or final_bbox_h <= 0:
cropped_source_image = np.full((8,8,3), 255, dtype=np.uint8)
cropped_source_mask = np.zeros((8,8), dtype=np.uint8)
final_x1, final_y1, final_bbox_w, final_bbox_h = 0,0,8,8
else:
cropped_source_image = source_image_np[final_y1 : final_y1 + final_bbox_h, final_x1 : final_x1 + final_bbox_w, :]
cropped_source_mask = dilated_source_mask_np[final_y1 : final_y1 + final_bbox_h, final_x1 : final_x1 + final_bbox_w]
ref_box_yyxx = get_bbox_from_mask(ref_mask_np)
ref_mask_0_1 = ref_mask_np // 255
ref_mask_3_0_1 = np.stack([ref_mask_0_1]*3, axis=-1)
masked_ref_image = ref_image_np * ref_mask_3_0_1 + np.ones_like(ref_image_np, dtype=np.uint8) * 255 * (1 - ref_mask_3_0_1)
ry1, ry2, rx1, rx2 = ref_box_yyxx
if not(ry1 >= ry2 or rx1 >= rx2):
masked_ref_image_cropped = masked_ref_image[ry1:ry2+1, rx1:rx2+1, :]
ref_mask_cropped_for_expand = ref_mask_np[ry1:ry2+1, rx1:rx2+1]
else:
masked_ref_image_cropped = np.full((100,100,3), 255, dtype=np.uint8)
ref_mask_cropped_for_expand = np.zeros((100,100), dtype=np.uint8)
expanded_ref_image, _ = expand_image_mask(masked_ref_image_cropped, ref_mask_cropped_for_expand, ratio=1.3)
processed_ref_image_square = pad_to_square(expanded_ref_image, pad_value=255)
target_ref_h = final_bbox_h
orig_ref_h, orig_ref_w = processed_ref_image_square.shape[:2]
if orig_ref_h == 0 or target_ref_h == 0:
scaled_ref_image = np.full((target_ref_h if target_ref_h > 0 else 8, 100 if target_ref_h > 0 else 8, 3), 255, dtype=np.uint8)
if target_ref_h == 0 and final_bbox_h > 0: target_ref_h = scaled_ref_image.shape[0] # Update if placeholder used
else:
scale_ratio = target_ref_h / orig_ref_h
target_ref_w = round(orig_ref_w * scale_ratio)
if target_ref_w <=0: target_ref_w = 1
scaled_ref_image = cv2.resize(processed_ref_image_square, (target_ref_w, target_ref_h), interpolation=cv2.INTER_AREA)
diptych_image = np.concatenate([scaled_ref_image, cropped_source_image], axis=1)
mask_for_ref_part = np.zeros((target_ref_h, scaled_ref_image.shape[1]), dtype=np.uint8)
if cropped_source_mask.ndim != 2: cropped_source_mask = cropped_source_mask[:,:,0]
diptych_mask_np = np.concatenate([mask_for_ref_part, cropped_source_mask], axis=1)
diptych_mask_3ch_for_preview = np.stack([diptych_mask_np]*3, axis=-1)
show_diptych_image_np = create_highlighted_mask(diptych_image, diptych_mask_3ch_for_preview)
diptych_image_tensor = torch.from_numpy(diptych_image.astype(np.float32) / 255.0).unsqueeze(0)
diptych_mask_tensor = torch.from_numpy(diptych_mask_np.astype(np.float32) / 255.0).unsqueeze(0).unsqueeze(1)
original_source_image_tensor = source_image.clone()
show_diptych_image_tensor = torch.from_numpy(show_diptych_image_np.astype(np.float32) / 255.0).unsqueeze(0)
tar_box_yyxx_crop_value = (final_y1, final_y1 + final_bbox_h - 1, final_x1, final_x1 + final_bbox_w - 1)
return (diptych_image_tensor, diptych_mask_tensor, original_source_image_tensor, tar_box_yyxx_crop_value, show_diptych_image_tensor)
class CropBackNoScaling:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"raw_image": ("IMAGE",),
"old_tar_image": ("IMAGE",),
"tar_box_yyxx_crop": ("BOX",),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "crop_back"
def crop_back(self, raw_image, old_tar_image, tar_box_yyxx_crop):
processed_np = (raw_image[0].cpu().numpy() * 255).astype(np.uint8)
original_source_np = (old_tar_image[0].cpu().numpy() * 255).astype(np.uint8)
# Unpack tar_box_yyxx_crop
# It was (y1, y2_inclusive, x1, x2_inclusive) from FillProcessNoScaling
# We need final_bbox_x, final_bbox_y, final_bbox_width, final_bbox_height
crop_y1, crop_y2, crop_x1, crop_x2 = tar_box_yyxx_crop
final_bbox_x = crop_x1
final_bbox_y = crop_y1
final_bbox_width = crop_x2 - crop_x1 + 1
final_bbox_height = crop_y2 - crop_y1 + 1
processed_h, processed_w = processed_np.shape[:2]
crop_x_start_from_right = max(0, processed_w - final_bbox_width)
crop_y_start_from_right = 0
slice_h_from_processed = min(processed_h, final_bbox_height)
slice_w_from_processed = min(final_bbox_width, processed_w - crop_x_start_from_right)
if slice_w_from_processed <= 0 or slice_h_from_processed <= 0:
return (old_tar_image,)
generated_part_raw = processed_np[
crop_y_start_from_right : crop_y_start_from_right + slice_h_from_processed,
crop_x_start_from_right : crop_x_start_from_right + slice_w_from_processed,
:
]
if generated_part_raw.shape[0] != final_bbox_height or generated_part_raw.shape[1] != final_bbox_width:
if final_bbox_width > 0 and final_bbox_height > 0 : # only resize if target is valid
generated_part_resized = cv2.resize(generated_part_raw, (final_bbox_width, final_bbox_height), interpolation=cv2.INTER_AREA)
else: # if target is 0, cannot resize to it, use raw (which might be empty)
generated_part_resized = generated_part_raw
else:
generated_part_resized = generated_part_raw
output_image_np = original_source_np.copy()
paste_y1 = final_bbox_y
paste_x1 = final_bbox_x
actual_paste_y1 = max(0, paste_y1)
actual_paste_x1 = max(0, paste_x1)
actual_paste_y2 = min(output_image_np.shape[0], paste_y1 + final_bbox_height)
actual_paste_x2 = min(output_image_np.shape[1], paste_x1 + final_bbox_width)
h_to_paste_in_original = actual_paste_y2 - actual_paste_y1
w_to_paste_in_original = actual_paste_x2 - actual_paste_x1
if h_to_paste_in_original > 0 and w_to_paste_in_original > 0 and \
generated_part_resized.shape[0] >= h_to_paste_in_original and \
generated_part_resized.shape[1] >= w_to_paste_in_original:
slice_from_generated_y = slice(0, h_to_paste_in_original)
slice_from_generated_x = slice(0, w_to_paste_in_original)
target_paste_slice_y = slice(actual_paste_y1, actual_paste_y2)
target_paste_slice_x = slice(actual_paste_x1, actual_paste_x2)
try:
output_image_np[target_paste_slice_y, target_paste_slice_x, :] = \
generated_part_resized[slice_from_generated_y, slice_from_generated_x, :]
except IndexError:
return (old_tar_image,)
else:
pass # Skip paste if no valid area or source data too small
output_image_tensor = torch.from_numpy(output_image_np.astype(np.float32) / 255.0).unsqueeze(0)
return (output_image_tensor,)
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long