1
1
import torch
2
2
import comfy .model_management
3
+ from typing_extensions import override
4
+ from comfy_api .latest import ComfyExtension , io
3
5
4
6
from kornia .morphology import dilation , erosion , opening , closing , gradient , top_hat , bottom_hat
5
7
import kornia .color
6
8
7
9
8
- class Morphology :
10
+ class Morphology ( io . ComfyNode ) :
9
11
@classmethod
10
- def INPUT_TYPES (s ):
11
- return {"required" : {"image" : ("IMAGE" ,),
12
- "operation" : (["erode" , "dilate" , "open" , "close" , "gradient" , "bottom_hat" , "top_hat" ],),
13
- "kernel_size" : ("INT" , {"default" : 3 , "min" : 3 , "max" : 999 , "step" : 1 }),
14
- }}
12
+ def define_schema (cls ):
13
+ return io .Schema (
14
+ node_id = "Morphology" ,
15
+ display_name = "ImageMorphology" ,
16
+ category = "image/postprocessing" ,
17
+ inputs = [
18
+ io .Image .Input ("image" ),
19
+ io .Combo .Input (
20
+ "operation" ,
21
+ options = ["erode" , "dilate" , "open" , "close" , "gradient" , "bottom_hat" , "top_hat" ],
22
+ ),
23
+ io .Int .Input ("kernel_size" , default = 3 , min = 3 , max = 999 , step = 1 ),
24
+ ],
25
+ outputs = [
26
+ io .Image .Output (),
27
+ ],
28
+ )
15
29
16
- RETURN_TYPES = ("IMAGE" ,)
17
- FUNCTION = "process"
18
-
19
- CATEGORY = "image/postprocessing"
20
-
21
- def process (self , image , operation , kernel_size ):
30
+ @classmethod
31
+ def execute (cls , image , operation , kernel_size ) -> io .NodeOutput :
22
32
device = comfy .model_management .get_torch_device ()
23
33
kernel = torch .ones (kernel_size , kernel_size , device = device )
24
34
image_k = image .to (device ).movedim (- 1 , 1 )
@@ -39,49 +49,63 @@ def process(self, image, operation, kernel_size):
39
49
else :
40
50
raise ValueError (f"Invalid operation { operation } for morphology. Must be one of 'erode', 'dilate', 'open', 'close', 'gradient', 'tophat', 'bottomhat'" )
41
51
img_out = output .to (comfy .model_management .intermediate_device ()).movedim (1 , - 1 )
42
- return (img_out , )
52
+ return io . NodeOutput (img_out )
43
53
44
54
45
- class ImageRGBToYUV :
55
+ class ImageRGBToYUV ( io . ComfyNode ) :
46
56
@classmethod
47
- def INPUT_TYPES (s ):
48
- return {"required" : { "image" : ("IMAGE" ,),
49
- }}
57
+ def define_schema (cls ):
58
+ return io .Schema (
59
+ node_id = "ImageRGBToYUV" ,
60
+ category = "image/batch" ,
61
+ inputs = [
62
+ io .Image .Input ("image" ),
63
+ ],
64
+ outputs = [
65
+ io .Image .Output (display_name = "Y" ),
66
+ io .Image .Output (display_name = "U" ),
67
+ io .Image .Output (display_name = "V" ),
68
+ ],
69
+ )
50
70
51
- RETURN_TYPES = ("IMAGE" , "IMAGE" , "IMAGE" )
52
- RETURN_NAMES = ("Y" , "U" , "V" )
53
- FUNCTION = "execute"
54
-
55
- CATEGORY = "image/batch"
56
-
57
- def execute (self , image ):
71
+ @classmethod
72
+ def execute (cls , image ) -> io .NodeOutput :
58
73
out = kornia .color .rgb_to_ycbcr (image .movedim (- 1 , 1 )).movedim (1 , - 1 )
59
- return (out [..., 0 :1 ].expand_as (image ), out [..., 1 :2 ].expand_as (image ), out [..., 2 :3 ].expand_as (image ))
74
+ return io . NodeOutput (out [..., 0 :1 ].expand_as (image ), out [..., 1 :2 ].expand_as (image ), out [..., 2 :3 ].expand_as (image ))
60
75
61
- class ImageYUVToRGB :
76
+ class ImageYUVToRGB ( io . ComfyNode ) :
62
77
@classmethod
63
- def INPUT_TYPES (s ):
64
- return {"required" : {"Y" : ("IMAGE" ,),
65
- "U" : ("IMAGE" ,),
66
- "V" : ("IMAGE" ,),
67
- }}
78
+ def define_schema (cls ):
79
+ return io .Schema (
80
+ node_id = "ImageYUVToRGB" ,
81
+ category = "image/batch" ,
82
+ inputs = [
83
+ io .Image .Input ("Y" ),
84
+ io .Image .Input ("U" ),
85
+ io .Image .Input ("V" ),
86
+ ],
87
+ outputs = [
88
+ io .Image .Output (),
89
+ ],
90
+ )
68
91
69
- RETURN_TYPES = ("IMAGE" ,)
70
- FUNCTION = "execute"
71
-
72
- CATEGORY = "image/batch"
73
-
74
- def execute (self , Y , U , V ):
92
+ @classmethod
93
+ def execute (cls , Y , U , V ) -> io .NodeOutput :
75
94
image = torch .cat ([torch .mean (Y , dim = - 1 , keepdim = True ), torch .mean (U , dim = - 1 , keepdim = True ), torch .mean (V , dim = - 1 , keepdim = True )], dim = - 1 )
76
95
out = kornia .color .ycbcr_to_rgb (image .movedim (- 1 , 1 )).movedim (1 , - 1 )
77
- return (out ,)
96
+ return io .NodeOutput (out )
97
+
98
+
99
+ class MorphologyExtension (ComfyExtension ):
100
+ @override
101
+ async def get_node_list (self ) -> list [type [io .ComfyNode ]]:
102
+ return [
103
+ Morphology ,
104
+ ImageRGBToYUV ,
105
+ ImageYUVToRGB ,
106
+ ]
107
+
78
108
79
- NODE_CLASS_MAPPINGS = {
80
- "Morphology" : Morphology ,
81
- "ImageRGBToYUV" : ImageRGBToYUV ,
82
- "ImageYUVToRGB" : ImageYUVToRGB ,
83
- }
109
+ async def comfy_entrypoint () -> MorphologyExtension :
110
+ return MorphologyExtension ()
84
111
85
- NODE_DISPLAY_NAME_MAPPINGS = {
86
- "Morphology" : "ImageMorphology" ,
87
- }
0 commit comments