diff --git a/README.MD b/README.MD index 0525d2a..d6b0659 100644 --- a/README.MD +++ b/README.MD @@ -80,6 +80,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.
+* [LUT Apply](#LUT) Add the street parameter. * Commit [AutoAdjustV2](#AutoAdjustV2) node, add optional mask input and support for multiple automatic color adjustment modes. * Due to the upcoming discontinuation of gemini-pro vision services, [PromptTagger](#PromptTagger) and [PromptEmbellish](#PromptEmbellish) have added the "gemini-1.5-flash" API to continue using it. * [Ultra](#Ultra) nodes added the option to run ```VitMatte``` on the CUDA device, resulting in a 5-fold increase in running speed. @@ -356,11 +357,13 @@ Node options: ### LUT Apply Apply LUT to the image. only supports .cube format. +![image](image/lut_apply_example.jpg) Node options: ![image](image/lut_apply_node.jpg) * LUT*: Here is a list of available. cube files in the LUT folder, and the selected LUT files will be applied to the image. * color_space: For regular image, please select linear, for image in the log color space, please select log. +* strength: Range 0~100, LUT application strength. The larger the value, the greater the difference from the original image, and the smaller the value, the closer it is to the original image. *LUT folder is defined in ```resource_dir.ini```, this file is located in the root directory of the plug-in, and the default name is ```resource_dir.ini.example```. to use this file for the first time, you need to change the file suffix to ```.ini```. Open the text editing software and find the line starting with "LUT_dir=", after "=", enter the custom folder path name. all .cube files in this folder will be collected and displayed in the node list during ComfyUI initialization. diff --git a/README_CN.MD b/README_CN.MD index c4db12b..ea077f7 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -80,6 +80,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git ## 更新说明 **如果本插件更新后出现依赖包错误,请重新安装相关依赖包。 +* [LUT Apply](#LUT) 节点增加strenght参数。 * 添加 [AutoAdjustV2](#AutoAdjustV2) 节点,增加可选遮罩输入,增加多种自动调色模式支持。 * 由于gemini-pro-vision即将停止服务, [PromptTagger](#PromptTagger) 和 [PromptEmbellish](#PromptEmbellish) 添加"gemini-1.5-flash" API以继续使用。 * [Ultra](#Ultra) 节点增加```VitMatte```方法在CUDA设备运行选项,运行速度提升5倍。 @@ -357,6 +358,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git ![image](image/lut_apply_node.jpg) * LUT*: 这里列出了LUT文件夹中可用的.cube文件列表,选中的LUT文件将被应用到图像。 * color_space: 普通图片请选择linear, log色彩空间的图片请选择log。 +* strength: 范围0~100, LUT应用强度。数值越大,与原图的差别越大, 数值越小,越接近原图。 *LUT文件夹在```resource_dir.ini```中定义,这个文件位于插件根目录下, 默认名字是```resource_dir.ini.example```, 初次使用这个文件需将文件后缀改为.ini。用文本编辑软件打开,找到“LUT_dir=”开头的这一行,编辑“=”之后为自定义文件夹路径名。这个文件夹里面所有的.cube文件将在ComfyUI初始化时被收集并显示在节点的列表中。如果ini中设定的文件夹无效,将启用插件自带的LUT文件夹。 diff --git a/image/lut_apply_example.jpg b/image/lut_apply_example.jpg index 659dc55..5c61f39 100644 Binary files a/image/lut_apply_example.jpg and b/image/lut_apply_example.jpg differ diff --git a/image/lut_apply_node.jpg b/image/lut_apply_node.jpg index 181e589..7f2747d 100644 Binary files a/image/lut_apply_node.jpg and b/image/lut_apply_node.jpg differ diff --git a/py/color_correct_LUTapply.py b/py/color_correct_LUTapply.py index 15dedea..2d28df2 100644 --- a/py/color_correct_LUTapply.py +++ b/py/color_correct_LUTapply.py @@ -15,6 +15,7 @@ class ColorCorrectLUTapply: "image": ("IMAGE", ), # "LUT": (LUT_LIST,), # LUT文件 "color_space": (color_space_list,), + "strength": ("INT", {"default": 100, "min": 0, "max": 100, "step": 1}), }, "optional": { } @@ -25,14 +26,14 @@ class ColorCorrectLUTapply: FUNCTION = 'color_correct_LUTapply' CATEGORY = '😺dzNodes/LayerColor' - def color_correct_LUTapply(self, image, LUT, color_space): + def color_correct_LUTapply(self, image, LUT, color_space, strength): ret_images = [] for i in image: i = torch.unsqueeze(i, 0) _image = tensor2pil(i) lut_file = LUT_DICT[LUT] - ret_image = apply_lut(_image, lut_file, log=(color_space == 'log')) + ret_image = apply_lut(_image, lut_file=lut_file, colorspace=color_space, strength=strength) if _image.mode == 'RGBA': ret_image = RGB2RGBA(ret_image, _image.split()[-1]) diff --git a/py/imagefunc.py b/py/imagefunc.py index 3015126..ceb400f 100644 --- a/py/imagefunc.py +++ b/py/imagefunc.py @@ -1077,29 +1077,79 @@ def gamma_trans(image:Image, gamma:float) -> Image: _corrected = cv2.LUT(cv2_image,gamma_table) return cv22pil(_corrected) -def apply_lut(image:Image, lut_file:str, log:bool=False) -> Image: - from colour.io.luts.iridas_cube import read_LUT_IridasCube, LUT3D, LUT3x1D - lut: Union[LUT3x1D, LUT3D] = read_LUT_IridasCube(lut_file) - lut.name = os.path.splitext(os.path.basename(lut_file))[0] # use base filename instead of internal LUT name +# def apply_lut(image:Image, lut_file:str, log:bool=False) -> Image: +# from colour.io.luts.iridas_cube import read_LUT_IridasCube, LUT3D, LUT3x1D +# lut: Union[LUT3x1D, LUT3D] = read_LUT_IridasCube(lut_file) +# lut.name = os.path.splitext(os.path.basename(lut_file))[0] # use base filename instead of internal LUT name +# +# im_array = np.asarray(image.convert('RGB'), dtype=np.float32) / 255 +# is_non_default_domain = not np.array_equal(lut.domain, np.array([[0., 0., 0.], [1., 1., 1.]])) +# dom_scale = None +# if is_non_default_domain: +# dom_scale = lut.domain[1] - lut.domain[0] +# im_array = im_array * dom_scale + lut.domain[0] +# if log: +# im_array = im_array ** (1 / 2.2) +# im_array = lut.apply(im_array) +# if log: +# im_array = im_array ** (2.2) +# if is_non_default_domain: +# im_array = (im_array - lut.domain[0]) / dom_scale +# im_array = im_array * 255 +# ret_image = Image.fromarray(np.uint8(im_array)) +# +# return ret_image - im_array = np.asarray(image.convert('RGB'), dtype=np.float32) / 255 +def apply_lut(image:Image, lut_file:str, colorspace:str, strength:int, clip_values:bool=True) -> Image: + """ + Apply a LUT to an image. + :param image: Image to apply the LUT to. + :param lut_file: LUT file to apply. + :param colorspace: Colorspace to convert the image to before applying the LUT. + :param clip_values: Clip the values of the LUT to the domain of the LUT. + :param strength: Strength of the LUT. + :return: Image with the LUT applied. + """ + log_colorspace = False + if colorspace == "log": + log_colorspace = True + + from colour.io.luts.iridas_cube import read_LUT_IridasCube + + lut = read_LUT_IridasCube(lut_file) + lut.name = lut_file + + if clip_values: + if lut.domain[0].max() == lut.domain[0].min() and lut.domain[1].max() == lut.domain[1].min(): + lut.table = np.clip(lut.table, lut.domain[0, 0], lut.domain[1, 0]) + else: + if len(lut.table.shape) == 2: # 3x1D + for dim in range(3): + lut.table[:, dim] = np.clip(lut.table[:, dim], lut.domain[0, dim], lut.domain[1, dim]) + else: # 3D + for dim in range(3): + lut.table[:, :, :, dim] = np.clip(lut.table[:, :, :, dim], lut.domain[0, dim], lut.domain[1, dim]) + + img = pil2tensor(image) + lut_img = img.numpy().copy() is_non_default_domain = not np.array_equal(lut.domain, np.array([[0., 0., 0.], [1., 1., 1.]])) dom_scale = None if is_non_default_domain: dom_scale = lut.domain[1] - lut.domain[0] - im_array = im_array * dom_scale + lut.domain[0] - if log: - im_array = im_array ** (1 / 2.2) - im_array = lut.apply(im_array) - if log: - im_array = im_array ** (2.2) + lut_img = lut_img * dom_scale + lut.domain[0] + if log_colorspace: + lut_img = lut_img ** (1/2.2) + lut_img = lut.apply(lut_img) + if log_colorspace: + lut_img = lut_img ** (2.2) if is_non_default_domain: - im_array = (im_array - lut.domain[0]) / dom_scale - im_array = im_array * 255 - ret_image = Image.fromarray(np.uint8(im_array)) - - return ret_image + lut_img = (lut_img - lut.domain[0]) / dom_scale + lut_img = torch.from_numpy(lut_img) + if strength < 100: + strength /= 100 + lut_img = strength * lut_img + (1 - strength) * img + return tensor2pil(lut_img) def color_adapter(image:Image, ref_image:Image) -> Image: image = pil2cv2(image)