OpenCV摄像头实时处理:从单特征到联合识别(形状识别 + 颜色识别 + 形状颜色联合识别)
前言
在计算机视觉入门阶段,形状识别和颜色识别是两个核心的基础单特征识别任务,而将两者结合的形状 + 颜色联合识别,是实现复杂视觉应用的重要过渡。本文将先分别拆解形状识别、颜色识别的核心原理与代码实现,再讲解如何将两个单特征识别逻辑整合为联合识别工具,形成从基础到进阶的完整学习链路,所有代码均基于摄像头实时视频流实现,实用性拉满。
目录
前言
一、基础铺垫:核心原理与通用准备
1.1 核心依赖与环境准备
1.2 通用注意事项
二、单特征识别①:实时形状识别(摄像头版)
2.1 核心原理
2.2 完整可运行代码
2.3 关键参数调试
三、单特征识别②:实时颜色识别(摄像头版)
3.1 核心原理
3.2 完整可运行代码
3.3 关键参数调试
四、进阶整合:形状 + 颜色联合识别(摄像头版)
4.1 整合思路
4.2 完整可运行代码
4.3 核心优化点(相比单独识别)
五、三版本对比与调试总表
5.1 功能与效率对比
5.2 通用调试总表(解决 90% 的问题)
六、扩展与进阶方向
七、总结
论文投稿:
第二届计算机视觉研究进展与应用国际学术会议 (ACVRA 2026)
大会官网:https://ais.cn/u/2YrM7j
大会时间:2026年2月6-8日
大会地点:中国-武汉



一、基础铺垫:核心原理与通用准备
1.1 核心依赖与环境准备
所有案例均基于OpenCV-Python和NumPy实现,提前安装依赖:
# 安装核心库
pip install opencv-python numpy
# 验证安装
python -c "import cv2, numpy; print('OpenCV版本:', cv2.__version__)"
1.2 通用注意事项
- 摄像头 ID:
0为电脑内置摄像头,1为外接摄像头,根据实际设备调整; - 阈值参数:所有面积阈值、HSV 颜色范围、轮廓近似系数均需根据实际光照 / 目标大小微调;
- 资源释放:所有案例均包含
cap.release()和cv2.destroyAllWindows(),避免摄像头占用和内存泄漏。
二、单特征识别①:实时形状识别(摄像头版)
形状识别的核心是轮廓分析—— 通过提取物体的轮廓,拟合多边形后根据顶点数判断形状,适合识别三角形、正方形、矩形、圆形等规则几何形状。
2.1 核心原理
- 预处理:将彩色图转灰度图→高斯模糊降噪→Canny 边缘检测,提取物体边缘;
- 轮廓查找:仅提取外部轮廓,排除物体内部的镂空轮廓,简化计算;
- 轮廓筛选:过滤小面积轮廓,排除噪声干扰;
- 轮廓近似:通过多边形拟合减少轮廓顶点数,得到形状的核心顶点特征;
- 形状判定:根据拟合后的顶点数识别形状,4 顶点通过宽高比区分正方形 / 矩形。
2.2 完整可运行代码
# coding=utf-8
import cv2
import numpy as np
def detect_shapes(frame):
"""形状识别核心函数:输入帧,返回标注后的帧"""
# 1. 预处理:灰度化→高斯模糊→边缘检测
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 5x5高斯核,降噪
edges = cv2.Canny(blurred, 50, 150) # Canny边缘检测,高低阈值50/150
# 2. 查找外部轮廓:RETR_EXTERNAL=仅外部轮廓,CHAIN_APPROX_SIMPLE=压缩轮廓点
contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
# 3. 筛选轮廓:面积<1000视为噪声,忽略
if cv2.contourArea(cnt) < 1000:
continue
# 4. 轮廓近似:拟合多边形,epsilon=轮廓周长×0.02(拟合精度)
epsilon = 0.02 * cv2.arcLength(cnt, True) # True表示轮廓是闭合的
approx = cv2.approxPolyDP(cnt, epsilon, True)
# 5. 计算轮廓几何中心:用于标注文字的位置
M = cv2.moments(cnt)
if M["m00"] != 0: # 避免除零错误
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
# 6. 根据顶点数判定形状,设置标注颜色
vertices = len(approx)
shape_name = "未知"
color = (0, 0, 255) # 默认红色:未知形状
if vertices == 3:
shape_name = "三角形"
color = (0, 255, 0) # 绿色
elif vertices == 4:
# 4顶点:计算宽高比,区分正方形(1:1)和矩形
x, y, w, h = cv2.boundingRect(approx)
aspect_ratio = float(w) / h
if 0.95 <= aspect_ratio <= 1.05: # 宽高比接近1,判定为正方形
shape_name = "正方形"
color = (255, 0, 0) # 蓝色
else:
shape_name = "矩形"
color = (255, 255, 0) # 青色
elif vertices >= 8: # 顶点数≥8,判定为圆形(椭圆适配)
shape_name = "圆形"
color = (0, 255, 255) # 黄色
# 7. 绘制轮廓和形状标注
cv2.drawContours(frame, [approx], -1, color, 2) # 绘制拟合后的轮廓,线宽2
cv2.putText(frame, shape_name, (cX - 20, cY - 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) # 白色文字,线宽2
return frame
def main():
# 摄像头初始化,设置分辨率
cap = cv2.VideoCapture(1) # 摄像头ID,0=内置,1=外接
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# 检查摄像头是否打开
if not cap.isOpened():
print("错误:无法打开摄像头!")
return
# 创建可调整大小的显示窗口
cv2.namedWindow('实时形状识别', cv2.WINDOW_NORMAL)
print("形状识别已启动,按 'q' 键退出...")
while True:
ret, frame = cap.read()
if not ret:
print("错误:无法读取视频帧!")
break
frame = cv2.flip(frame, 1) # 镜像翻转,解决摄像头画面左右颠倒
processed_frame = detect_shapes(frame) # 形状识别
cv2.imshow('实时形状识别', processed_frame)
# 按q退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
2.3 关键参数调试
- 轮廓面积阈值:
cv2.contourArea(cnt) < 1000,目标过小则减小 1000,噪声过多则增大; - 轮廓近似精度:
epsilon = 0.02 * cv2.arcLength(cnt, True),0.01~0.03 为宜,值越小拟合越精细; - Canny 边缘阈值:
cv2.Canny(blurred, 50, 150),光照强则提高阈值,光照弱则降低。
三、单特征识别②:实时颜色识别(摄像头版)
颜色识别的核心是HSV 颜色空间—— 相比 OpenCV 默认的 BGR 空间,HSV 更贴合人眼对颜色的感知,能有效排除光照亮度的干扰,是颜色识别的首选空间。
3.1 核心原理
- 颜色空间转换:将 BGR 彩色图转为 HSV 空间,分离色调(H)、饱和度(S)、明度(V);
- 定义 HSV 范围:为目标颜色(红 / 蓝 / 绿)设置 HSV 上下界,生成颜色掩膜(符合范围为白色 255,否则为黑色 0);
- 形态学操作:对掩膜进行开运算(先腐蚀后膨胀),去除噪声点;
- 轮廓查找与筛选:根据掩膜查找颜色区域的轮廓,过滤小面积轮廓,排除误识别;
- 颜色判定:根据轮廓对应的掩膜,判定区域主颜色,并绘制标注框。
3.2 完整可运行代码
# coding=utf-8
import cv2
import numpy as np
def color_detection(frame):
"""颜色识别核心函数:输入帧,返回标注后的帧"""
# 1. 转换为HSV颜色空间,颜色识别的核心步骤
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 2. 定义HSV颜色范围(适配日常光照,S/V最小值≥100,过滤低饱和度/低明度干扰)
# 红色:HSV中分为两段(0-10和160-179),需单独定义后合并
lower_red1 = np.array([0, 100, 100])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 100, 100])
upper_red2 = np.array([179, 255, 255])
red_mask = cv2.inRange(hsv_frame, lower_red1, upper_red1) + cv2.inRange(hsv_frame, lower_red2, upper_red2)
# 蓝色
lower_blue = np.array([110, 100, 100])
upper_blue = np.array([130, 255, 255])
blue_mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
# 绿色
lower_green = np.array([50, 100, 100])
upper_green = np.array([70, 255, 255])
green_mask = cv2.inRange(hsv_frame, lower_green, upper_green)
# 3. 形态学开运算:5x5核,去除掩膜中的小噪声点
kernel = np.ones((5, 5), np.uint8)
red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernel)
blue_mask = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel)
green_mask = cv2.morphologyEx(green_mask, cv2.MORPH_OPEN, kernel)
# 4. 合并所有颜色掩膜,查找外部轮廓
all_mask = red_mask + blue_mask + green_mask
contours, _ = cv2.findContours(all_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
# 5. 筛选轮廓:面积<500视为噪声,忽略
if cv2.contourArea(contour) < 500:
continue
# 获取轮廓外接矩形,用于绘制标注框
x, y, w, h = cv2.boundingRect(contour)
# 6. 判定区域主颜色
color_name = ""
color_box = (0, 0, 255) # 标注框颜色,与识别颜色对应
if np.any(red_mask[y:y+h, x:x+w]):
color_name = "红色"
color_box = (0, 0, 255)
elif np.any(blue_mask[y:y+h, x:x+w]):
color_name = "蓝色"
color_box = (255, 0, 0)
elif np.any(green_mask[y:y+h, x:x+w]):
color_name = "绿色"
color_box = (0, 255, 0)
# 7. 绘制颜色标注框和文字
cv2.rectangle(frame, (x, y), (x+w, y+h), color_box, 2)
cv2.putText(frame, color_name, (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, color_box, 2)
return frame
def main():
# 摄像头初始化
cap = cv2.VideoCapture(1) # 0=内置,1=外接
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
if not cap.isOpened():
print("错误:无法打开摄像头!")
return
cv2.namedWindow('实时颜色识别', cv2.WINDOW_NORMAL)
print("颜色识别已启动,按 'q' 键退出...")
while True:
ret, frame = cap.read()
if not ret:
print("错误:无法读取视频帧!")
break
frame = cv2.flip(frame, 1) # 镜像翻转
processed_frame = color_detection(frame) # 颜色识别
cv2.imshow('实时颜色识别', processed_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
3.3 关键参数调试
- HSV 颜色范围:光照强则提高 S/V 最小值(如 120),光照弱则降低(如 80);红色两段区间可微调(如 160→150);
- 形态学核大小:噪声多则增大核(如 7x7),目标小则减小核(如 3x3);
- 轮廓面积阈值:
cv2.contourArea(contour) < 500,根据目标大小调整,避免漏识别 / 误识别。
四、进阶整合:形状 + 颜色联合识别(摄像头版)
联合识别的核心是 **“先轮廓、后双特征”—— 基于形状识别的轮廓分析逻辑,对每个有效轮廓同时执行形状判定和颜色判定 **,再将两个特征结果组合标注,相比单独识别,减少了重复的轮廓查找和预处理,提升运行效率。
4.1 整合思路
- 复用形状识别的预处理 + 轮廓查找 + 筛选 + 近似逻辑,作为双特征识别的基础;
- 对每个有效轮廓,先通过
detect_shape函数判定形状; - 基于轮廓的外接矩形,提取ROI(感兴趣区域),通过
detect_color函数判定该区域的主颜色; - 组合颜色 + 形状特征,绘制统一的标注框和文字;
- 优化颜色识别逻辑:仅对轮廓 ROI 进行颜色分析,避免背景干扰,提升识别精度和效率。
4.2 完整可运行代码
# coding=utf-8
import cv2
import numpy as np
# ===================== 子函数:颜色识别(ROI版)=====================
def detect_color_roi(frame, x, y, w, h):
"""
针对轮廓ROI的颜色识别,避免背景干扰
:param frame: 原始帧
:param x,y,w,h: 轮廓外接矩形参数
:return: 识别的颜色名称(红色/蓝色/绿色/未知)
"""
# 提取轮廓ROI区域,仅分析该区域的颜色
roi = frame[y:y+h, x:x+w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# 定义HSV颜色范围
lower_red1 = np.array([0, 100, 100])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 100, 100])
upper_red2 = np.array([179, 255, 255])
red_mask = cv2.inRange(hsv_roi, lower_red1, upper_red1) + cv2.inRange(hsv_roi, lower_red2, upper_red2)
lower_blue = np.array([110, 100, 100])
upper_blue = np.array([130, 255, 255])
blue_mask = cv2.inRange(hsv_roi, lower_blue, upper_blue)
lower_green = np.array([50, 100, 100])
upper_green = np.array([70, 255, 255])
green_mask = cv2.inRange(hsv_roi, lower_green, upper_green)
# 形态学开运算,去除ROI内的小噪声
kernel = np.ones((3, 3), np.uint8)
red_mask = cv2.morphologyEx(red_mask, cv2.MORPH_OPEN, kernel)
blue_mask = cv2.morphologyEx(blue_mask, cv2.MORPH_OPEN, kernel)
green_mask = cv2.morphologyEx(green_mask, cv2.MORPH_OPEN, kernel)
# 计算颜色像素占比,避免少量噪点导致误识别(占比≥10%才判定)
red_pix = cv2.countNonZero(red_mask)
blue_pix = cv2.countNonZero(blue_mask)
green_pix = cv2.countNonZero(green_mask)
total_pix = w * h
min_ratio = 0.1
if red_pix / total_pix >= min_ratio:
return "红色"
elif blue_pix / total_pix >= min_ratio:
return "蓝色"
elif green_pix / total_pix >= min_ratio:
return "绿色"
else:
return "未知"
# ===================== 子函数:形状识别 =====================
def detect_shape_approx(approx):
"""
根据轮廓近似结果判定形状
:param approx: 轮廓的多边形拟合结果
:return: 识别的形状名称(三角形/正方形/矩形/圆形/未知)
"""
vertices = len(approx)
if vertices == 3:
return "三角形"
elif vertices == 4:
x, y, w, h = cv2.boundingRect(approx)
aspect_ratio = float(w) / h
if 0.95 <= aspect_ratio <= 1.05:
return "正方形"
else:
return "矩形"
elif vertices >= 8:
return "圆形"
else:
return "未知"
# ===================== 主函数:形状+颜色联合识别 =====================
def detect_shape_color(frame):
"""联合识别核心函数,整合形状和颜色识别"""
result_frame = frame.copy()
# 预处理:复用形状识别的逻辑,提取边缘
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150)
# 查找外部轮廓,为双特征识别提供基础
contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
# 筛选有效轮廓,面积<800视为噪声
if cv2.contourArea(cnt) < 800:
continue
# 轮廓近似,拟合多边形
epsilon = 0.02 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
# 获取轮廓外接矩形,用于ROI颜色识别和标注框绘制
x, y, w, h = cv2.boundingRect(approx)
# 1. 识别形状
shape = detect_shape_approx(approx)
# 2. 识别颜色(仅分析ROI区域)
color = detect_color_roi(frame, x, y, w, h)
# 3. 设置标注样式:框颜色与识别颜色对应,未知为黄色
box_color = (0, 255, 255) # 默认黄色
if color == "红色":
box_color = (0, 0, 255)
elif color == "蓝色":
box_color = (255, 0, 0)
elif color == "绿色":
box_color = (0, 255, 0)
# 4. 组合特征标签,调整标注位置(避免超出画面)
label = f"{color}-{shape}"
label_x = x if x + len(label)*15 < frame.shape[1] else x - len(label)*15
label_y = y - 10 if y - 10 > 0 else y + h + 20
# 5. 绘制标注:轮廓+外接框+特征标签
cv2.drawContours(result_frame, [approx], -1, box_color, 2)
cv2.rectangle(result_frame, (x, y), (x+w, y+h), box_color, 2)
cv2.putText(result_frame, label, (label_x, label_y),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, box_color, 2)
return result_frame
# ===================== 程序入口 =====================
def main():
# 摄像头初始化
cap = cv2.VideoCapture(1) # 0=内置,1=外接
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
if not cap.isOpened():
print("错误:无法打开摄像头!")
return
# 创建大尺寸显示窗口,提升视觉体验
cv2.namedWindow('形状+颜色联合识别', cv2.WINDOW_NORMAL)
cv2.resizeWindow('形状+颜色联合识别', 800, 600)
print("联合识别已启动,按 'q' 键退出...")
while True:
ret, frame = cap.read()
if not ret:
print("错误:无法读取视频帧!")
break
frame = cv2.flip(frame, 1) # 镜像翻转
processed_frame = detect_shape_color(frame) # 联合识别
cv2.imshow('形状+颜色联合识别', processed_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
4.3 核心优化点(相比单独识别)
- ROI 颜色识别:仅对轮廓外接矩形内的区域做颜色分析,排除背景干扰,识别精度更高、计算量更小;
- 像素占比判定:颜色识别增加10% 占比阈值,避免少量噪点导致的颜色误判;
- 统一标注样式:标注框颜色与识别颜色一致,标签直接组合「颜色 - 形状」,视觉更直观;
- 自适应标注位置:根据轮廓位置调整文字标注,避免文字超出画面;
- 融合阈值:轮廓面积阈值设为 800,兼顾形状和颜色识别的需求,平衡噪声过滤和目标识别。
五、三版本对比与调试总表
5.1 功能与效率对比
| 版本 | 核心逻辑 | 优点 | 适用场景 | 运行效率 |
|---|---|---|---|---|
| 形状识别 | 轮廓分析 + 多边形拟合 | 规则形状识别精准 | 仅需形状特征的场景 | 高 |
| 颜色识别 | HSV 掩膜 + 轮廓筛选 | 光照适应性强,颜色准 | 仅需颜色特征的场景 | 中 |
| 联合识别 | 轮廓基础 + 双特征判定 | 特征更丰富,贴近实际应用 | 物料分拣、玩具识别等 | 中(比单独颜色识别高) |
5.2 通用调试总表(解决 90% 的问题)
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 漏识别目标 | 轮廓面积阈值过高 / HSV 范围窄 | 减小面积阈值 / 降低 HSV 的 S/V 最小值 / 微调 H 的范围 |
| 误识别噪声 | 轮廓面积阈值过低 / 核太小 | 增大面积阈值 / 增大形态学核大小 / 提高 HSV 的 S/V 最小值 |
| 形状识别错误 | 轮廓近似 epsilon 不适配 | 调整 epsilon 系数(0.01~0.03)/ 提高 Canny 边缘检测阈值 |
| 颜色识别错误 | 光照干扰 / HSV 范围不适配 | 固定光照环境 / 微调 HSV 范围 / 增加颜色像素占比阈值 |
| 画面卡顿 | 分辨率过高 / 轮廓数量过多 | 降低摄像头分辨率(如 640x480→320x240)/ 增大轮廓面积阈值 |
| 红色识别不全 | 未处理 HSV 红色两段区间 | 确认红色双掩膜合并逻辑 / 微调红色第二段的 H 范围(160~179) |
六、扩展与进阶方向
从基础的形状 / 颜色识别,可逐步扩展为更复杂的视觉应用,推荐进阶方向:
- 增加更多特征:识别更多颜色(黄色、橙色)、更多形状(五边形、六边形);
- 添加置信度:为形状 / 颜色识别添加置信度评分,标注时显示(如 “红色 - 圆形 95%”);
- 目标跟踪:在联合识别基础上,添加 KCF/CSRT 跟踪算法,实现对目标的实时跟踪;
- 结果保存:添加按键功能(如按
s键),保存识别结果帧和特征信息到文件; - 批量处理:将摄像头流改为图片 / 视频文件,实现离线的形状 + 颜色识别;
- 硬件落地:将代码移植到树莓派 / ESP32,结合摄像头模块实现嵌入式视觉应用。
七、总结
本文从单特征识别到联合特征识别,完整讲解了 OpenCV 中形状和颜色识别的核心逻辑:
- 形状识别的核心是轮廓分析,通过多边形拟合的顶点数提取形状特征;
- 颜色识别的核心是HSV 颜色空间,通过掩膜和轮廓筛选提取颜色特征;
- 联合识别的关键是复用轮廓基础,避免重复计算,同时通过 ROI 分析提升识别精度;
- 所有视觉识别任务的核心都是阈值调优,根据实际场景微调参数,是实现精准识别的关键。
这三个版本的代码是计算机视觉入门的经典案例,掌握后可轻松应对大部分基础的视觉识别场景,也是学习目标检测、目标跟踪等高级技术的重要基础。








