Python案例如何用OpenCV做目标跟踪

wen python案例 2

本文目录导读:

Python案例如何用OpenCV做目标跟踪

  1. 基本目标跟踪(使用预训练跟踪器)
  2. 基于颜色的目标跟踪
  3. 光流法目标跟踪
  4. 多目标跟踪
  5. 移动物体检测与跟踪
  6. 使用预训练YOLO进行目标检测和跟踪
  7. 常用跟踪器对比
  8. 使用建议

我来介绍几个使用OpenCV进行目标跟踪的Python案例。

基本目标跟踪(使用预训练跟踪器)

import cv2
import numpy as np
def basic_object_tracking():
    """
    基本目标跟踪示例
    """
    # 初始化视频捕获
    cap = cv2.VideoCapture(0)  # 0表示默认摄像头
    # 读取第一帧
    ret, frame = cap.read()
    if not ret:
        print("无法读取视频")
        return
    # 选择跟踪区域
    bbox = cv2.selectROI("选择跟踪目标", frame, False)
    cv2.destroyWindow("选择跟踪目标")
    # 创建跟踪器(多种可选)
    # tracker = cv2.TrackerKCF_create()  # KCF跟踪器
    # tracker = cv2.TrackerCSRT_create()  # CSRT跟踪器
    # tracker = cv2.TrackerMIL_create()   # MIL跟踪器
    tracker = cv2.TrackerKCF_create()
    # 初始化跟踪器
    tracker.init(frame, bbox)
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # 更新跟踪器
        success, bbox = tracker.update(frame)
        # 绘制跟踪结果
        if success:
            x, y, w, h = [int(v) for v in bbox]
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
            cv2.putText(frame, "Tracking", (x, y - 10), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        else:
            cv2.putText(frame, "Lost", (50, 50), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.imshow("目标跟踪", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

基于颜色的目标跟踪

import cv2
import numpy as np
def color_based_tracking():
    """
    基于颜色的目标跟踪
    """
    cap = cv2.VideoCapture(0)
    # 读取第一帧并选择目标
    ret, frame = cap.read()
    if not ret:
        return
    # 选择ROI
    bbox = cv2.selectROI("选择目标", frame, False)
    roi = frame[int(bbox[1]):int(bbox[1]+bbox[3]), 
               int(bbox[0]):int(bbox[0]+bbox[2])]
    # 计算目标颜色直方图
    hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
    roi_hist = cv2.calcHist([hsv_roi], [0], None, [180], [0, 180])
    cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
    # 设置追踪窗口初始位置
    track_window = (int(bbox[0]), int(bbox[1]), 
                   int(bbox[2]), int(bbox[3]))
    # 设置终止条件
    term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
        # 使用MeanShift进行跟踪
        ret, track_window = cv2.meanShift(dst, track_window, term_crit)
        # 绘制跟踪结果
        x, y, w, h = track_window
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
        cv2.imshow("颜色跟踪", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

光流法目标跟踪

import cv2
import numpy as np
def optical_flow_tracking():
    """
    基于光流法的目标跟踪
    """
    cap = cv2.VideoCapture(0)
    # 读取第一帧
    ret, old_frame = cap.read()
    if not ret:
        return
    old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
    # 选择跟踪点
    points = cv2.goodFeaturesToTrack(old_gray, maxCorners=100, 
                                     qualityLevel=0.3, minDistance=7)
    # 光流参数
    lk_params = dict(winSize=(15, 15),
                    maxLevel=2,
                    criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
    # 创建掩码用于绘制轨迹
    mask = np.zeros_like(old_frame)
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 计算光流
        new_points, status, error = cv2.calcOpticalFlowPyrLK(
            old_gray, frame_gray, points, None, **lk_params)
        # 选择好的点
        good_new = new_points[status == 1]
        good_old = points[status == 1]
        # 绘制轨迹
        for i, (new, old) in enumerate(zip(good_new, good_old)):
            a, b = new.ravel()
            c, d = old.ravel()
            mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), 
                          (0, 255, 0), 2)
            frame = cv2.circle(frame, (int(a), int(b)), 5, (0, 0, 255), -1)
        # 合并帧和轨迹
        img = cv2.add(frame, mask)
        # 更新旧帧和点
        old_gray = frame_gray.copy()
        points = good_new.reshape(-1, 1, 2)
        cv2.imshow("光流跟踪", img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        # 如果点太少,重新检测
        if len(points) < 10:
            points = cv2.goodFeaturesToTrack(old_gray, maxCorners=100, 
                                           qualityLevel=0.3, minDistance=7)
    cap.release()
    cv2.destroyAllWindows()

多目标跟踪

import cv2
import numpy as np
def multi_object_tracking():
    """
    多目标跟踪示例
    """
    cap = cv2.VideoCapture(0)
    # 读取第一帧
    ret, frame = cap.read()
    if not ret:
        return
    # 创建多目标跟踪器
    tracker = cv2.MultiTracker_create()
    # 选择多个跟踪目标(选择后按空格确认,按ESC取消)
    bboxes = []
    colors = [(0, 255, 0), (255, 0, 0), (0, 0, 255)]  # 不同目标的颜色
    while True:
        # 选择ROI
        bbox = cv2.selectROI("选择目标 (按空格确认, ESC结束)", frame, False)
        if bbox == (0, 0, 0, 0):  # 按ESC退出
            break
        bboxes.append(bbox)
        cv2.rectangle(frame, (int(bbox[0]), int(bbox[1])),
                     (int(bbox[0]+bbox[2]), int(bbox[1]+bbox[3])),
                     colors[len(bboxes)-1], 2)
        # 使用KCF跟踪器
        tracker.add(cv2.TrackerKCF_create(), frame, bbox)
        print(f"已选择 {len(bboxes)} 个目标")
    cv2.destroyWindow("选择目标 (按空格确认, ESC结束)")
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # 更新所有跟踪器
        success, boxes = tracker.update(frame)
        # 绘制所有跟踪结果
        for i, box in enumerate(boxes):
            x, y, w, h = [int(v) for v in box]
            cv2.rectangle(frame, (x, y), (x+w, y+h), 
                         colors[i % len(colors)], 2)
            cv2.putText(frame, f"Object {i+1}", (x, y-10),
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[i % len(colors)], 2)
        cv2.imshow("多目标跟踪", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

移动物体检测与跟踪

import cv2
import numpy as np
def motion_detection_tracking():
    """
    移动物体检测与跟踪
    """
    cap = cv2.VideoCapture(0)
    # 背景减法器
    backSub = cv2.createBackgroundSubtractorMOG2()
    # 创建KCF跟踪器用于持续跟踪
    tracker = None
    tracking = False
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # 应用背景减法
        fgMask = backSub.apply(frame)
        # 查找轮廓
        contours, _ = cv2.findContours(fgMask, cv2.RETR_EXTERNAL, 
                                      cv2.CHAIN_APPROX_SIMPLE)
        # 处理检测到的移动物体
        for contour in contours:
            area = cv2.contourArea(contour)
            if area > 1000:  # 过滤小面积噪声
                x, y, w, h = cv2.boundingRect(contour)
                if not tracking:
                    # 开始跟踪新的物体
                    tracker = cv2.TrackerCSRT_create()
                    tracker.init(frame, (x, y, w, h))
                    tracking = True
                    print("开始跟踪")
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
        # 如果已经在跟踪,更新跟踪器
        if tracking and tracker is not None:
            success, bbox = tracker.update(frame)
            if success:
                x, y, w, h = [int(v) for v in bbox]
                cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 3)
                cv2.putText(frame, "Tracking", (x, y-10),
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
            else:
                tracking = False
                print("跟踪丢失")
        # 显示结果
        cv2.imshow("原始帧", frame)
        cv2.imshow("前景掩码", fgMask)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

使用预训练YOLO进行目标检测和跟踪

import cv2
import numpy as np
def yolo_with_tracking():
    """
    YOLO检测 + 跟踪
    """
    # 加载YOLO
    net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
    # 加载类别名称
    with open("coco.names", "r") as f:
        classes = [line.strip() for line in f.readlines()]
    # 获取输出层
    layer_names = net.getLayerNames()
    output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
    cap = cv2.VideoCapture(0)
    # 存储跟踪器
    trackers = []
    tracked_objects = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        height, width, channels = frame.shape
        # YOLO检测(每30帧检测一次)
        if cv2.waitKey(1) % 30 == 0:
            # 准备输入
            blob = cv2.dnn.blobFromImage(frame, 0.00392, (416, 416), 
                                        (0, 0, 0), True, crop=False)
            net.setInput(blob)
            outs = net.forward(output_layers)
            # 处理检测结果
            boxes = []
            confidences = []
            class_ids = []
            for out in outs:
                for detection in out:
                    scores = detection[5:]
                    class_id = np.argmax(scores)
                    confidence = scores[class_id]
                    if confidence > 0.5:
                        center_x = int(detection[0] * width)
                        center_y = int(detection[1] * height)
                        w = int(detection[2] * width)
                        h = int(detection[3] * height)
                        x = int(center_x - w / 2)
                        y = int(center_y - h / 2)
                        boxes.append([x, y, w, h])
                        confidences.append(float(confidence))
                        class_ids.append(class_id)
            # 应用非极大值抑制
            indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
            # 为检测到的目标创建跟踪器
            trackers = []
            tracked_objects = []
            if len(indexes) > 0:
                for i in indexes.flatten():
                    x, y, w, h = boxes[i]
                    label = str(classes[class_ids[i]])
                    # 创建跟踪器
                    tracker = cv2.TrackerCSRT_create()
                    tracker.init(frame, (x, y, w, h))
                    trackers.append(tracker)
                    tracked_objects.append(label)
        # 更新所有跟踪器
        for i, tracker in enumerate(trackers):
            success, bbox = tracker.update(frame)
            if success:
                x, y, w, h = [int(v) for v in bbox]
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
                cv2.putText(frame, tracked_objects[i], (x, y-10),
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        cv2.imshow("YOLO + 跟踪", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

常用跟踪器对比

def compare_trackers():
    """
    比较不同跟踪器的性能
    """
    trackers = {
        'BOOSTING': cv2.TrackerBoosting_create(),
        'MIL': cv2.TrackerMIL_create(),
        'KCF': cv2.TrackerKCF_create(),
        'TLD': cv2.TrackerTLD_create(),
        'MEDIANFLOW': cv2.TrackerMedianFlow_create(),
        'CSRT': cv2.TrackerCSRT_create()
    }
    cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    # 选择跟踪目标
    bbox = cv2.selectROI("选择目标", frame, False)
    cv2.destroyWindow("选择目标")
    # 初始化所有跟踪器
    active_trackers = {}
    for name, tracker in trackers.items():
        tracker.init(frame, bbox)
        active_trackers[name] = tracker
    # 显示跟踪结果对比
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        results_frame = frame.copy()
        for name, tracker in active_trackers.items():
            success, bbox = tracker.update(frame)
            if success:
                x, y, w, h = [int(v) for v in bbox]
                cv2.rectangle(results_frame, (x, y), (x+w, y+h), 
                            (0, 255, 0), 2)
                cv2.putText(results_frame, f"{name}: OK", (x, y-10),
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
            else:
                cv2.putText(results_frame, f"{name}: Lost", 
                           (50, 50 + list(active_trackers.keys()).index(name)*30),
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.imshow("跟踪器对比", results_frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

使用建议

  1. 选择合适的跟踪器

    • CSRT: 准确度高,适合复杂场景
    • KCF: 速度快,适合实时应用
    • MIL: 鲁棒性好,但速度较慢
  2. 性能优化

    • 降低分辨率
    • 使用灰度图像
    • 限制跟踪区域
  3. 鲁棒性提升

    • 结合多种跟踪方法
    • 定期重新检测
    • 使用光流法辅助

这些案例涵盖了OpenCV中常见的跟踪方法,可以根据具体需求选择和调整。

抱歉,评论功能暂时关闭!