121 lines
4.3 KiB
Markdown
121 lines
4.3 KiB
Markdown
|
|
# Documentation
|
|
- Class name: FL_PixelSort
|
|
- Category: 🏵️Fill Nodes
|
|
- Output node: False
|
|
- Repo Ref: https://github.com/fylipeclick/ClickFill
|
|
|
|
FL_PixelSort节点可以对图像应用像素排序效果,这种效果基于图像的色相值进行排序,从而实现对图像纹理的艺术化处理。该节点支持通过方向、阈值、平滑度和旋转等参数的自定义设置,以达到各种视觉效果。
|
|
|
|
# Input types
|
|
## Required
|
|
- images
|
|
- 需要处理的图像集合。这些图像将根据其色相值进行排序,从而实现创意性的重构和处理。
|
|
- Comfy dtype: IMAGE
|
|
- Python dtype: List[torch.Tensor]
|
|
## Optional
|
|
- direction
|
|
- 指定像素排序过程的方向,可选'Horizontal'(水平)或'Vertical'(垂直)。这会影响图像上排序效果的方向。
|
|
- Comfy dtype: COMBO[STRING]
|
|
- Python dtype: str
|
|
- threshold
|
|
- 决定触发排序所需的色相变化敏感度的值。较低的阈值会导致基于较小的色相差异进行更积极的排序。
|
|
- Comfy dtype: FLOAT
|
|
- Python dtype: float
|
|
- smoothing
|
|
- 控制已排序区域和未排序区域之间过渡的平滑度,值越高,过渡越平滑。
|
|
- Comfy dtype: FLOAT
|
|
- Python dtype: float
|
|
- rotation
|
|
- 在排序之前对图像应用旋转,可能的值表示90度旋转的次数。
|
|
- Comfy dtype: INT
|
|
- Python dtype: int
|
|
|
|
# Output types
|
|
- image
|
|
- 应用了像素排序效果的处理后图像,基于指定的参数进行处理。
|
|
- Comfy dtype: IMAGE
|
|
- Python dtype: torch.Tensor
|
|
|
|
|
|
## Usage tips
|
|
- Infra type: `GPU`
|
|
- Common nodes: unknown
|
|
|
|
|
|
## Source code
|
|
```python
|
|
class FL_PixelSort:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"images": ("IMAGE",),
|
|
},
|
|
"optional": {
|
|
"direction": (["Horizontal", "Vertical"],),
|
|
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"smoothing": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}),
|
|
"rotation": ("INT", {"default": 0, "min": 0, "max": 3, "step": 1}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "pixel_sort_hue"
|
|
CATEGORY = "🏵️Fill Nodes"
|
|
|
|
def t2p(self, t):
|
|
if t is not None:
|
|
i = 255.0 * t.cpu().numpy().squeeze()
|
|
p = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
|
return p
|
|
|
|
def hue(self, pixel):
|
|
r, g, b = pixel
|
|
h, _, _ = rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
|
|
return h
|
|
|
|
def pixel_sort_hue(self, images, direction="Horizontal", threshold=0.5, smoothing=0.1, rotation=0):
|
|
out = []
|
|
total_images = len(images)
|
|
for i, img in enumerate(images, start=1):
|
|
p = self.t2p(img)
|
|
sorted_image = self.sort_pixels(p, self.hue, threshold, smoothing, rotation)
|
|
o = np.array(sorted_image.convert("RGB")).astype(np.float32) / 255.0
|
|
o = torch.from_numpy(o).unsqueeze(0)
|
|
out.append(o)
|
|
|
|
# Print progress update
|
|
progress = i / total_images * 100
|
|
sys.stdout.write(f"\rProcessing images: {progress:.2f}%")
|
|
sys.stdout.flush()
|
|
|
|
# Print a new line after the progress update
|
|
print()
|
|
|
|
out = torch.cat(out, 0)
|
|
return (out,)
|
|
|
|
def sort_pixels(self, image, value, threshold, smoothing, rotation=0):
|
|
pixels = np.rot90(np.array(image), rotation)
|
|
values = np.apply_along_axis(value, 2, pixels)
|
|
edges = np.apply_along_axis(lambda row: np.convolve(row, [-1, 1], 'same'), 0, values > threshold)
|
|
edges = np.maximum(edges, 0)
|
|
edges = np.minimum(edges, 1)
|
|
edges = np.convolve(edges.flatten(), np.ones(int(smoothing * pixels.shape[1])), 'same').reshape(edges.shape)
|
|
intervals = [np.flatnonzero(row) for row in edges]
|
|
|
|
for row, key in enumerate(values):
|
|
order = np.split(key, intervals[row])
|
|
for index, interval in enumerate(order[1:]):
|
|
order[index + 1] = np.argsort(interval) + intervals[row][index]
|
|
order[0] = range(order[0].size)
|
|
order = np.concatenate(order)
|
|
|
|
for channel in range(3):
|
|
pixels[row, :, channel] = pixels[row, order.astype('uint32'), channel]
|
|
|
|
return Image.fromarray(np.rot90(pixels, -rotation))
|
|
|
|
```
|