上一章我们学习了轮廓进阶、形状特征、圆形度、多条件轮廓筛选,能够对画面里的物体做形状识别与过滤。本章是整个 OpenCV Python 系列的收官之作,不再学习新 API,而是把前面所有章节的知识点全部串联,搭建一套工业、机器人里最常用的实时颜色目标追踪流水线:摄像头采集画面 → 预处理降噪 → HSV 颜色分割生成掩码 → 形态学清理噪点孔洞 → 轮廓检测 + 多条件筛选 → 旋转最小外接矩形绘制,输出目标坐标、中心位置、旋转角度。

同时我们会复盘整套 OpenCV 系列的学习路线,分析 Python OpenCV 的优势与局限,最后自然引出后续 STM32 嵌入式系列,实现视觉算法从 PC 验证到单片机落地的衔接。

前置回顾整套流水线顺序:图像读取 → 高斯模糊降噪 → BGR 转 HSV → inRange 颜色阈值分割 → 形态学开运算 + 闭运算 → findContours 轮廓查找 → 轮廓面积筛选 → minAreaRect 旋转框提取 → 绘制结果、打印目标信息。

一、项目需求说明

我们实现一个实时追踪程序:

  1. 调用电脑摄像头,实时读取帧画面;
  2. 识别指定颜色色块(示例红色,可自行修改 HSV 阈值);
  3. 过滤掩码里零散噪点、孔洞;
  4. 过滤面积过小的无效轮廓;
  5. 使用最小旋转外接矩形 minAreaRect,获取目标中心点、宽高、倾斜角度;
  6. 在画面上绘制旋转矩形、中心点,实时打印目标坐标和角度;
  7. 支持退出按键 q。

重点区分:boundingRect 是正外接矩形,不带角度;minAreaRect 是旋转外接矩形,能拿到物体倾斜角度,机器人定位、抓取、无人机视觉追踪都依赖它。

二、minAreaRect 角度坑点

minAreaRect 返回的角度有一个非常反直觉的规则:

  • 角度范围:[-90, 0);
  • 当矩形长边水平时,角度接近 0;物体逆时针旋转,角度往负方向走;
  • 想要转为我们习惯的 0~90° 直观角度,需要自己做转换。

后面代码里已经封装好角度转换逻辑,直接使用即可。

三、完整可运行代码(摄像头实时追踪)

import cv2
import numpy as np

#===================== 配置区,自行修改 =====================
#红色HSV阈值,根据自己场景调整

lower_hsv = np.array([0, 120, 80])
upper_hsv = np.array([10, 255, 255])

#轮廓最小面积,过滤噪点
min_contour_area = 200

#形态学核大小
kernel_size = (5, 5)
#===========================================================

#打开摄像头,0代表默认摄像头
cap = cv2.VideoCapture(0)

#设置摄像头分辨率(可选)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

if not cap.isOpened():
    print("摄像头打开失败!")
    exit()

#创建形态学核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)

while True:
    ret, frame = cap.read()

    if not ret:
        print("读取画面失败,退出循环")
        break

    # 1. 高斯模糊降噪,减少画面噪点(预处理)
    blur = cv2.GaussianBlur(frame, (3, 3), 0)

    # 2. BGR转HSV,颜色分割
    hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)

    # 3. 生成颜色掩码
    mask = cv2.inRange(hsv, lower_hsv, upper_hsv)

    # 4. 形态学预处理:先开去外部小白噪点,再闭填充内部孔洞
    mask_open = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
    mask_clean = cv2.morphologyEx(mask_open, cv2.MORPH_CLOSE, kernel)

    5. 查找最外层轮廓
    contours, _ = cv2.findContours(mask_clean, cv2.RETR_EXTERNAL,         cv2.CHAIN_APPROX_SIMPLE)
    draw_img = frame.copy()

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area < min_contour_area:
            continue

        # 获取旋转最小外接矩形
        rect = cv2.minAreaRect(cnt)
        # rect 结构:( (cx, cy), (w, h), angle )
        (cx, cy), (w, h), angle = rect
        # 把-90~0的角度转为0~90便于观察
        angle_show = abs(angle)

        #获取旋转矩形四个顶点
        box_points = cv2.boxPoints(rect)
        box_points = np.intp(box_points)

        #绘制旋转矩形
        cv2.drawContours(draw_img, [box_points], -1, (0, 255, 0), 2)
        #绘制中心点
        cv2.circle(draw_img, (int(cx), int(cy)), 4, (0, 0, 255), -1)
        #文字标注:中心坐标、角度
        text = f"X:{int(cx)} Y:{int(cy)} Angle:{angle_show:.1f}"
        cv2.putText(draw_img, text, (int(cx)+10, int(cy)-10),
        cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 255, 0), 1)

        #控制台打印目标信息
        print(f"目标中心:X={cx:.1f}, Y={cy:.1f}, 宽={w:.1f}, 高={h:.1f}, 原始角度={angle:.1f},显示角度={angle_show:.1f}")

    #窗口展示
    cv2.imshow("原始掩码 mask", mask)
    cv2.imshow("清理后掩码 mask_clean", mask_clean)
    cv2.imshow("目标追踪结果", draw_img)

    #按键退出:q 退出
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        break

#释放资源
cap.release()
cv2.destroyAllWindows()

使用说明

  1. 运行后会弹出 3 个窗口:原始掩码、清理后的掩码、带框标注的追踪画面;
  2. 如果识别不到目标,优先调整 HSV 上下限;
  3. 噪点多就加大核尺寸或者提高 min_contour_area;
  4. 想要追踪别的颜色,替换 HSV 阈值即可。

四、整套流水线拆解回顾

步骤对应章节知识点作用
GaussianBlur图像滤波基础抑制画面高频噪点,让 HSV 分割更稳定
BGR2HSV + inRangeHSV 颜色空间按颜色分离前景和背景,生成二值掩码
开运算、闭运算形态学进阶去除掩码杂点、填补色块内部黑洞,轮廓更干净
findContours轮廓基础从掩码中提取物体轮廓
contourArea 面积筛选轮廓进阶过滤噪声产生的微小无效轮廓
minAreaRect轮廓进阶获取带旋转角度的外接框,拿到中心坐标、倾斜角度
drawContours、putText绘图基础在画面可视化标记目标

这就是机器视觉最经典的“2D 颜色目标定位”方案,比赛小车、视觉追踪、分拣项目里大量使用。

五、Python-OpenCV 的优势与局限性

优点:

  1. 开发速度极快,几十行代码就能验证视觉方案;
  2. 调试方便,可以实时看掩码、中间结果,快速调参;
  3. 电脑算力充足,适合前期算法验证、方案选型。

短板(也是我们转 STM32 的原因):

  1. 依赖 PC,不能独立跑在小车、无人机上;
  2. Python 解释层开销大,帧率上限有限,实时性一般;
  3. 无法直接驱动电机、电调、舵机,只能输出坐标;
  4. 没有硬件控制能力,视觉算法算出坐标之后,还需要单片机去执行控制。

一句话总结:Python OpenCV 是算法验证平台,真正的执行控制交给嵌入式单片机。

六、本章 API 汇总表

函数功能说明
cv2.VideoCapture(0)打开摄像头
cv2.minAreaRect(cnt)获取最小旋转外接矩形,返回中心点、宽高、角度
cv2.boxPoints(rect)把旋转矩形转为四个顶点坐标,用于绘制
cap.release()释放摄像头资源
waitKey(1)画面刷新,监听按键

七、高频踩坑清单

  1. minAreaRect 角度范围是 [-90,0),不要直接当成 0~90° 使用,做角度闭环控制时一定要做转换;
  2. 摄像头画面镜像:如果需要镜像,frame = cv2.flip(frame,1);
  3. HSV 阈值受光照影响极大,强光、暗光下同一颜色阈值会失效,工程上要做曝光补偿;
  4. 目标重叠:多个色块贴在一起时轮廓会合并,需要额外做分割;
  5. 资源释放:程序异常退出时摄像头可能被占用,需要手动释放或者重启终端;
  6. 轮廓筛选阈值不能固定死:目标远近变化,像素面积会跟着变化;
  7. 掩码不干净,优先调形态学核,而不是单纯加大面积阈值,否则小目标会被误过滤。

八、系列复盘:从像素到目标定位的完整学习路线

所有章节走下来,整套 OpenCV Python 系列其实是一条非常清晰的递进路线,可以分成四个阶段:

  • 基础操作阶段:图像读取、显示、保存,像素访问,ROI 裁剪,颜色空间转换,绘图基础。这一阶段解决的是“怎么把图像读进来、怎么在图上画东西”。
  • 图像增强阶段:均值滤波、高斯滤波、中值滤波、双边滤波,直方图均衡化,阈值分割。这一阶段解决的是“怎么让图像更干净、目标更突出”。
  • 形态学与轮廓阶段:腐蚀膨胀、开闭运算、梯度与顶帽黑帽,findContours、contourArea、boundingRect、minAreaRect、形状特征与圆形度。这一阶段解决的是“怎么从二值图里把目标抠出来并量化描述”。
  • 综合实战阶段:颜色目标追踪、形状识别、多条件筛选、实时视频流处理。这一阶段解决的是“怎么把零散 API 串成一条能跑起来的流水线”。

回头看,本章这条流水线里的每一个环节,都能在前面某一章找到出处。这也是学习 OpenCV 最有效的方式:不要孤立地记 API,而是记住它在流水线里的位置和作用。当你遇到新需求时,先想清楚它属于流水线的哪一步,再去查对应章节的 API,效率会高很多。

九、从 PC 到单片机:嵌入式视觉落地预告

本章的程序跑在电脑上,摄像头、算力、显示窗口都是现成的。但真实的机器人、小车、分拣设备上,往往没有 PC,只有一块单片机加一个摄像头模块。这时候就要面对几个现实问题:

  1. 算力受限:STM32 这类 MCU 主频通常只有几十到几百 MHz,没有 GPU,不能直接跑完整的 OpenCV 流水线;
  2. 内存受限:一帧 640×480 的 RGB 图像就有近 900KB,必须考虑降分辨率、灰度化、二值化等轻量化手段;
  3. 算法简化:颜色分割、阈值二值化、简单的行列扫描找边界,往往比完整的轮廓分析更适合 MCU;
  4. 控制闭环:视觉算出目标偏差后,要直接驱动电机、舵机,形成“感知—决策—执行”的闭环。

所以后续的 STM32 嵌入式系列,会从最基础的 GPIO、定时器、串口、PWM 讲起,逐步过渡到摄像头数据采集(如 OV7670、MT9V034 等)、二值化图像处理、简单目标定位,最终实现一个能独立跑在小车上的视觉循迹与目标追踪系统。

PC 上验证算法,单片机上落地执行。这条从 Python 到嵌入式的路线,就是很多机器视觉项目真实的技术演进路径。

十、本章小结

  • 本章用一条完整的实时颜色目标追踪流水线,把滤波、颜色空间、形态学、轮廓、旋转外接矩形、绘图全部串了起来;
  • minAreaRect 是拿到目标中心坐标和倾斜角度的关键,注意它的角度范围是 [-90, 0);
  • Python OpenCV 适合算法验证和快速调参,真正的硬件执行控制要交给嵌入式平台;
  • 至此 OpenCV Python 系列全部结束,下一系列将进入 STM32 嵌入式开发,完成从视觉算法到硬件落地的衔接。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐