diff --git a/README.MD b/README.MD index c30a588..b30374c 100644 --- a/README.MD +++ b/README.MD @@ -70,7 +70,7 @@ When this error has occurred, please check the network environment. ## Update **If the dependency package error after updating, please reinstall the relevant dependency packages.
- +* Commit [Levels](#Levels) node, it can achieve the same color levels adjustment function as Photoshop.[Sharp&Soft](#Sharp) add the "None" option. * Commit [BlendIfMask](#BlendIfMask) node, This node cooperates with ImgaeBlendV2 or ImageBlendAdvanceV2 to achieve the same Blend If function as Photoshop. * Commit [ColorTemperature](#ColorTemperature) and [ColorBalance](#ColorBalance) nodes, used to adjust the color temperature and color balance of the picture. * Add new types of [Blend Mode V2](#BlendModeV2) between images. now supports up to 30 blend modes. The new blend mode is available for all V2 versions that support mixed mode nodes, including ImageBlend V2, ImageBlendAdvance V2, DropShadow V2, InnerShadow V2, OuterGlow V2, InnerGlow V2, Stroke V2, ColorOverlay V2, GradientOverlay V2. @@ -373,6 +373,20 @@ Node Options: ![image](image/color_temperature_node.png) * temperature: Color temperature value. Range between-100 and 100. The higher the value, the higher the color temperature (bluer); The lower the color temperature, the lower the color temperature (yellowish). +### Levels +![image](image/levels_example.png) +Change the levels of image. + +Node Options: +![image](image/levels_node.png) +* channel: Select the channel you want to adjust. Available in RGB, red, green, blue. +* black_point: Input black point value. Value range 0-255, default 0. +* white_point: Input white point value. Value range 0-255, default 255. +* gray_point: Input grey point values. Value range 0.01-9.99, default 1. +* output_black_point: Output black point value. Value range 0-255, default 0. +* output_white_point: Output white point value. Value range 0-255, default 255. + + ### ColorBalance ![image](image/color_balance_example.png) Change the color balance of an image. @@ -1357,7 +1371,7 @@ Enhance or smooth out details for image. Node options: ![image](image/sharp_and_soft_node.png) -* enhance: Provide 4 presets, which are very sharp, sharp, soft and very soft. +* enhance: Provide 4 presets, which are very sharp, sharp, soft and very soft. If you choose None, you will not do any processing. ### SkinBeauty Make the skin look smoother. diff --git a/README_CN.MD b/README_CN.MD index 72e73cf..fdb53ae 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -70,6 +70,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git ## 更新说明 **如果本插件更新后出现依赖包错误,请重新安装相关依赖包。 +* 添加 [Levels](#Levels) 节点, 可以实现与Photoshop相同的色阶调整功能。[Sharp&Soft](#Sharp)增加"None"选项。 * 添加 [BlendIfMask](#BlendIfMask) 节点,该节点与 ImgaeBlendV2 或者 ImageBlendAdvanceV2 配合,可以实现与Photoshop相同的混合颜色带功能。 * 添加 [ColorTemperature](#ColorTemperature) 和 [ColorBalance](#ColorBalance) 节点,用于调整图片色温和色彩平衡。 * 更新 [混合模式](#混合模式)到V2版本,现在支持多达30种混合模式。新增的混合模式适用于所有支持混合模式节点的V2版本,包括ImageBlend V2, ImageBlendAdvance V2, DropShadow V2, InnerShadow V2, OuterGlow V2, InnerGlow V2, Stroke V2, ColorOverlay V2, GradientOverlay V2。 @@ -376,6 +377,19 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git * magenta_green: 品-绿平衡。负值为偏品,正值为偏绿。 * yellow_blue: 黄-蓝平衡。负值为偏黄,正值为偏蓝。 +### Levels +![image](image/levels_example.png) +改变图像色阶。 + +节点选项说明: +![image](image/levels_node.png) +* channel: 选择要调整的通道。有RGB, red, green, blue可供选择。 +* black_point: 图像输入黑点值。取值范围0-255, 默认值0。 +* white_point: 图像输入白点值。取值范围0-255, 默认值255。 +* gray_point: 图像输入灰点值。取值范围0.01-9.99, 默认1。 +* output_black_point: 图像输出黑点值。取值范围0-255, 默认值0。 +* output_white_point: 图像输出黑点值。取值范围0-255, 默认值255。 + ### Gamma 改变图像的Gamma值。 @@ -1352,7 +1366,7 @@ mask反转 节点选项说明: ![image](image/sharp_and_soft_node.png) -* enhance: 提供四个预设档位,分别是very sharp、sharp、soft和very soft。 +* enhance: 提供四个预设档位,分别是very sharp、sharp、soft和very soft。选None则不做任何处理。 ### SkinBeauty 磨皮效果。 diff --git a/image/levels_example.png b/image/levels_example.png new file mode 100644 index 0000000..3a9ee63 Binary files /dev/null and b/image/levels_example.png differ diff --git a/image/levels_node.png b/image/levels_node.png new file mode 100644 index 0000000..871dfc8 Binary files /dev/null and b/image/levels_node.png differ diff --git a/py/color_correct_levels.py b/py/color_correct_levels.py new file mode 100644 index 0000000..49a1699 --- /dev/null +++ b/py/color_correct_levels.py @@ -0,0 +1,90 @@ +from .imagefunc import * + + +NODE_NAME = 'Levels' + +class ColorCorrectLevels: + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(self): + channel_list = ["RGB", "red", "green", "blue"] + return { + "required": { + "image": ("IMAGE", ), # + "channel": (channel_list,), + "black_point": ("INT", {"default": 0, "min": 0, "max": 255, "step": 1}), + "white_point": ("INT", {"default": 255, "min": 0, "max": 255, "step": 1}), + "gray_point": ("FLOAT", {"default": 1, "min": 0.01, "max": 9.99, "step": 0.01}), + "output_black_point": ("INT", {"default": 0, "min": 0, "max": 255, "step": 1}), + "output_white_point": ("INT", {"default": 255, "min": 0, "max": 255, "step": 1}), + }, + "optional": { + } + } + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image",) + FUNCTION = 'levels' + CATEGORY = '😺dzNodes/LayerColor' + + def levels(self, image, channel, + black_point, white_point, + gray_point, output_black_point, output_white_point): + + l_images = [] + l_masks = [] + ret_images = [] + + for l in image: + l_images.append(torch.unsqueeze(l, 0)) + m = tensor2pil(l) + if m.mode == 'RGBA': + l_masks.append(m.split()[-1]) + else: + l_masks.append(Image.new('L', m.size, 'white')) + + + for i in range(len(l_images)): + _image = l_images[i] + _mask = l_masks[i] + orig_image = tensor2pil(_image) + + + if channel == "red": + r, g, b, _ = image_channel_split(orig_image, 'RGB') + r = adjust_levels(r, black_point, white_point, gray_point, + output_black_point, output_white_point) + ret_image = image_channel_merge((r.convert('L'), g, b), 'RGB') + elif channel == "green": + r, g, b, _ = image_channel_split(orig_image, 'RGB') + g = adjust_levels(g, black_point, white_point, gray_point, + output_black_point, output_white_point) + ret_image = image_channel_merge((r, g.convert('L'), b), 'RGB') + elif channel == "blue": + r, g, b, _ = image_channel_split(orig_image, 'RGB') + b = adjust_levels(b, black_point, white_point, gray_point, + output_black_point, output_white_point) + ret_image = image_channel_merge((r, g, b.convert('L')), 'RGB') + else: + ret_image = adjust_levels(orig_image, black_point, white_point, gray_point, + output_black_point, output_white_point) + + if orig_image.mode == 'RGBA': + ret_image = RGB2RGBA(ret_image, orig_image.split()[-1]) + + ret_images.append(pil2tensor(ret_image)) + + log(f"{NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish') + return (torch.cat(ret_images, dim=0),) + + +NODE_CLASS_MAPPINGS = { + "LayerColor: Levels": ColorCorrectLevels +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "LayerColor: Levels": "LayerColor: Levels" +} \ No newline at end of file diff --git a/py/imagefunc.py b/py/imagefunc.py index 58f9cf2..c2df7b9 100644 --- a/py/imagefunc.py +++ b/py/imagefunc.py @@ -786,6 +786,43 @@ def histogram_equalization(image:Image, mask:Image=None, gamma_strength=0.5) -> return image.convert('L') +def adjust_levels(image:Image, input_black:int=0, input_white:int=255, midtones:float=1.0, + output_black:int=0, output_white:int=255) -> Image: + + if input_black == input_white or output_black == output_white: + return Image.new('RGB', size=image.size, color='gray') + + img = pil2cv2(image).astype(np.float64) + + if input_black > input_white: + input_black, input_white = input_white, input_black + if output_black > output_white: + output_black, output_white = output_white, output_black + + + # input_levels remap + if input_black > 0 or input_white < 255: + img = 255 * ((img - input_black) / (input_white - input_black)) + img[img < 0] = 0 + img[img > 255] = 255 + + # # mid_tone + if midtones != 1.0: + img = 255 * np.power(img / 255, 1.0 / midtones) + + img[img < 0] = 0 + img[img > 255] = 255 + + # output_levels remap + if output_black > 0 or output_white < 255: + img = (img / 255) * (output_white - output_black) + output_black + img[img < 0] = 0 + img[img > 255] = 255 + + img = img.astype(np.uint8) + return cv22pil(img) + + def get_image_color_tone(image:Image) -> str: image = image.convert('RGB') max_score = 0.0001 diff --git a/py/sharp&soft.py b/py/sharp&soft.py index 13eca56..535f209 100644 --- a/py/sharp&soft.py +++ b/py/sharp&soft.py @@ -10,7 +10,7 @@ class SharpAndSoft: @classmethod def INPUT_TYPES(self): - enhance_list = ['very sharp', 'sharp', 'soft', 'very soft'] + enhance_list = ['very sharp', 'sharp', 'soft', 'very soft', 'None'] return { "required": { @@ -45,6 +45,8 @@ class SharpAndSoft: filter_radius = 15 denoise = 0.06 detail_mult = 0.01 + else: + return (images,) d = int(filter_radius * 2) + 1 s = 0.02