Skip to content

Commit 8ad38d2

Browse files
jtydhr88Kosinkadinkchristian-byrne
authored
BBox widget (Comfy-Org#11594)
* Boundingbox widget * code improve --------- Co-authored-by: Jedrzej Kosinski <kosinkadink1@gmail.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org>
1 parent 6c14f12 commit 8ad38d2

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

comfy_api/latest/_io.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,30 @@ def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str
12091209
def as_dict(self):
12101210
return super().as_dict()
12111211

1212+
@comfytype(io_type="BOUNDING_BOX")
1213+
class BoundingBox(ComfyTypeIO):
1214+
class BoundingBoxDict(TypedDict):
1215+
x: int
1216+
y: int
1217+
width: int
1218+
height: int
1219+
Type = BoundingBoxDict
1220+
1221+
class Input(WidgetInput):
1222+
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None,
1223+
socketless: bool=True, default: dict=None, component: str=None):
1224+
super().__init__(id, display_name, optional, tooltip, None, default, socketless)
1225+
self.component = component
1226+
if default is None:
1227+
self.default = {"x": 0, "y": 0, "width": 512, "height": 512}
1228+
1229+
def as_dict(self):
1230+
d = super().as_dict()
1231+
if self.component:
1232+
d["component"] = self.component
1233+
return d
1234+
1235+
12121236
DYNAMIC_INPUT_LOOKUP: dict[str, Callable[[dict[str, Any], dict[str, Any], tuple[str, dict[str, Any]], str, list[str] | None], None]] = {}
12131237
def register_dynamic_input_func(io_type: str, func: Callable[[dict[str, Any], dict[str, Any], tuple[str, dict[str, Any]], str, list[str] | None], None]):
12141238
DYNAMIC_INPUT_LOOKUP[io_type] = func
@@ -2190,5 +2214,6 @@ def as_dict(self):
21902214
"ImageCompare",
21912215
"PriceBadgeDepends",
21922216
"PriceBadge",
2217+
"BoundingBox",
21932218
"NodeReplace",
21942219
]

comfy_extras/nodes_images.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ def define_schema(cls):
2323
return IO.Schema(
2424
node_id="ImageCrop",
2525
search_aliases=["trim"],
26-
display_name="Image Crop",
26+
display_name="Image Crop (Deprecated)",
2727
category="image/transform",
28+
is_deprecated=True,
2829
inputs=[
2930
IO.Image.Input("image"),
3031
IO.Int.Input("width", default=512, min=1, max=nodes.MAX_RESOLUTION, step=1),
@@ -47,6 +48,57 @@ def execute(cls, image, width, height, x, y) -> IO.NodeOutput:
4748
crop = execute # TODO: remove
4849

4950

51+
class ImageCropV2(IO.ComfyNode):
52+
@classmethod
53+
def define_schema(cls):
54+
return IO.Schema(
55+
node_id="ImageCropV2",
56+
search_aliases=["trim"],
57+
display_name="Image Crop",
58+
category="image/transform",
59+
inputs=[
60+
IO.Image.Input("image"),
61+
IO.BoundingBox.Input("crop_region", component="ImageCrop"),
62+
],
63+
outputs=[IO.Image.Output()],
64+
)
65+
66+
@classmethod
67+
def execute(cls, image, crop_region) -> IO.NodeOutput:
68+
x = crop_region.get("x", 0)
69+
y = crop_region.get("y", 0)
70+
width = crop_region.get("width", 512)
71+
height = crop_region.get("height", 512)
72+
73+
x = min(x, image.shape[2] - 1)
74+
y = min(y, image.shape[1] - 1)
75+
to_x = width + x
76+
to_y = height + y
77+
img = image[:,y:to_y, x:to_x, :]
78+
return IO.NodeOutput(img, ui=UI.PreviewImage(img))
79+
80+
81+
class BoundingBox(IO.ComfyNode):
82+
@classmethod
83+
def define_schema(cls):
84+
return IO.Schema(
85+
node_id="PrimitiveBoundingBox",
86+
display_name="Bounding Box",
87+
category="utils/primitive",
88+
inputs=[
89+
IO.Int.Input("x", default=0, min=0, max=MAX_RESOLUTION),
90+
IO.Int.Input("y", default=0, min=0, max=MAX_RESOLUTION),
91+
IO.Int.Input("width", default=512, min=1, max=MAX_RESOLUTION),
92+
IO.Int.Input("height", default=512, min=1, max=MAX_RESOLUTION),
93+
],
94+
outputs=[IO.BoundingBox.Output()],
95+
)
96+
97+
@classmethod
98+
def execute(cls, x, y, width, height) -> IO.NodeOutput:
99+
return IO.NodeOutput({"x": x, "y": y, "width": width, "height": height})
100+
101+
50102
class RepeatImageBatch(IO.ComfyNode):
51103
@classmethod
52104
def define_schema(cls):
@@ -632,6 +684,8 @@ class ImagesExtension(ComfyExtension):
632684
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
633685
return [
634686
ImageCrop,
687+
ImageCropV2,
688+
BoundingBox,
635689
RepeatImageBatch,
636690
ImageFromBatch,
637691
ImageAddNoise,

0 commit comments

Comments
 (0)