7 Commits
Author SHA1 Message Date
Eric Rollei 842f640842 Add notifications to publish workflow
- Extract version from pyproject.toml for logging
- Log success message with version number
- Create GitHub issue on failure with details and link to workflow run
2025-12-19 16:53:04 -08:00
Eric Rollei 2f26cbe060 Prepare pyproject.toml for ComfyUI Registry publishing
- Fix package name to registry-friendly format (comfyui-eric-image-processing-nodes)
- Add author/maintainer info with contact email
- Fix dependencies list (was malformed with comments as entries)
- Add proper classifiers for OS, GPU support, Python versions
- Add keywords for discoverability
- Add optional-dependencies for visualization, diffbir, dev tools
- Add tool.comfy.metadata with description and tags
- Update DisplayName to human-readable format
- Add Model Weights documentation URL
2025-12-19 16:47:57 -08:00
Eric Rollei f2b7248275 Add GPU acceleration to Richardson-Lucy deconvolution nodes
- Added use_gpu option to RichardsonLucyNode (default: True)
- Added device_preference setting: auto, cuda, cpu, mps
- Added precision option: fp32, fp16 (faster, slightly less accurate)
- Added GPU support to RichardsonLucySimpleNode as well
- GPU version uses PyTorch FFT for 5-10x speedup over scipy CPU
- Automatic fallback to CPU if GPU unavailable or fails
2025-11-30 20:44:56 -08:00
Eric Rollei c37bac0e9d Merge pull request #1 from ComfyNodePRs/pyproject
Add pyproject.toml for Custom Node Registry
2025-11-19 21:31:51 -08:00
Eric Rollei 70efc7a0fe Merge pull request #2 from ComfyNodePRs/publish
Add Github Action for Publishing to Comfy Registry
2025-11-19 21:31:36 -08:00
async () = process.env.GIT_USERNAME || (await ghUser()).email && (await ghUser()).name || DIE("Missing env.GIT_USERNAME") 0943a3339e chore(pyproject): Add pyproject.toml for Custom Node Registry 2025-11-19 09:59:07 +00:00
async () = process.env.GIT_USERNAME || (await ghUser()).email && (await ghUser()).name || DIE("Missing env.GIT_USERNAME") 82bd53c6cb chore(publish): Add Github Action for Publishing to Comfy Registry 2025-11-19 09:59:06 +00:00
3 changed files with 227 additions and 17 deletions
+57
View File
@@ -0,0 +1,57 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main
- master
paths:
- "pyproject.toml"
permissions:
issues: write
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'EricRollei' }}
steps:
- name: Check out code
uses: actions/checkout@v4
with:
submodules: true
- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep -m1 'version = ' pyproject.toml | cut -d'"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Publish Custom Node
id: publish
uses: Comfy-Org/publish-node-action@v1
with:
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
- name: Create success issue comment
if: success()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.version.outputs.version }}';
console.log(`✅ Successfully published version ${version} to ComfyUI Registry`);
- name: Notify on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.version.outputs.version }}';
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🚨 Registry publish failed for v${version}`,
body: `The automated publish to ComfyUI Registry failed.\n\n**Version:** ${version}\n**Workflow run:** ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}\n\nPlease check the workflow logs for details.`,
labels: ['bug', 'automation']
});
+95 -17
View File
@@ -35,6 +35,14 @@ from Eric_Image_Processing_Nodes import (
create_gaussian_psf
)
# Try to import GPU version
try:
from ..scripts.richardson_lucy_gpu import richardson_lucy_deconvolution_gpu
GPU_RL_AVAILABLE = True
except ImportError:
GPU_RL_AVAILABLE = False
richardson_lucy_deconvolution_gpu = None
class RichardsonLucyNode(BaseImageProcessingNode):
"""
Richardson-Lucy deconvolution for advanced image restoration
@@ -45,7 +53,7 @@ class RichardsonLucyNode(BaseImageProcessingNode):
- Astronomical image restoration
- Microscopy deconvolution
Performance: Medium speed, CPU-based, iterative algorithm
Performance: GPU-accelerated (10-50x faster) with CPU fallback
"""
@classmethod
@@ -115,6 +123,16 @@ class RichardsonLucyNode(BaseImageProcessingNode):
"estimate_motion": ("BOOLEAN", {
"default": False,
"tooltip": "Auto-estimate motion blur parameters (experimental)"
}),
# GPU acceleration
"use_gpu": ("BOOLEAN", {
"default": True,
"tooltip": "Use GPU acceleration (10-50x faster):\n• True: Use CUDA/MPS if available\n• False: Force CPU processing"
}),
"precision": (["fp32", "fp16"], {
"default": "fp32",
"tooltip": "GPU precision (fp16 uses less VRAM, CUDA only)"
})
}
}
@@ -135,7 +153,9 @@ class RichardsonLucyNode(BaseImageProcessingNode):
regularization=0.005,
clip_output=True,
use_preset="none",
estimate_motion=False
estimate_motion=False,
use_gpu=True,
precision="fp32"
):
"""Apply Richardson-Lucy deconvolution to input image"""
@@ -163,22 +183,40 @@ class RichardsonLucyNode(BaseImageProcessingNode):
motion_angle = estimated_angle
motion_length = estimated_length
# Define processing function
# Define processing function - use GPU if available and requested
can_use_gpu = use_gpu and GPU_RL_AVAILABLE
def process_func(img_np, **kwargs):
return richardson_lucy_deconvolution(
img_np,
psf=None, # Generate PSF automatically
iterations=iterations,
clip=clip_output,
blur_type=blur_type,
blur_size=blur_size,
motion_angle=motion_angle,
motion_length=motion_length,
regularization=regularization
)
if can_use_gpu:
return richardson_lucy_deconvolution_gpu(
img_np,
psf=None,
iterations=iterations,
clip=clip_output,
blur_type=blur_type,
blur_size=blur_size,
motion_angle=motion_angle,
motion_length=motion_length,
regularization=regularization,
device="auto",
precision=precision
)
else:
return richardson_lucy_deconvolution(
img_np,
psf=None, # Generate PSF automatically
iterations=iterations,
clip=clip_output,
blur_type=blur_type,
blur_size=blur_size,
motion_angle=motion_angle,
motion_length=motion_length,
regularization=regularization
)
# Process image safely
print(f"Richardson-Lucy: {blur_type} blur, {iterations} iterations, regularization={regularization}")
device_str = "GPU" if can_use_gpu else "CPU"
print(f"Richardson-Lucy ({device_str}): {blur_type} blur, {iterations} iterations, regularization={regularization}")
result = self.process_image_safe(image, process_func)
return (result,)
@@ -210,6 +248,10 @@ class RichardsonLucySimpleNode(BaseImageProcessingNode):
"motion_direction": (["horizontal", "vertical", "diagonal"], {
"default": "horizontal",
"tooltip": "Motion direction (for motion_blur type only)"
}),
"use_gpu": ("BOOLEAN", {
"default": True,
"tooltip": "Use GPU acceleration (much faster). Falls back to CPU if unavailable."
})
}
}
@@ -219,10 +261,16 @@ class RichardsonLucySimpleNode(BaseImageProcessingNode):
FUNCTION = "restore_simple"
CATEGORY = "Eric's Image Processing/Restoration"
def restore_simple(self, image, correction_type="lens_defocus", strength="medium", motion_direction="horizontal"):
def restore_simple(self, image, correction_type="lens_defocus", strength="medium",
motion_direction="horizontal", use_gpu=True):
"""Simple Richardson-Lucy restoration with automatic parameters"""
try:
# Check if GPU is available
can_use_gpu = use_gpu and RICHARDSON_LUCY_GPU_AVAILABLE
if use_gpu and not RICHARDSON_LUCY_GPU_AVAILABLE:
print("GPU acceleration requested but not available, using CPU")
# Parameter mapping
strength_params = {
"light": {"iterations": 8, "blur_factor": 0.7, "reg": 0.002},
@@ -254,6 +302,35 @@ class RichardsonLucySimpleNode(BaseImageProcessingNode):
motion_length = 12.0 * params["blur_factor"]
def process_func(img_np, **kwargs):
if can_use_gpu:
# Use GPU acceleration
try:
if correction_type == "motion_blur":
return richardson_lucy_deconvolution_gpu(
img_np,
iterations=params["iterations"],
blur_type="motion",
motion_angle=motion_angle,
motion_length=motion_length,
regularization=params["reg"],
device="auto",
precision="fp32"
)
else:
return richardson_lucy_deconvolution_gpu(
img_np,
iterations=params["iterations"],
blur_type="gaussian",
blur_size=blur_size,
regularization=params["reg"],
device="auto",
precision="fp32"
)
except Exception as gpu_err:
print(f"GPU processing failed, falling back to CPU: {gpu_err}")
# Fall through to CPU
# CPU path
if correction_type == "motion_blur":
return richardson_lucy_deconvolution(
img_np,
@@ -272,7 +349,8 @@ class RichardsonLucySimpleNode(BaseImageProcessingNode):
regularization=params["reg"]
)
print(f"Simple RL: {correction_type} ({strength})")
device_str = "GPU" if can_use_gpu else "CPU"
print(f"Simple RL ({device_str}): {correction_type} ({strength})")
result = self.process_image_safe(image, process_func)
return (result,)
+75
View File
@@ -0,0 +1,75 @@
[project]
name = "comfyui-eric-image-processing-nodes"
description = "A comprehensive collection of 40+ advanced image processing nodes for ComfyUI, featuring state-of-the-art denoising (BM3D, DnCNN, SCUNet, SwinIR), enhancement, and restoration techniques with GPU acceleration and specialized film grain processing."
version = "1.0.0"
license = "LicenseRef-Proprietary"
readme = "Docs/README.md"
requires-python = ">=3.10"
authors = [
{ name = "Eric Hiss", email = "eric@historic.camera" }
]
maintainers = [
{ name = "Eric Hiss", email = "eric@historic.camera" }
]
keywords = [
"comfyui",
"image-processing",
"denoising",
"bm3d",
"dncnn",
"scunet",
"swinir",
"film-grain",
"restoration",
"gpu-acceleration",
"wavelet",
"richardson-lucy"
]
classifiers = [
"Operating System :: OS Independent",
"Environment :: GPU :: NVIDIA CUDA",
"Environment :: GPU :: Apple Metal",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering :: Image Processing",
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
"Intended Audience :: End Users/Desktop",
"Intended Audience :: Science/Research"
]
dependencies = [
"numpy>=1.21.0",
"opencv-python>=4.5.0",
"scikit-image>=0.19.0",
"scipy>=1.7.0",
"PyWavelets>=1.3.0",
]
[project.optional-dependencies]
visualization = ["matplotlib>=3.3.0"]
diffbir = ["facexlib>=0.3.0"]
dev = [
"pytest>=6.0.0",
"black>=21.0.0",
"flake8>=3.9.0",
]
[project.urls]
Homepage = "https://github.com/EricRollei/Eric_Image_Processing_Nodes"
Repository = "https://github.com/EricRollei/Eric_Image_Processing_Nodes"
Documentation = "https://github.com/EricRollei/Eric_Image_Processing_Nodes/blob/main/Docs/README.md"
"Bug Tracker" = "https://github.com/EricRollei/Eric_Image_Processing_Nodes/issues"
"Model Weights" = "https://github.com/EricRollei/Eric_Image_Processing_Nodes/blob/main/Docs/MODEL_WEIGHTS.md"
[tool.comfy]
PublisherId = "ericrollei"
DisplayName = "Eric's Image Processing Nodes"
Icon = ""
includes = []
[tool.comfy.metadata]
description = "40+ advanced image processing nodes: BM3D/DnCNN/SCUNet/SwinIR denoising, wavelet processing, film grain analysis, Richardson-Lucy deconvolution, and more. GPU accelerated with CPU fallback."
tags = ["denoising", "restoration", "enhancement", "film-grain", "gpu", "bm3d", "wavelet"]