Add ImageFilter module
This commit is contained in:
@@ -2,6 +2,7 @@ import json
|
||||
import os
|
||||
|
||||
import folder_paths
|
||||
import nodes
|
||||
|
||||
|
||||
class Loader:
|
||||
@@ -31,6 +32,15 @@ class Loader:
|
||||
if not os.path.exists(fonts_folder_path):
|
||||
os.mkdir(fonts_folder_path)
|
||||
|
||||
def setup_override(self):
|
||||
if self.config()["override"]["postprocessing"]:
|
||||
nodes.NODE_CLASS_MAPPINGS = dict(
|
||||
filter(
|
||||
lambda item: not item[1].CATEGORY.startswith("image/postprocessing"),
|
||||
nodes.NODE_CLASS_MAPPINGS.items()
|
||||
)
|
||||
)
|
||||
|
||||
def get_modules(self):
|
||||
modules = dict()
|
||||
|
||||
@@ -54,6 +64,10 @@ class Loader:
|
||||
from .modules import ImageDraw
|
||||
modules.update(ImageDraw.NODE_CLASS_MAPPINGS)
|
||||
|
||||
if self.config()["modules"]["ImageFilter"]:
|
||||
from .modules import ImageFilter
|
||||
modules.update(ImageFilter.NODE_CLASS_MAPPINGS)
|
||||
|
||||
if self.config()["modules"]["ImageSegmentation"]:
|
||||
from .modules import ImageSegmentation
|
||||
modules.update(ImageSegmentation.NODE_CLASS_MAPPINGS)
|
||||
|
||||
@@ -479,6 +479,136 @@ You also can change the fonts folder in config.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
### Image Filter
|
||||

|
||||
> Apply filter on images.
|
||||
|
||||
<details>
|
||||
<summary>Nodes:</summary>
|
||||
|
||||
`Warning` Some changes are difficult to notice without detailed consideration.You can load this [JSON](images/image_filter.json) and look at the changes in detail.
|
||||
|
||||
### Smooth
|
||||

|
||||
> Anti-Aliasing of image artifacts.
|
||||
|
||||
### SmoothMore
|
||||

|
||||
> Improved Anti-Aliasing of image artifacts.
|
||||
|
||||
### Blur
|
||||

|
||||
> Blurring the image.
|
||||
|
||||
### BoxBlur
|
||||

|
||||
> Blurring the image by box algorithm.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* radius `[0 - *]` - blurring radius.
|
||||
|
||||
</details>
|
||||
|
||||
### GaussianBlur
|
||||

|
||||
> Blurring the image by gaussian algorithm.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* radius `[0 - *]` - blurring radius.
|
||||
|
||||
</details>
|
||||
|
||||
### Contour
|
||||

|
||||
> Find the contours of the image.
|
||||
|
||||
### Detail
|
||||

|
||||
> Image detailing.
|
||||
|
||||
### EdgeEnhance
|
||||

|
||||
> Clarity of the image boundaries.
|
||||
|
||||
### EdgeEnhanceMore
|
||||

|
||||
> Improved clarity of image boundaries.
|
||||
|
||||
### Emboss
|
||||

|
||||
> Embossed image.
|
||||
|
||||
### FindEdges
|
||||

|
||||
> Identifies the boundaries of the image.
|
||||
|
||||
### Sharpen
|
||||

|
||||
> Sharpness improvement.
|
||||
|
||||
### Rank
|
||||

|
||||
> Rank filter sorts all pixels in a window of a given size.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* size `[0 - *]` - The size of the core in PX.
|
||||
* rank `[0 - *]` - Which pixel value to choose.
|
||||
|
||||
</details>
|
||||
|
||||
### Median
|
||||

|
||||
> Selects the average pixel value in a window of the specified size.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* size `[0 - *]` - The size of the core in PX.
|
||||
|
||||
</details>
|
||||
|
||||
### Min
|
||||

|
||||
> Selects the smallest pixel value in the window at the specified size.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* size `[0 - *]` - The size of the core in PX.
|
||||
|
||||
</details>
|
||||
|
||||
### Max
|
||||

|
||||
> Selects the largest pixel value in the window at the specified size.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* size `[0 - *]` - The size of the core in PX.
|
||||
|
||||
</details>
|
||||
|
||||
### Mode
|
||||

|
||||
> Selects the most common pixel value in a field of the specified size.
|
||||
|
||||
<details>
|
||||
<summary>Params:</summary>
|
||||
|
||||
* size `[0 - *]` - The size of the core in PX.
|
||||
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
### Clamp
|
||||

|
||||
@@ -507,8 +637,9 @@ You also can change the fonts folder in config.
|
||||
|
||||
## Configuration:
|
||||
You can configurate Allor with `config.json`.
|
||||
* `fonts_folder_path` - Array with a relative path to fonts folder, by default is `["comfy_extras", "fonts"]`. (Converted to `ComfyUI/comfy_extras/fonts` for Unix and `ComfyUI\comfy_extras\fonts` for Windows).
|
||||
* `modules` - You can disable (or enable) modules at will. Nodes from disabled modules will not be loaded during the start of ComfyUI.
|
||||
* fonts_folder_path - Array with a relative path to fonts folder, by default is `["comfy_extras", "fonts"]`. (Converted to `ComfyUI/comfy_extras/fonts` for Unix and `ComfyUI\comfy_extras\fonts` for Windows).
|
||||
* modules - You can disable (or enable) modules at will. Nodes from disabled modules will not be loaded during the start of ComfyUI.
|
||||
* override - If the nested value is set to `true`, similar functionality from the original nodes is disabled.
|
||||
|
||||
## Examples:
|
||||

|
||||
|
||||
@@ -5,5 +5,6 @@ loader = Loader()
|
||||
|
||||
loader.setup_rembg()
|
||||
loader.setup_paths()
|
||||
loader.setup_override()
|
||||
|
||||
NODE_CLASS_MAPPINGS = loader.get_modules()
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
"ImageComposite": true,
|
||||
"ImageContainer": true,
|
||||
"ImageDraw": true,
|
||||
"ImageFilter": true,
|
||||
"ImageSegmentation": true,
|
||||
"ImageText": true
|
||||
},
|
||||
"override" : {
|
||||
"postprocessing": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
import torch
|
||||
from PIL import ImageFilter
|
||||
|
||||
|
||||
def applyImageFilter(images, image_filter):
|
||||
return (torch.stack([
|
||||
images[i].tensor_to_image().filter(image_filter).image_to_tensor() for i in range(len(images))
|
||||
]),)
|
||||
|
||||
|
||||
class ImageFilterSmooth:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_smooth"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_smooth(self, images):
|
||||
return applyImageFilter(images, ImageFilter.SMOOTH)
|
||||
|
||||
|
||||
class ImageFilterSmoothMore:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_smooth_more"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_smooth_more(self, images):
|
||||
return applyImageFilter(images, ImageFilter.SMOOTH_MORE)
|
||||
|
||||
|
||||
class ImageFilterBlur:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_blur"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_blur(self, images):
|
||||
return applyImageFilter(images, ImageFilter.BLUR)
|
||||
|
||||
|
||||
class ImageFilterBoxBlur:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"radius": ("INT", {
|
||||
"default": 1,
|
||||
"step": 1
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_box_blur"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_box_blur(self, images, radius):
|
||||
return applyImageFilter(images, ImageFilter.BoxBlur(radius))
|
||||
|
||||
|
||||
class ImageFilterGaussianBlur:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"radius": ("INT", {
|
||||
"default": 1,
|
||||
"step": 1
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_gaussian_blur"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_gaussian_blur(self, images, radius):
|
||||
return applyImageFilter(images, ImageFilter.GaussianBlur(radius))
|
||||
|
||||
|
||||
class ImageFilterContour:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_contour"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_contour(self, images):
|
||||
return applyImageFilter(images, ImageFilter.CONTOUR)
|
||||
|
||||
|
||||
class ImageFilterDetail:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_detail"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_detail(self, images):
|
||||
return applyImageFilter(images, ImageFilter.DETAIL)
|
||||
|
||||
|
||||
class ImageFilterEdgeEnhance:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_edge_enhance"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_edge_enhance(self, images):
|
||||
return applyImageFilter(images, ImageFilter.EDGE_ENHANCE)
|
||||
|
||||
|
||||
class ImageFilterEdgeEnhanceMore:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_edge_enhance_more"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_edge_enhance_more(self, images):
|
||||
return applyImageFilter(images, ImageFilter.EDGE_ENHANCE_MORE)
|
||||
|
||||
|
||||
class ImageFilterEmboss:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_emboss"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_emboss(self, images):
|
||||
return applyImageFilter(images, ImageFilter.EMBOSS)
|
||||
|
||||
|
||||
class ImageFilterFindEdges:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_find_edges"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_find_edges(self, images):
|
||||
return applyImageFilter(images, ImageFilter.FIND_EDGES)
|
||||
|
||||
|
||||
class ImageFilterSharpen:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_sharpen"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_sharpen(self, images):
|
||||
return applyImageFilter(images, ImageFilter.SHARPEN)
|
||||
|
||||
|
||||
class ImageFilterRank:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"size": ("INT", {
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"step": 2
|
||||
}),
|
||||
"rank": ("INT", {
|
||||
"default": 1,
|
||||
"step": 1
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_rank"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_rank(self, images, size, rank):
|
||||
return applyImageFilter(images, ImageFilter.RankFilter(int(size) + 1, rank))
|
||||
|
||||
|
||||
class ImageFilterMedian:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"size": ("INT", {
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"step": 2
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_median"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_median(self, images, size):
|
||||
return applyImageFilter(images, ImageFilter.MedianFilter(int(size) + 1))
|
||||
|
||||
|
||||
class ImageFilterMin:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"size": ("INT", {
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"step": 2
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_min"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_min(self, images, size):
|
||||
return applyImageFilter(images, ImageFilter.MinFilter(int(size) + 1))
|
||||
|
||||
|
||||
class ImageFilterMax:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"size": ("INT", {
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"step": 2
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_max"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_max(self, images, size):
|
||||
return applyImageFilter(images, ImageFilter.MaxFilter(int(size) + 1))
|
||||
|
||||
|
||||
class ImageFilterMode:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE",),
|
||||
"size": ("INT", {
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"step": 2
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_filter_mode"
|
||||
CATEGORY = "image/filter"
|
||||
|
||||
def image_filter_mode(self, images, size):
|
||||
return applyImageFilter(images, ImageFilter.ModeFilter(int(size) + 1))
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ImageFilterSmooth": ImageFilterSmooth,
|
||||
"ImageFilterSmoothMore": ImageFilterSmoothMore,
|
||||
"ImageFilterBlur": ImageFilterBlur,
|
||||
"ImageFilterBoxBlur": ImageFilterBoxBlur,
|
||||
"ImageFilterGaussianBlur": ImageFilterGaussianBlur,
|
||||
"ImageFilterContour": ImageFilterContour,
|
||||
"ImageFilterDetail": ImageFilterDetail,
|
||||
"ImageFilterEdgeEnhance": ImageFilterEdgeEnhance,
|
||||
"ImageFilterEdgeEnhanceMore": ImageFilterEdgeEnhanceMore,
|
||||
"ImageFilterEmboss": ImageFilterEmboss,
|
||||
"ImageFilterFindEdges": ImageFilterFindEdges,
|
||||
"ImageFilterSharpen": ImageFilterSharpen,
|
||||
"ImageFilterRank": ImageFilterRank,
|
||||
"ImageFilterMedian": ImageFilterMedian,
|
||||
"ImageFilterMin": ImageFilterMin,
|
||||
"ImageFilterMax": ImageFilterMax,
|
||||
"ImageFilterMode": ImageFilterMode
|
||||
}
|
||||
Reference in New Issue
Block a user