# 多维量化色彩 **Repository Path**: YzlisTop/Multidimensional-Emotion-Semantic-Color ## Basic Information - **Project Name**: 多维量化色彩 - **Description**: ----------- - **Primary Language**: Unknown - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-07 - **Last Updated**: 2025-09-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 多维语义化色彩判断 > 通过识别图像特征自定义采样定义图像情感 ## 本地部署 > 首次部署 ```bash git clone https://gitee.com/u1iz/Multidimensional-Emotion-Semantic-Color.git cd Multidimensional-Emotion-Semantic-Color npm install ``` > 终端一 ```bash :: 拉取更新 git pull :: 启动WebSocket服务器 node ws/ws ``` > 终端二 ```bash :: 打开前端页面 npm run dev ``` ## 实现 ### 核心 ##### 分割图像 > 安装依赖 ```bash pip install opencv-python numpy scikit-image ``` > 原图 ![test](README.assets/test.jpg) > 分段 split.py[^split] ![image-20250808150626401](README.assets/image-20250808150626401.png) > 分段重组 join.py[^join] ![ret](README.assets/ret.png) > 旧 > ```python 结构计算: 容差 = {H, S, L} 图像 = [[[像素信息,是否被编组]]] 分组 = {} for 列数 in 图像: 列 = 图像[列数] for 像素1索引 in 列: 像素1 = 图像[列数][像素1索引] if 像素1未被编组: 分组[像素1的HSL值] += 像素1 for 列数2 in 图像: 列2 = 图像[列数2] for 索引2 in 列2: 像素2 = 图像[列数2 + 列数][像素1索引 + 索引2] if |像素2 - 像素1| < 容差: 分组[像素1的HSL值] += 像素2 最终得到分组对象,例 { "HSL": { 像素值列表: [hsl, hsl], 像素相对值: [hsl, hsl], // 相对均值 像素绝对位置: [[x, y], [x, y]], 像素均值: [H, S,L], 像素中位数: [H, S, L] } } ``` ## 涉及算法 ### 色彩空间转换 $$ \large\begin{aligned} &\text{输入:} &\text{G,B} &\in [0, 255] \\ &\text{输出:} &\text{H}&\in [0\degree, 360\degree) \\ &&\text{S,L } &\in [0\%, 100\%] \\\\ \end{aligned} $$ $$ \begin{aligned} R_n &= \frac{R}{255} & G_n &= \frac{G}{255} & B_n &= \frac{B}{255} \\[1em] t_{\text{max}} &= \max(R_n, G_n, B_n) & t_{\text{min}} &= \min(R_n, G_n, B_n) & \Delta &= t_{\text{max}} - t_{\text{min}} \\\\[1em] L' &= \frac{t_{\text{max}} + t_{\text{min}}}{2} \\[1em] S' &= \begin{cases} 0 & \Delta = 0 \\ \frac{\Delta}{1-|2L'-1|} & \text{otherwise} \end{cases} \\[1em] H' &= \begin{cases} \left( \frac{H_n - B_n}{\Delta} \right) \!\!\! \mod 6 \times 60^{\circ} & t_{\text{max}} = R_n \\ \left( \frac{B_n - R_n}{\Delta} + 2 \right) \times 60^{\circ} & t_{\text{max}} = G_n \\ \left( \frac{R_n - G_n}{\Delta} + 4 \right) \times 60^{\circ} & t_{\text{max}} = B_n \end{cases} \end{aligned} $$ ## 涉及依赖 ``` pip install opencv-python numpy scikit-image tqdm ``` ---- [^split]: 详见页面末尾 ```python import cv2 import numpy as np import os from skimage import graph, segmentation, color from skimage.measure import regionprops import shutil def color_segmentation( image_path, k=8, min_pixels=0, color_thresh=15 ): # 读取图像 image = cv2.imread(image_path) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) h, w, _ = image.shape # 删除并重新创建输出目录 if os.path.exists('./split'): shutil.rmtree('./split') # 递归删除整个文件夹及其内容 os.makedirs('./split', exist_ok=True) # 重新创建空文件夹 # K-means聚类 pixel_data = image.reshape((-1, 3)).astype(np.float32) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2) _, labels, centers = cv2.kmeans( pixel_data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) centers = np.uint8(centers) clustered = centers[labels.flatten()].reshape((h, w, 3)) labels = labels.reshape((h, w)) + 1 # 标签从1开始 # 构建区域邻接图(RAG)并融合小色块 if min_pixels > 0: rag = graph.rag_mean_color(image, labels) regions = regionprops(labels) # 标记需要融合的小色块 small_regions = [r.label for r in regions if r.area < min_pixels] neighbor_map = {r.label: [] for r in regions} # 查找每个小色块的相邻色块 for region in regions: if region.label in small_regions: boundary_labels = np.unique(labels[max(0, region.bbox[0]-1):min(h, region.bbox[2]+1), max(0, region.bbox[1]-1):min(w, region.bbox[3]+1)]) neighbor_map[region.label] = [ x for x in boundary_labels if x != region.label and x not in small_regions] # 融合到最相似的相邻色块 for small_label in small_regions: if not neighbor_map[small_label]: continue # 计算颜色相似度 small_color = rag.nodes[small_label]['mean color'] min_diff = float('inf') best_neighbor = None for neighbor in neighbor_map[small_label]: neighbor_color = rag.nodes[neighbor]['mean color'] diff = np.linalg.norm(small_color - neighbor_color) if diff < min_diff and diff < color_thresh: min_diff = diff best_neighbor = neighbor # 执行融合 if best_neighbor: labels[labels == small_label] = best_neighbor # 保存色块(保持原分辨率) output_segments = [] for label in np.unique(labels): if label == 0: continue # 跳过背景 mask = np.where(labels == label, 255, 0).astype(np.uint8) mean_color = cv2.mean(image, mask)[:3] # 创建带透明通道的色块 segmented_img = np.zeros((h, w, 4), dtype=np.uint8) segmented_img[..., :3] = mean_color segmented_img[..., 3] = mask # 保存文件 output_path = f'./split/segment_{label:03d}.png' cv2.imwrite(output_path, cv2.cvtColor( segmented_img, cv2.COLOR_RGBA2BGRA)) output_segments.append(segmented_img) return output_segments, (h, w) # 使用示例 if __name__ == "__main__": # 示例1:K-means聚类+小色块融合 color_segmentation( './test.jpg', k=16, min_pixels=100, color_thresh=20 ) ``` [^join]:详见页面末尾 ```python import cv2 import numpy as np import glob # 获取所有PNG文件路径并按文件名排序 file_list = glob.glob('./split/*.png') file_list.sort() # 按文件名排序 # 检查是否找到图片 if not file_list: print("错误:未找到任何PNG文件") exit() # 初始化叠加结果(全透明背景) result = None # 遍历所有图片并叠加 for file_path in file_list: # 读取图片(保留Alpha通道) img = cv2.imread(file_path, cv2.IMREAD_UNCHANGED) # 如果图片是3通道(无Alpha),添加Alpha通道 if img.shape[2] == 3: img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA) # 初始化叠加结果(使用第一张图片的尺寸) if result is None: result = np.zeros_like(img, dtype=np.float32) # 转换为浮点数以便计算 img_float = img.astype(np.float32) / 255.0 # 提取Alpha通道并归一化 alpha = img_float[:, :, 3] alpha = np.expand_dims(alpha, axis=2) # 图层叠加公式:result = new_alpha * img + (1 - new_alpha) * result result[:, :, :3] = alpha * img_float[:, :, :3] + (1 - alpha) * result[:, :, :3] result[:, :, 3] = alpha.squeeze() + result[:, :, 3] * (1 - alpha.squeeze()) # 转换回8位整数(0-255范围) result = (result * 255).clip(0, 255).astype(np.uint8) # 保存结果 cv2.imwrite('./ret.png', result) print("图片已保存为 ./ret.png") ```