下面是使用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。
这是一个基本的行人计数器实现,你可以根据需求进行修改。
求关注,收藏,点赞 我将继续为您分享有关机器视觉方面的知识。