171 lines
4.6 KiB
Python
171 lines
4.6 KiB
Python
import torch
|
|
import os
|
|
import sys
|
|
|
|
import numpy as np
|
|
import cv2
|
|
from cv2.ximgproc import guidedFilter
|
|
import copy
|
|
|
|
|
|
class EnhanceDetail:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"images": ("IMAGE",),
|
|
"filter_radius": ("INT", {
|
|
"default": 2,
|
|
"min": 1,
|
|
"max": 64,
|
|
"step": 1
|
|
}),
|
|
"sigma": ("FLOAT", {
|
|
"default": 0.1,
|
|
"min": 0.01,
|
|
"max": 100.0,
|
|
"step": 0.01
|
|
}),
|
|
"denoise": ("FLOAT", {
|
|
"default": 0.1,
|
|
"min": 0.0,
|
|
"max": 10.0,
|
|
"step": 0.01
|
|
}),
|
|
"detail_mult": ("FLOAT", {
|
|
"default": 2.0,
|
|
"min": 0.0,
|
|
"max": 100.0,
|
|
"step": 0.1
|
|
}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "enhance"
|
|
|
|
CATEGORY = "image/filters"
|
|
|
|
def enhance(self, images: torch.Tensor, filter_radius: int, sigma: float, denoise: float, detail_mult: float):
|
|
|
|
if filter_radius == 0:
|
|
return (images,)
|
|
|
|
d = filter_radius * 2 + 1
|
|
s = sigma / 10
|
|
n = denoise / 10
|
|
|
|
dup = copy.deepcopy(images.cpu().numpy())
|
|
|
|
for i in range(len(dup)):
|
|
image = dup[i]
|
|
imgB = image
|
|
if denoise>0.0:
|
|
imgB = cv2.bilateralFilter(image, d, n, d)
|
|
|
|
imgG = guidedFilter(image, image, d, s)
|
|
|
|
details = (imgB/imgG - 1) * detail_mult + 1
|
|
dup[i] = details*imgG - imgB + image
|
|
|
|
return (torch.from_numpy(dup),)
|
|
|
|
class GuidedFilterAlpha:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE",),
|
|
"alpha": ("IMAGE",),
|
|
"filter_radius": ("INT", {
|
|
"default": 8,
|
|
"min": 1,
|
|
"max": 64,
|
|
"step": 1
|
|
}),
|
|
"sigma": ("FLOAT", {
|
|
"default": 0.1,
|
|
"min": 0.01,
|
|
"max": 1.0,
|
|
"step": 0.01
|
|
}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "guided_filter_alpha"
|
|
|
|
CATEGORY = "image/filters"
|
|
|
|
def guided_filter_alpha(self, image: torch.Tensor, alpha: torch.Tensor, filter_radius: int, sigma: float):
|
|
|
|
d = filter_radius * 2 + 1
|
|
s = sigma / 10
|
|
|
|
i_dup = copy.deepcopy(image.cpu().numpy())
|
|
a_dup = copy.deepcopy(alpha.cpu().numpy())
|
|
|
|
for i in range(len(i_dup)):
|
|
image_work = i_dup[i]
|
|
alpha_work = a_dup[i]
|
|
i_dup[i] = guidedFilter(image_work, alpha_work, d, s)
|
|
|
|
return (torch.from_numpy(i_dup),)
|
|
|
|
class RemapRange:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE",),
|
|
"blackpoint": ("FLOAT", {
|
|
"default": 0.0,
|
|
"min": 0.0,
|
|
"max": 1.0,
|
|
"step": 0.01
|
|
}),
|
|
"whitepoint": ("FLOAT", {
|
|
"default": 1.0,
|
|
"min": 0.01,
|
|
"max": 1.0,
|
|
"step": 0.01
|
|
}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "remap"
|
|
|
|
CATEGORY = "image/filters"
|
|
|
|
def remap(self, image: torch.Tensor, blackpoint: float, whitepoint: float):
|
|
|
|
bp = min(blackpoint, whitepoint - 0.001)
|
|
scale = 1 / (whitepoint - bp)
|
|
|
|
i_dup = copy.deepcopy(image.cpu().numpy())
|
|
i_dup = np.clip((i_dup - bp) * scale, 0.0, 1.0)
|
|
|
|
return (torch.from_numpy(i_dup),)
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"EnhanceDetail": EnhanceDetail,
|
|
"GuidedFilterAlpha": GuidedFilterAlpha,
|
|
"RemapRange": RemapRange,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"EnhanceDetail": "Enhance Detail",
|
|
"GuidedFilterAlpha": "Guided Filter Alpha",
|
|
"RemapRange": "Remap Range",
|
|
} |