在OpenCV中如何可靠将颜色分类为红、黄或「其他」?机器人项目场景
红黄色调区分方案(暗淡色归为「其他」)
方案1:RGB分量阈值+亮度过滤(轻量直接)
针对已提取的圆圈平均RGB值,直接通过分量对比+亮度筛选分类,无需复杂颜色空间转换:
- 亮度计算:用加权公式
Y = 0.299*R + 0.587*G + 0.114*B,先过滤掉Y < 60(可根据实际样本调整阈值)的暗淡色,直接归为「其他」 - 红色判断:满足
R > G*1.5且R > B*1.5,同时亮度达标 - 黄色判断:满足
abs(R - G) < 30且R > B*2且G > B*2,同时亮度达标 - 其余情况归为「其他」
示例代码:
def classify_color(r, g, b): # 计算亮度 brightness = 0.299 * r + 0.587 * g + 0.114 * b if brightness < 60: return "其他" # 判断红色 if r > g * 1.5 and r > b * 1.5: return "红色" # 判断黄色 if abs(r - g) < 30 and r > b * 2 and g > b * 2: return "黄色" return "其他"
方案2:校准版LAB距离匹配(解决标准值偏差问题)
之前用标准LAB值效果差,核心是实际涂色和标准色存在偏差,改用实际样本校准:
- 从输入图像中手动挑选10-20个明确的红色、黄色圆圈,提取它们的平均LAB值,分别计算红、黄的LAB平均值(记为
lab_red_avg、lab_yellow_avg) - 计算待分类颜色的LAB值与两个平均值的欧氏距离:
dist_red = sqrt((L-Lr)^2 + (A-Ar)^2 + (B-Br)^2),同理dist_yellow - 结合亮度过滤和距离阈值(比如红色阈值40、黄色阈值35,根据样本聚类调整)分类:
- 亮度达标且
dist_red < 阈值_red→ 红色 - 亮度达标且
dist_yellow < 阈值_yellow→ 黄色 - 其余归为「其他」
- 亮度达标且
示例代码:
import math import cv2 import numpy as np # 替换为你的实际样本校准平均值 lab_red_avg = np.array([50, 70, 20]) lab_yellow_avg = np.array([75, 10, 70]) brightness_thresh = 60 red_dist_thresh = 40 yellow_dist_thresh = 35 def classify_lab(r, g, b): # RGB转LAB rgb = np.uint8([[[r, g, b]]]) lab = cv2.cvtColor(rgb, cv2.COLOR_RGB2LAB)[0][0] # 亮度过滤 brightness = 0.299 * r + 0.587 * g + 0.114 * b if brightness < brightness_thresh: return "其他" # 计算距离 dist_red = math.sqrt(sum((lab - lab_red_avg)**2)) dist_yellow = math.sqrt(sum((lab - lab_yellow_avg)**2)) if dist_red < red_dist_thresh and dist_red < dist_yellow: return "红色" elif dist_yellow < yellow_dist_thresh: return "黄色" return "其他"
方案3:轻量机器学习分类(稳定适配复杂色调)
如果前两种方案仍有偏差,用极小的机器学习模型适配,适合嵌入式/机器人场景:
- 收集标注数据:提取至少50个样本(红、黄、其他各若干)的平均RGB/LAB值,标注对应类别
- 用
scikit-learn训练逻辑回归或SVM模型(仅3维特征,训练极快) - 导出轻量模型(如
joblib格式),部署到机器人端直接预测
示例训练代码:
from sklearn.linear_model import LogisticRegression import joblib import numpy as np # 替换为你的实际标注数据集 # X:RGB特征数组,y:标签(0=其他,1=红色,2=黄色) X = np.array([[200, 50, 50], [220, 200, 50], [80, 80, 80], ...]) y = np.array([1, 2, 0, ...]) # 训练并保存模型 model = LogisticRegression() model.fit(X, y) joblib.dump(model, "color_classifier.pkl") # 预测函数 def classify_ml(r, g, b): pred = model.predict([[r, g, b]]) return ["其他", "红色", "黄色"][pred[0]]
额外优化建议
- 对提取的圆圈区域先做中值滤波去噪,再计算平均颜色,避免噪点干扰结果
- 亮度阈值可根据木板实际光照动态调整,比如取图像整体平均亮度的0.3倍
内容的提问来源于stack exchange,提问作者Kotetsu Chan
相关产品推荐
相关产品推荐

