Pi视觉追踪(三):OpenCV运动检测

视觉检测是追踪系统最关键的一环。对于蚊子这种小而快的目标,传统的HSV颜色阈值完全失效,必须切换到运动检测范式。

为什么不能用HSV颜色阈值

气球场景HSV颜色阈值有效,因为气球大、颜色鲜艳。但蚊子场景完全不同:

维度 气球 蚊子
大小 占画面几十~几百像素 几像素到十几像素
颜色 单一鲜艳 暗色杂色,HSV无效
速度 慢可预测 快(1-2 m/s)、轨迹zigzag
检测方法 HSV+轮廓/霍夫圆 帧差/MOG2 + 轮廓面积过滤

两种主流运动检测算法

A. MOG2背景减除(推荐主用)

维护一个背景模型(混合高斯),每帧与当前帧对比。自适应光照变化,抗噪声,阴影可检测(灰色标记)。

OpenCV接口:cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=16, detectShadows=True)

参数调优:

参数 默认 调节方向
history 500 越大越鲁棒但响应慢
varThreshold 16 越大越严格(蚊子小目标建议25-50)
detectShadows True 关掉可减少噪声,但易误判阴影为前景

B. 帧差法(轻量备用)

直接计算连续帧灰度差,计算量小,但只对快速运动有效。改进版本是三帧差分法,可以减少”空洞”现象。

检测流水线


读取帧
  → 灰度化 + GaussianBlur降噪
  → MOG2.apply() 得到前景掩码
  → morphologyEx 开运算去噪点
  → findContours 找轮廓
  → 按面积过滤(蚊子5~50像素²,去除过大过小)
  → 取最大/最近运动blob
  → moments计算质心(cx, cy)
  → 返回质心坐标

完整代码:MOG2背景减除检测


"""
motion_mog2.py — OpenCV MOG2 背景减除检测运动物体
来源:改编自 myronabotanel/motion-tracking-opencv 与百度云开发者社区教程
依赖:pip install opencv-python numpy

运行:python motion_mog2.py  (按q退出)
说明:摄像头0号,输出前景掩码+检测框+质心
"""
import cv2
import numpy as np

# === 配置 ===
CAM_INDEX = 0
RES_W, RES_H = 320, 240                # 低分辨率提帧率
HISTORY = 500
VAR_THRESHOLD = 40                     # 蚊子小目标建议25-50
DETECT_SHADOWS = False                 # 关闭阴影检测减噪
MIN_AREA = 5                           # 蚊子最小面积(像素²)
MAX_AREA = 500                         # 排除人等大物体
MORPH_KERNEL = 3                       # 形态学核大小

# MOG2初始化
fgbg = cv2.createBackgroundSubtractorMOG2(
    history=HISTORY,
    varThreshold=VAR_THRESHOLD,
    detectShadows=DETECT_SHADOWS
)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (MORPH_KERNEL, MORPH_KERNEL))

cap = cv2.VideoCapture(CAM_INDEX)
cap.set(3, RES_W)
cap.set(4, RES_H)

# 预热背景模型(采集几十帧让MOG2学背景)
print("预热背景模型(请勿在前方活动),3秒...")
for _ in range(60):
    ret, _ = cap.read()
    if not ret:
        break

def detect_largest_motion(frame):
    """返回最大运动blob的质心(cx, cy)与面积,无则返回None"""
    fgmask = fgbg.apply(frame)
    fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)

    contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if not contours:
        return None, fgmask

    # 按面积过滤
    valid = [c for c in contours if MIN_AREA <= cv2.contourArea(c) <= MAX_AREA]
    if not valid:
        return None, fgmask

    largest = max(valid, key=cv2.contourArea)
    M = cv2.moments(largest)
    if M["m00"] == 0:
        return None, fgmask
    cx = int(M["m10"] / M["m00"])
    cy = int(M["m01"] / M["m00"])
    return (cx, cy, cv2.contourArea(largest)), fgmask


if __name__ == "__main__":
    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                break
            result, fgmask = detect_largest_motion(frame)
            if result:
                cx, cy, area = result
                cv2.circle(frame, (cx, cy), 5, (0, 0, 255), -1)
                cv2.putText(frame, f"area={area}", (cx + 10, cy),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
            # 画画面中心十字
            cv2.drawMarker(frame, (RES_W // 2, RES_H // 2), (255, 0, 0),
                           cv2.MARKER_CROSS, 10, 1)
            cv2.imshow("frame", frame)
            cv2.imshow("fgmask", fgmask)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
    finally:
        cap.release()
        cv2.destroyAllWindows()

蚊子检测的额外建议

  1. 降分辨率提帧率:320×240甚至160×120,可上60fps以上,这对于追快速运动至关重要。
  2. 环境光照稳定:蚊子背景复杂时,可在视野中放浅色背景板。
  3. 缩小ROI:先用低分辨率全帧检测,锁定后只处理ROI区域,大幅提帧率。
  4. 多帧确认:连续3-5帧检测到才触发跟踪,避免单帧噪点误触发。
  5. 有效距离:C270在1米外蚊子已近亚像素,实际有效范围0.5~1.5米。

已发布

分类

,

来自