diff --git a/README.MD b/README.MD
index 6eb0c0f..05cab79 100644
--- a/README.MD
+++ b/README.MD
@@ -146,7 +146,7 @@ When this error has occurred, please check the network environment.
**If the dependency package error after updating, please double clicking ```repair_dependency.bat``` (for Official ComfyUI Protable) or ```repair_dependency_aki.bat``` (for ComfyUI-aki-v1.x) in the plugin folder to reinstall the dependency packages.
-
+* Commit [GetMainColorsV2](#GetMainColorsV2) node, add sorting by color area and output color values and proportions in the preview image. This part of the code was improved by @ HL, thanks.
* Optimize dependency packages. Optimize some algorithms.
* Split some nodes of the dependencies that are prone to problems into [ComfyUI_LayerStyle_Advance](#https://github.com/chflame163/ComfyUI_LayerStyle_Advance) repository. Including:
LayerMask: BiRefNetUltra, LayerMask: BiRefNetUltraV2, LayerMask: LoadBiRefNetModel, LayerMask: LoadBiRefNetModelV2,
@@ -1099,6 +1099,12 @@ Outputs:
* preview_image: 5 main color preview images.
* color_1~color_5: Color value output. Output an RGB string in HEX format.
+### GetMainColorsV2
+Add sorting by color area to the [GetMainColors](#GetMainColors) node and display color values and color areas in the preview image.
+This part of the code was improved by @ HL, thanks.
+
+
+
### ColorName
Output the most similar color name in the color palette based on the color value.
diff --git a/README_CN.MD b/README_CN.MD
index 459326f..0d1a52e 100644
--- a/README_CN.MD
+++ b/README_CN.MD
@@ -127,6 +127,7 @@ os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
## 更新说明
**如果本插件更新后出现依赖包错误,请双击运行插件目录下的```install_requirements.bat```(官方便携包),或 ```install_requirements_aki.bat```(秋叶整合包) 重新安装依赖包。
+* 添加 [GetMainColorsV2](#GetMainColorsV2) 节点,增加按颜色面积排序,并在预览图中输出色值和比例。这部分代码由@HL完善,感谢。
* 优化依赖包。优化部分图形算法。
* 分拆部分依赖易出问题的节点至[ComfyUI_LayerStyle_Advance](#https://github.com/chflame163/ComfyUI_LayerStyle_Advance)仓库。包括下列节点:
LayerMask: BiRefNetUltra, LayerMask: BiRefNetUltraV2, LayerMask: LoadBiRefNetModel, LayerMask: LoadBiRefNetModelV2,
@@ -973,6 +974,12 @@ ImageScaleByAspectRatio的V2升级版
* preview_image: 5个主色预览图片。
* color_1~color_5: 色值输出。输出格式为HEX格式的RGB字符串。
+### GetMainColorsV2
+在[GetMainColors](#GetMainColors)节点基础上增加按颜色面积排序,并在预览图片中显示色值和颜色面积。
+这部分代码由@HL完善,感谢。
+
+
+
### ColorName
根据色值输出调色盘里最近似的颜色名称。

diff --git a/image/get_main_color_v2_example.jpg b/image/get_main_color_v2_example.jpg
new file mode 100644
index 0000000..6a9d73a
Binary files /dev/null and b/image/get_main_color_v2_example.jpg differ
diff --git a/py/get_main_colors.py b/py/get_main_colors.py
index 945c146..783a256 100644
--- a/py/get_main_colors.py
+++ b/py/get_main_colors.py
@@ -1,10 +1,152 @@
import torch
-from PIL import Image, ImageDraw
+from PIL import Image, ImageDraw, ImageFont
+from collections import Counter
+import colorsys
from .imagefunc import AnyType, log, tensor2pil, pil2tensor, load_custom_size, gaussian_blur
from .imagefunc import RGB_to_Hex
any = AnyType("*")
+
+class LS_GetMainColorsV2:
+
+ def __init__(self):
+ self.NODE_NAME = 'Get Main Colors V2'
+
+ @classmethod
+ def INPUT_TYPES(self):
+ size_list = ['custom']
+ size_list.extend(load_custom_size())
+ k_means_algorithm_list = ["lloyd", "elkan"]
+ return {
+ "required": {
+ "image": ("IMAGE",),
+ "k_means_algorithm": (k_means_algorithm_list,),
+ },
+ "optional": {
+ }
+ }
+
+ RETURN_TYPES = ("IMAGE", "STRING","STRING", "STRING", "STRING", "STRING",)
+ RETURN_NAMES = ("preview_image", "color_1", "color_2", "color_3", "color_4", "color_5",)
+ FUNCTION = 'get_main_colors_v2'
+ CATEGORY = '😺dzNodes/LayerUtility'
+
+ def get_main_colors_v2(self, image, k_means_algorithm):
+ ret_images = []
+ grid_width = 512
+ grid_height = 64 # Reduced height to fit 10 colors
+
+ for i in range(len(image)):
+ pil_img = tensor2pil(torch.unsqueeze(image[i], 0)).convert("RGB")
+ blured_image = gaussian_blur(pil_img, (pil_img.width + pil_img.height) // 400)
+
+ accuracy = 60
+ num_colors = 5 # Increased to 5 colors
+ num_iterations = int(512 * (accuracy / 100))
+ original_colors, color_percentages = self.interrogate_colors(
+ pil2tensor(blured_image), num_colors=num_colors, algorithm=k_means_algorithm, mix_iter=num_iterations,
+ random_state=0)
+
+ main_colors = self.ndarrays_to_colorhex(original_colors)
+
+ # Sort colors by percentage
+ sorted_colors = sorted(zip(main_colors, color_percentages), key=lambda x: x[1], reverse=True)
+ print(f"sorted_colors={sorted_colors},type={type(sorted_colors)}")
+ # Create color info string with HSB values
+ color_info = "\n".join([
+ f"RGB {color[1:]} HSB {self.rgb_to_hsb(color)[0]:03.0f} {self.rgb_to_hsb(color)[1]:03.0f} {self.rgb_to_hsb(color)[2]:03.0f} 占比 {percentage:.2f}%"
+ for color, percentage in sorted_colors
+ ])
+
+ # draw colors image
+ ret_image = Image.new('RGB', size=(grid_width, grid_height * len(main_colors)), color="white")
+ draw = ImageDraw.Draw(ret_image)
+
+ # Use default font with size 20
+ font = ImageFont.load_default().font_variant(size=20)
+
+ for j, (color, percentage) in enumerate(sorted_colors):
+ x1 = 0
+ y1 = grid_height * j
+ draw.rectangle((x1, y1, x1 + grid_width, y1 + grid_height), fill=color, outline=color)
+
+ # Calculate contrast color
+ contrast_color = self.get_contrast_color(color)
+
+ # Add text with contrast color and HSB values
+ h, s, b = self.rgb_to_hsb(color)
+ text = f"RGB {color[1:]} HSB {h:03.0f} {s:03.0f} {b:03.0f} {percentage:.2f}%"
+ # 使用 font.getbbox() 来获取文本的边界框
+ bbox = font.getbbox(text)
+ text_height = bbox[3] - bbox[1]
+
+ # 计算文本的垂直位置,使其在色块中垂直居中
+ text_x = 10 # 固定左边距为10像素
+ text_y = y1 + (grid_height - text_height) // 2
+
+ # 绘制文本
+ draw.text((text_x, text_y), text, fill=contrast_color, font=font)
+
+ ret_images.append(pil2tensor(ret_image))
+
+ log(f"{self.NODE_NAME} Processed {len(ret_images)} image(s).", message_type='finish')
+ return (torch.cat(ret_images, dim=0), sorted_colors[0][0], sorted_colors[1][0], sorted_colors[2][0], sorted_colors[3][0], sorted_colors[4][0],)
+
+ def ndarrays_to_colorhex(self, colors: list) -> list:
+ return [RGB_to_Hex((int(color[0]), int(color[1]), int(color[2]))) for color in colors]
+
+ def interrogate_colors(self, image: torch.Tensor, num_colors: int, algorithm: str, mix_iter: int,
+ random_state: int) -> tuple:
+ from sklearn.cluster import KMeans
+ pixels = image.view(-1, image.shape[-1]).numpy()
+ kmeans = KMeans(
+ n_clusters=num_colors,
+ algorithm=algorithm,
+ max_iter=mix_iter,
+ random_state=random_state,
+ ).fit(pixels)
+
+ colors = kmeans.cluster_centers_ * 255
+
+ # Count pixels in each cluster
+ labels = kmeans.labels_
+ label_counts = Counter(labels)
+ total_pixels = len(labels)
+
+ # Calculate percentages
+ color_percentages = [label_counts[i] / total_pixels * 100 for i in range(num_colors)]
+
+ return colors, color_percentages
+
+ def get_contrast_color(self, hex_color):
+ # Convert hex to RGB
+ rgb = tuple(int(hex_color[i:i + 2], 16) for i in (1, 3, 5))
+
+ # Calculate luminance
+ luminance = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255
+
+ # Choose black or white based on luminance
+ if luminance > 0.5:
+ return "#000000" # Black for light backgrounds
+ else:
+ return "#FFFFFF" # White for dark backgrounds
+
+ def rgb_to_hsb(self, hex_color):
+ # Convert hex to RGB
+ rgb = tuple(int(hex_color[i:i + 2], 16) for i in (1, 3, 5))
+
+ # Convert RGB to HSB
+ h, s, v = colorsys.rgb_to_hsv(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255)
+
+ # Convert to degrees and percentages
+ h = h * 360
+ s = s * 100
+ b = v * 100
+
+ return h, s, b
+
+
class LS_GetMainColors:
def __init__(self):
@@ -83,9 +225,12 @@ class LS_GetMainColors:
NODE_CLASS_MAPPINGS = {
- "LayerUtility: GetMainColors": LS_GetMainColors
+ "LayerUtility: GetMainColors": LS_GetMainColors,
+ "LayerUtility: GetMainColorsV2": LS_GetMainColorsV2,
}
NODE_DISPLAY_NAME_MAPPINGS = {
- "LayerUtility: GetMainColors": "LayerUtility: Get Main Colors"
+ "LayerUtility: GetMainColors": "LayerUtility: Get Main Colors",
+ "LayerUtility: GetMainColorsV2": "LayerUtility: Get Main Colors V2",
+
}
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 1c4c4ee..1a3188b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "comfyui_layerstyle"
description = "A set of nodes for ComfyUI it generate image like Adobe Photoshop's Layer Style. the Drop Shadow is first completed node, and follow-up work is in progress."
-version = "2.0.5"
+version = "2.0.6"
license = "MIT"
dependencies = ["numpy", "pillow", "torch", "matplotlib", "Scipy", "scikit_image", "scikit_learn", "opencv-contrib-python", "pymatting", "timm", "colour-science", "transformers", "blend_modes", "huggingface_hub", "loguru"]