6 Commits
5 changed files with 146 additions and 14 deletions
+5
View File
@@ -1,5 +1,10 @@
# ComfyUI-NegiTools
> [!IMPORTANT]
> "Depth Estimation by Marigold (experimental)" module is not maintained and will be discontinued in the future;
> if you would like to continue using Marigold, please consider using this alternative choice.
> https://github.com/kijai/ComfyUI-Marigold
## Installation
- Install dependencies: pip install -r requirements.txt
+3
View File
@@ -10,6 +10,7 @@ from .negi.point_list_to_mask import PointListToMask
from .negi.depth_estimation_by_marigold import DepthEstimationByMarigold
from .negi.stereo_image_generator import StereoImageGenerator
from .negi.image_reader_writer import RandomImageLoader, SaveImageToDirectory
from .negi.detect_face_rotation_for_inpainting import DetectFaceRotationForInpainting
NODE_CLASS_MAPPINGS = {
"NegiTools_OpenAiDalle3": OpenAiDalle3,
@@ -26,6 +27,7 @@ NODE_CLASS_MAPPINGS = {
"NegiTools_StereoImageGenerator": StereoImageGenerator,
"NegiTools_RandomImageLoader": RandomImageLoader,
"NegiTools_SaveImageToDirectory": SaveImageToDirectory,
"NegiTools_DetectFaceRotationForInpainting": DetectFaceRotationForInpainting,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -43,4 +45,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"NegiTools_StereoImageGenerator": "Stereo Image Generator 🧅",
"NegiTools_RandomImageLoader": "Random Image Loader 🧅",
"NegiTools_SaveImageToDirectory": "Save Image to Directory 🧅",
"NegiTools_DetectFaceRotationForInpainting": "Detect Face Rotation for Inpainting 🧅",
}
+118
View File
@@ -0,0 +1,118 @@
import json
import numpy as np
import torch
class DetectFaceRotationForInpainting:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"parts": ("STRING", {"multiline": False, "default": ""}),
"image": ("IMAGE",),
"radius_scale": ("FLOAT", {
"default": 1.0,
"min": 0.1,
"max": 5.0,
"step": 0.01,
"round": 0.001,
"display": "number"
}),
"overwrite_rotation": (["None", "0", "90", "180", "270"],),
}
}
RETURN_TYPES = ("INT", "MASK", "INT")
RETURN_NAMES = ("ROTATION_INV", "MASK", "ROTATION")
FUNCTION = "doit"
OUTPUT_NODE = False
CATEGORY = "utils"
@staticmethod
def get_face(xw, yw, radius_scale, parts):
x = 0.0
y = 0.0
n = 0
radius = 0
rot = 0
for name in ["Nose", "REye", "LEye", "REar", "LEar"]:
if name in parts:
x += parts[name]["x"]
y += parts[name]["y"]
n += 1
if n != 0:
x = x / n
y = y / n
for name in ["Nose", "REye", "LEye", "REar", "LEar"]:
if name in parts:
x0 = x * xw
y0 = y * yw
x1 = parts[name]["x"] * xw
y1 = parts[name]["y"] * yw
radius = max(radius, int(np.sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)) * radius_scale))
if n != 0 and "Neck" in parts:
x0 = x * xw
y0 = y * yw
x1 = parts["Neck"]["x"] * xw
y1 = parts["Neck"]["y"] * yw
if abs(x1 - x0) < abs(y1 - y0):
rot = 0 if y0 < y1 else 180
else:
rot = 90 if x0 < x1 else 270
return x, y, radius, rot
@staticmethod
def rotate(rot, x, y):
if rot == 0:
return x, y
if rot == 90:
return y, 1 - x
if rot == 180:
return 1 - x, 1 - y
if rot == 270:
return 1 - y, x
def doit(self, parts, image, radius_scale, overwrite_rotation):
parts_list = json.loads(parts)
xw = image.shape[2]
yw = image.shape[1]
x = 0.0
y = 0.0
radius = 0
rot = 0
for parts in parts_list:
t_x, t_y, t_radius, t_rot = self.get_face(xw, yw, radius_scale, parts)
if t_radius > radius:
x = t_x
y = t_y
radius = t_radius
rot = t_rot
if overwrite_rotation != "None":
rot = int(overwrite_rotation)
rot_inv = (0 if rot == 0 else 360 - rot)
x_r, y_r = self.rotate(rot_inv, x, y)
xw_r = (xw if rot == 0 or rot == 180 else yw)
yw_r = (yw if rot == 0 or rot == 180 else xw)
if radius == 0:
return rot_inv, torch.from_numpy(np.zeros((1, yw_r, xw_r), dtype=np.float32)), rot
px = (np.reshape(np.arange(xw_r, dtype=np.float32), (1, -1))
* np.ones((yw_r, 1), dtype=np.float32))
py = (np.reshape(np.arange(yw_r, dtype=np.float32), (-1, 1))
* np.ones((1, xw_r), dtype=np.float32))
d2 = np.power(px - x_r * xw_r, 2.0) + np.power(py - y_r * yw_r, 2.0)
mask = torch.from_numpy(np.reshape(d2 <= radius * radius, (1, yw_r, xw_r)).astype(np.float32))
return rot_inv, mask, rot
@@ -1,18 +1,18 @@
__version__ = "0.0.7"
from .hed import HEDdetector
from .leres import LeresDetector
from .lineart import LineartDetector
from .lineart_anime import LineartAnimeDetector
from .midas import MidasDetector
from .mlsd import MLSDdetector
from .normalbae import NormalBaeDetector
# from .hed import HEDdetector
# from .leres import LeresDetector
# from .lineart import LineartDetector
# from .lineart_anime import LineartAnimeDetector
# from .midas import MidasDetector
# from .mlsd import MLSDdetector
# from .normalbae import NormalBaeDetector
from .open_pose import OpenposeDetector
from .pidi import PidiNetDetector
from .zoe import ZoeDetector
# from .pidi import PidiNetDetector
# from .zoe import ZoeDetector
from .canny import CannyDetector
from .mediapipe_face import MediapipeFaceDetector
from .segment_anything import SamDetector
from .shuffle import ContentShuffleDetector
from .dwpose import DWposeDetector
# from .canny import CannyDetector
# from .mediapipe_face import MediapipeFaceDetector
# from .segment_anything import SamDetector
# from .shuffle import ContentShuffleDetector
# from .dwpose import DWposeDetector
+6
View File
@@ -1,3 +1,9 @@
openai >= 1.3.0
# controlnet-aux >= 0.0.7
numba >= 0.58.1
opencv-python >= 4.8.1.78
# required from controlnet_aux
huggingface-hub >= 0.19.3
scipy >= 1.11.3
scikit-image >= 0.20.0