尊重原创版权: https://www.conghengx.com/hot/43203.html
更多内容参考: https://www.conghengx.com/
在本教程中,您将学习如何使用 OpenCV 和 Python 构建人员计数器。使用 OpenCV,我们将实时计算进或出百货商店的人数。
在今天博客文章的第一部分,我们将讨论如何利用两者来创建更准确的人员计数器。之后,我们将查看项目的目录结构,然后实施整个人员计数项目。最后,我们将检查将
OpenCV 的人数统计应用到实际视频中的结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d6c6QRgO-1657169322117)(https://p9.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/ddbd50f1ec224a8685eceedb0fbfcd6c?from=pc)]
在继续本教程的其余部分之前,您必须了解对象检测和对象跟踪之间的根本区别。
当我们应用对象检测时,我们是在确定一个对象在图像/帧中的位置。与目标跟踪算法相比,目标检测器通常在计算上更昂贵,因此也更慢。目标检测算法的例子包括Haar级联、HOG
+线性支持向量机(HOG + Linear SVM)和基于深度学习的目标检测器,如Faster R-CNN、YOLO和Single
Shot检测器(SSD)。
另一方面,对象跟踪器将接受对象在图像中位置的输入 (x, y) 坐标,并将:
对象跟踪算法的示例包括 MedianFlow、MOSSE、GOTURN、核化相关滤波器和判别相关滤波器等。
高精度目标跟踪器将目标检测和目标跟踪的概念结合到一个算法中,通常分为两个阶段:
这种混合方法的好处是我们可以应用高度准确的对象检测方法,而无需太多的计算负担。我们将实施这样一个跟踪系统来建立我们的人员计数器。
这种混合方法的好处是我们可以应用高度准确的对象检测方法,而无需太多的计算负担。我们将实施这样一个跟踪系统来建立我们的人员计数器。
让我们回顾一下今天博客文章的项目结构。获取代码后,您可以使用 tree 命令检查目录结构:
$ tree --dirsfirst
.
├── pyimagesearch
│ ├── __init__.py
│ ├── centroidtracker.py
│ └── trackableobject.py
├── mobilenet_ssd
│ ├── MobileNetSSD_deploy.caffemodel
│ └── MobileNetSSD_deploy.prototxt
├── videos
│ ├── example_01.mp4
│ └── example_02.mp4
├── output
│ ├── output_01.avi
│ └── output_02.avi
└── people_counter.py
最重要的两个目录:
今天项目的核心包含在 people_counter.py 脚本中——这是我们将花费大部分时间的地方。今天我们还将回顾 trackableobject.py
脚本。
为了实现我们的人员计数器,我们将同时使用 OpenCV 和 dlib。我们将 OpenCV
用于标准的计算机视觉/图像处理功能,以及用于人数统计的深度学习对象检测器。
然后我们将使用 dlib 来实现相关过滤器。我们也可以在这里使用 OpenCV;但是,对于这个项目,dlib 对象跟踪实现更容易使用。
除了 dlib 的对象跟踪实现,我们还将使用质心跟踪实现。回顾整个质心跟踪算法超出了这篇博文的范围,但我在下面提供了一个简短的概述。
在步骤#1,我们接受一组边界框并计算它们对应的质心(即边界框的中心):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EjFyZFGs-1657169322118)(https://p9.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/fb8c4dee1354439bad5e99ab51aa7c96?from=pc)]
要使用 Python 通过质心脚本构建简单的对象跟踪,第一步是接受边界框坐标并使用它们来计算质心。
边界框本身可以由以下任一方式提供:
在上图中,您可以看到我们在算法的初始迭代中有两个对象要跟踪。
在步骤#2中,我们计算任何新质心(黄色)和现有质心(紫色)之间的欧几里得距离:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LxU2TA82-1657169322119)(https://p9.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/4fe39e7c3d61462f94944ad497ca4c43?from=pc)]
此图像中存在三个对象。我们需要计算每对原始质心(紫色)和新质心(黄色)之间的欧几里得距离。
质心跟踪算法假设它们之间具有最小欧几里德距离的质心对必须是相同的对象 ID。
在上面的示例图像中,我们有两个现有的质心(紫色)和三个新的质心(黄色),这意味着已经检测到一个新对象(因为与旧质心相比,还有一个新质心)。
然后箭头表示计算所有紫色质心和所有黄色质心之间的欧几里得距离。一旦我们有了欧几里得距离,我们就会在步骤#3 中尝试关联对象 ID:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jIterKDL-1657169322120)(https://p9.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/029d3da9d99b4f4b8d085dbd4ffcd4b6?from=pc)]
您可以看到我们的质心跟踪器已选择关联使它们各自的欧几里得距离最小化的质心。但是左下角的点呢?它没有与任何东西相关联——我们该怎么办?
要回答这个问题,我们需要执行步骤#4,注册新对象:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agNiGaNm-1657169322121)(https://p9.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/00d09c22e66f44e0958e9992a5254ff2?from=pc)]
注册意味着我们通过以下方式将新对象添加到我们的跟踪对象列表中:
如果对象丢失或离开视野,我们可以简单地取消注册对象(步骤#5)。
为了跟踪和计算视频流中的对象,我们需要一种简单的方法来存储有关对象本身的信息,包括:
为了实现所有这些目标,我们可以定义一个 TrackableObject 实例——打开 trackableobject.py 文件并插入以下代码:
class TrackableObject:
def __init__(self, objectID, centroid):
# store the object ID, then initialize a list of centroids
# using the current centroid
self.objectID = objectID
self.centroids = [centroid]
# initialize a boolean used to indicate if the object has
# already been counted or not
self.counted = False
TrackableObject 构造函数接受 objectID + centroid 并存储它们。 centroids
变量是一个列表,因为它将包含对象的质心位置历史记录。 构造函数还将 counted 初始化为 False ,表示该对象还没有被计数。
# import the necessary packages
from pyimagesearch.centroidtracker import CentroidTracker
from pyimagesearch.trackableobject import TrackableObject
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import dlib
import cv2
我们首先导入必要的包:
现在所有工具都触手可及,让我们解析命令行参数:
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True,
help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
help="path to Caffe pre-trained model")
ap.add_argument("-i", "--input", type=str,
help="path to optional input video file")
ap.add_argument("-o", "--output", type=str,
help="path to optional output video file")
ap.add_argument("-c", "--confidence", type=float, default=0.4,
help="minimum probability to filter weak detections")
ap.add_argument("-s", "--skip-frames", type=int, default=30,
help="# of skip frames between detections")
args = vars(ap.parse_args())
我们有六个命令行参数,它们允许我们在运行时从终端将信息传递给我们的人员计数器脚本: