init repo

This commit is contained in:
GW Wi
2023-11-09 12:01:53 +09:00
commit c9c761f3b9
2 changed files with 202 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
__pycache__/
.pytest_cache/
.tox/
.venv/
.vscode/
.vscode-test/
+196
View File
@@ -0,0 +1,196 @@
import numpy as np
from PIL import Image, ImageDraw
import torch
def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
# PIL to Tensor
def pil2tensor(image):
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
def crop_ndarray4(npimg, crop_region):
x1 = crop_region[0]
y1 = crop_region[1]
x2 = crop_region[2]
y2 = crop_region[3]
cropped = npimg[:, y1:y2, x1:x2, :]
return cropped
def crop_image(image, crop_region):
return crop_ndarray4(np.array(image), crop_region)
def empty_pil_tensor(w=64, h=64):
image = Image.new("RGB", (w, h))
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, w-1, h-1), fill=(0, 0, 0))
return pil2tensor(image)
class OFFCenterCrop:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
"""
Return a dictionary which contains config for all input fields.
Some types (string): "MODEL", "VAE", "CLIP", "CONDITIONING", "LATENT", "IMAGE", "INT", "STRING", "FLOAT".
Input types "INT", "STRING" or "FLOAT" are special values for fields on the node.
The type can be a list for selection.
Returns: `dict`:
- Key input_fields_group (`string`): Can be either required, hidden or optional. A node class must have property `required`
- Value input_fields (`dict`): Contains input fields config:
* Key field_name (`string`): Name of a entry-point method's argument
* Value field_config (`tuple`):
+ First value is a string indicate the type of field or a list for selection.
+ Secound value is a config for type "INT", "STRING" or "FLOAT".
"""
return {
"required": {
"image": ("IMAGE",)
},
}
RETURN_TYPES = ("IMAGE",)
# RETURN_NAMES = ("image_output_name",)
FUNCTION = "image_crop"
# OUTPUT_NODE = False
CATEGORY = "OFF"
# Tensor to PIL
def image_crop(self, image):
image = tensor2pil(image)
img_width, img_height = image.size
crop_size = img_width
if img_width > img_height:
crop_size = img_height
top = (img_height - crop_size)/2
left = (img_width - crop_size)/2
bottom = top + crop_size
right = left + crop_size
# Calculate the final coordinates for cropping
crop_top = max(top, 0)
crop_left = max(left, 0)
crop_bottom = min(bottom, img_height)
crop_right = min(right, img_width)
# Ensure that the cropping region has non-zero width and height
crop_width = crop_right - crop_left
crop_height = crop_bottom - crop_top
if crop_width <= 0 or crop_height <= 0:
raise ValueError(
"Invalid crop dimensions. Please check the values for top, left, right, and bottom.")
# Crop the image and resize
crop = image.crop((crop_left, crop_top, crop_right, crop_bottom))
crop = crop.resize(
(((crop.size[0] // 8) * 8), ((crop.size[1] // 8) * 8)))
return (pil2tensor(crop),)
class OFFSEGSToImage:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"segs": ("SEGS", ),
},
"optional": {
"fallback_image_opt": ("IMAGE", ),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "doit"
CATEGORY = "OFF"
def doit(self, segs, fallback_image_opt=None):
results = list()
for seg in segs[1]:
if seg.cropped_image is not None:
cropped_image = torch.from_numpy(seg.cropped_image)
elif fallback_image_opt is not None:
# take from original image
cropped_image = torch.from_numpy(
crop_image(fallback_image_opt, seg.crop_region))
else:
cropped_image = empty_pil_tensor()
results.append(cropped_image)
if len(results) == 0:
results.append(empty_pil_tensor())
return (results[0],)
class GWNumFormatter:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_number": ("INT", {
"default": 0,
"min": 0, # Minimum value
"max": 100000000, # Maximum value
}),
"width": ("INT", {
"default": 3,
"min": 0,
"max": 10,
})
},
}
RETURN_TYPES = ("STRING",)
# RETURN_NAMES = ("image_output_name",)
FUNCTION = "format"
# OUTPUT_NODE = False
CATEGORY = "GW"
def format(self, input_number, width):
return (f"%0{width}d" % (input_number),)
# A dictionary that contains all nodes you want to export with their names
# NOTE: names should be globally unique
NODE_CLASS_MAPPINGS = {
"Image Crop Fit": OFFCenterCrop,
"OFF SEGS to Image": OFFSEGSToImage,
"GW Number Formatting": GWNumFormatter
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"Image Crop Fit": "Image Crop Fit Node",
"OFF SEGS to Image": "OFF SEGS to Image",
"GW Number Formatting": "GW Number Formatting Node"
}