下面是使用opencv生成检测超市进出口人流量的代码,包括C++和Python两种语言。代码中使用了HOG+SVM的方法来进行行人检测,实现了对超市进出口的人流量统计,为了避免重复统计行人,可以在检测到行人后,对其进行跟踪,直到其离开监控区域。一种简单的方法是,为每个检测到的行人分配一个唯一的ID,然后使用一个字典来存储行人的位置和ID。在每一帧中,对于新检测到的行人,分配新的ID,并将其添加到字典中。对于已经存在于字典中的行人,使用光流等方法来跟踪其运动轨迹,更新其位置信息。如果一个行人离开了监控区域,从字典中删除其ID。

c++代码

#include <iostream>
#include <fstream>
#include <sstream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    // 加载视频文件
    VideoCapture cap("test.mp4");
    if (!cap.isOpened()) {
        cerr << "视频文件打开失败!" << endl;
        return -1;
    }

    // 加载行人检测器
    HOGDescriptor hog;
    hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

    // 定义进出口区域
    Rect entrance(0, 0, 200, 480);
    Rect exit(600, 0, 200, 480);

    // 初始化计数器和跟踪器
    int count_in = 0;
    int count_out = 0;
    map<int, Rect> trackers;

    while (true) {
        Mat frame;
        cap >> frame;
        if (frame.empty()) {
            break;
        }

        // 检测行人
        vector<Rect> detections;
        hog.detectMultiScale(frame, detections);

        // 绘制检测框,进行跟踪
        for (Rect detection : detections) {
            Point center = (detection.tl() + detection.br()) / 2;

            // 查找最近的跟踪器
            double min_dist = numeric_limits<double>::max();
            int min_id = -1;
            for (auto& [id, tracker] : trackers) {
                Rect2d rect;
                tracker.update(frame, rect);
                Point pos = (rect.tl() + rect.br()) / 2;
                double dist = norm(center - pos);
                if (dist < min_dist) {
                    min_dist = dist;
                    min_id = id;
                }
            }

            // 新的行人
            if (min_id == -1 || min_dist > 50) {
                int new_id = trackers.empty() ? 0 : (prev(trackers.end())->first + 1);
                trackers[new_id] = detection;
                Ptr<TrackerKCF> tracker = TrackerKCF::create();
                tracker->init(frame, trackers[new_id]);
            }
            // 已有的行人
            else {
                Ptr<TrackerKCF> tracker = TrackerKCF::create();
                tracker->init(frame, trackers[min_id]);
                trackers[min_id] = detection;
                tracker->update(frame, trackers[min_id]);
            }

            // 判断行人是否进入或离开了进出口区域
            for (auto& [id, tracker] : trackers) {
                Point center = (tracker.tl() + tracker.br()) / 2;
                if (entrance.contains(center)) {
                    count_in++;
                    trackers.erase(id);
                }
                else if (exit.contains(center)) {
                    count_out++;
                    trackers.erase(id);
                }
            }
        }

        // 绘制进出口区域
        rectangle(frame, entrance, Scalar(0, 0, 255), 2);
        rectangle(frame, exit, Scalar(0, 255, 0), 2);

        // 绘制行人和计数
        for (auto& [id, tracker] : trackers) {
            rectangle(frame, tracker, Scalar(255, 0, 0), 2);
        }
        putText(frame, "In: " + to_string(count_in), Point(10, 30), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 0, 255), 2);
        putText(frame, "Out: " + to_string(count_out), Point(10, 60), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0), 2);

        // 显示结果
        imshow("Pedestrian Counting", frame);
        if (waitKey(1) == 27) {
            break;
        }
    }

    return 0;
}

Python 代码:

import cv2

# 加载HOG+SVM行人检测器
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())

# 打开视频文件
cap = cv2.VideoCapture('test.mp4')
if not cap.isOpened():
    print("视频文件打开失败!")
    exit()

# 定义进出口区域
entrance = (0, 0, 200, 480)
exit = (600, 0, 200, 480)

# 初始化计数器和跟踪器
count_in = 0
count_out = 0
trackers = {}

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

    # 检测行人
    detections, _ = hog.detectMultiScale(frame)

    # 绘制检测框,进行跟踪
    for detection in detections:
        x, y, w, h = detection
        center = (x + w // 2, y + h // 2)

        # 查找最近的跟踪器
        min_dist = float('inf')
        min_id = None
        for id, tracker in trackers.items():
            pos = tracker['tracker'].update(frame)
            pos = (int(pos[0]), int(pos[1]))
            dist = cv2.norm(center, pos)
            if dist < min_dist:
                min_dist = dist
                min_id = id

        # 新的行人
        if min_id is None or min_dist > 50:
            new_id = max(trackers.keys(), default=-1) + 1
            trackers[new_id] = {
                'tracker': cv2.TrackerKCF_create(),
                'pos': center,
                'rect': detection,
            }
            trackers[new_id]['tracker'].init(frame, trackers[new_id]['rect'])
        # 已有的行人
        else:
            tracker = trackers[min_id]['tracker']
            trackers[min_id]['pos'] = tracker.update(frame)
            trackers[min_id]['pos'] = (int(trackers[min_id]['pos'][0]), int(trackers[min_id]['pos'][1]))
            trackers[min_id]['rect'] = (x, y, w, h)
            tracker.init(frame, trackers[min_id]['rect'])

        # 判断行人是否进入或离开
        for id, tracker in trackers.items():
            if entrance[0] <= tracker['pos'][0] <= entrance[0] + entrance[2] \
                    and entrance[1] <= tracker['pos'][1] <= entrance[1] + entrance[3]:
                if not tracker.get('entered', False):
                    count_in += 1
                    tracker['entered'] = True
            elif exit[0] <= tracker['pos'][0] <= exit[0] + exit[2] \
                    and exit[1] <= tracker['pos'][1] <= exit[1] + exit[3]:
                if not tracker.get('exited', False):
                    count_out += 1
                    tracker['exited'] = True

    # 在画面上显示进出口和计数器
    cv2.rectangle(frame, entrance, (0, 255, 0), 2)
    cv2.rectangle(frame, exit, (0, 0, 255), 2)
    cv2.putText(frame, f"In: {count_in}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    cv2.putText(frame, f"Out: {count_out}", (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

    # 显示画面
    cv2.imshow("frame", frame)
    if cv2.waitKey(1) == ord('q'):
        break

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

   以上代码实现了基于光流的行人跟踪,使用了 trackers 字典来存储每个行人的唯一ID、位置、检测框和跟踪器。对于新检测到的行人,我们为其分配新的ID,并将其添加到字典中。对于已经存在于字典中的行人,我们使用 cv2.TrackerKCF 来跟踪其运动轨迹,并更新其位置和检测框。当一个行人进入或离开监控区域时,我们将相应的计数器增加,并在其对应的跟踪器中设置 entered 或 exited 标志。最后,在每一帧中,我们在画面上显示进出口区域和计数器,以及所有检测到的行人的位置和ID。

这是一个基本的行人计数器实现,你可以根据需求进行修改。

求关注,收藏,点赞 我将继续为您分享有关机器视觉方面的知识。