You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV提取纯色块图像中的所有颜色并分离色块?

纯色块图像的颜色提取与色块分离

问题背景

需要处理由纯色块组成的图像,目标是提取所有视觉上的纯色,并将每个色块单独分离。尝试过以下方法但效果不佳:

  • 自动阈值提取:无法适配多色块场景
t, _ = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
_, target = cv2.threshold(img, t, 255, cv2.THRESH_BINARY_INV)
cnts, hierarchys = cv2.findContours(target, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
  • 边缘检测+形态学操作:残留大量多余轮廓
gray_temp = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = 255 - cv2.Canny(gray_temp, 25, 50)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
edges = cv2.erode(edges, kernel, iterations=1)
cnts, hierarchys = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

另外,用numpy提取颜色时,视觉相同的像素RGB值存在差异;使用extcolors库时,不同图像需要调整不同的tolerance值,通用性差。

解决方案

1. 色彩量化:解决同视觉色RGB不一致问题

用K-means聚类将相似颜色自动归为一类,无需手动调参,适配不同图像。核心思路是把像素的RGB值作为特征聚类,将视觉相近的像素合并为同一颜色:

import cv2
import numpy as np
from sklearn.cluster import KMeans

# 读取图像并转RGB格式
img = cv2.imread("your_image.jpg")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 将图像转为二维像素数组
pixels = img_rgb.reshape(-1, 3)

# 设定聚类数(可根据图像色块数量预估,或用肘部法则自动判断最优值)
k = 5
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(pixels)

# 提取聚类后的纯色中心(即图像中所有视觉纯色)
extracted_colors = kmeans.cluster_centers_.astype(int)

# 生成颜色统一的量化图像
quantized_img = kmeans.labels_.reshape(img_rgb.shape[:2])

2. 基于量化图像分离色块

量化后的图像每个色块颜色完全统一,用连通区域分析或轮廓检测即可精准分离:

方法一:连通区域分析(推荐,能区分同色不连通的色块)
# 遍历每个颜色类别
for color_idx in range(k):
    # 生成当前颜色的掩码
    mask = (quantized_img == color_idx).astype(np.uint8) * 255
    # 获取连通区域信息
    num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)
    # 遍历每个连通色块(跳过背景标签0)
    for i in range(1, num_labels):
        # 提取当前色块的掩码
        block_mask = (labels == i).astype(np.uint8) * 255
        # 提取色块图像
        block = cv2.bitwise_and(img, img, mask=block_mask)
        # 保存或处理色块
        cv2.imwrite(f"block_color{color_idx}_id{i}.png", block)
方法二:轮廓检测
for color_idx in range(k):
    mask = (quantized_img == color_idx).astype(np.uint8) * 255
    # 查找外轮廓(避免嵌套轮廓干扰)
    cnts, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in cnts:
        # 创建空白画布绘制色块
        block = np.zeros_like(img)
        cv2.drawContours(block, [cnt], -1, (255,255,255), thickness=cv2.FILLED)
        # 提取色块
        block = cv2.bitwise_and(img, block)
        cv2.imwrite(f"block_color{color_idx}.png", block)

3. 原有方法的改进思路

  • 自动阈值法仅适用于单通道二值场景,多色块图像必须先做色彩量化,再对每个颜色单独做阈值处理
  • 边缘检测法的误差源于颜色细微差异,先量化消除噪声后,再用边缘检测能大幅减少多余轮廓

内容的提问来源于stack exchange,提问作者HamGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 23:15:22