Python phát hiện và đếm đối tượng

Trong dự án python này, chúng tôi sẽ xây dựng Hệ thống đếm và phát hiện con người thông qua Webcam hoặc bạn có thể cung cấp video hoặc hình ảnh của riêng mình. Đây là một dự án học sâu cấp trung cấp về thị giác máy tính, dự án này sẽ giúp bạn nắm vững các khái niệm và giúp bạn trở thành chuyên gia trong lĩnh vực Khoa học dữ liệu. Hãy xây dựng một dự án thú vị

Phát hiện con người với Computer Vision

Điều kiện tiên quyết của dự án

Dự án bằng Python yêu cầu bạn phải có kiến ​​thức cơ bản về lập trình python và thư viện OpenCV. Chúng tôi sẽ cần các thư viện sau

  • OpenCV. Một thư viện mạnh được sử dụng cho máy học
  • imutils. để xử lý hình ảnh
  • Nặng nề. Được sử dụng cho máy tính khoa học. Hình ảnh được lưu trữ trong một mảng numpy
  • Argparse. Được sử dụng để cung cấp đầu vào trong dòng lệnh

Để cài đặt thư viện cần thiết, hãy chạy đoạn mã sau trong thiết bị đầu cuối của bạn

pip install opencv-python
pip install imutils
pip install numpy

Tải xuống mã dự án

Trước khi tiếp tục, vui lòng tải xuống nguồn của dự án phát hiện con người theo thời gian thực. Dự án phát hiện và đếm con người

Biểu đồ của Bộ mô tả Gradient định hướng

HOG là một bộ mô tả tính năng được sử dụng trong thị giác máy tính và xử lý hình ảnh với mục đích phát hiện đối tượng. Đây là một trong những kỹ thuật phổ biến nhất để phát hiện đối tượng, theo may mắn của chúng tôi, OpenCV đã được triển khai theo cách hiệu quả để kết hợp thuật toán HOG Descriptor với Support Vector Machine hoặc SVM

Các bước để xây dựng dự án phát hiện con người

1. Nhập thư viện

import cv2
import imutils
import numpy as np
import argparse

2. Tạo một mô hình sẽ phát hiện Con người

Như đã thảo luận trước đó, Chúng tôi sẽ sử dụng HOGDescriptor với SVM đã được triển khai trong OpenCV. mã dưới đây sẽ làm công việc này

HOGCV = cv2.HOGDescriptor[]
HOGCV.setSVMDetector[cv2.HOGDescriptor_getDefaultPeopleDetector[]]

cv2. HOGDescriptor_getDefaultPeopleDetector[] gọi mô hình được đào tạo trước để phát hiện OpenCV của con người và sau đó chúng tôi sẽ cung cấp cho máy vectơ hỗ trợ của mình với mô hình đó

3. phương pháp phát hiện[]

Ở đây, phép thuật thực sự sẽ xảy ra

Video. Một video kết hợp một chuỗi các hình ảnh để tạo thành một bức tranh chuyển động. Chúng tôi gọi những hình ảnh này là Frame. Vì vậy, nói chung, chúng tôi sẽ phát hiện người trong khung. Và cho nó xem nó giống như một video

Đó chính xác là những gì phương thức Detect[] của chúng ta sẽ làm. Nó sẽ mất một khung hình để phát hiện một người trong đó. Tạo một hộp xung quanh một người và hiển thị khung. và trả lại khung với người được bao quanh bởi một hộp màu xanh lá cây

def detect[frame]:
    bounding_box_cordinates, weights =  HOGCV.detectMultiScale[frame, winStride = [4, 4], padding = [8, 8], scale = 1.03]
    
    person = 1
    for x,y,w,h in bounding_box_cordinates:
        cv2.rectangle[frame, [x,y], [x+w,y+h], [0,255,0], 2]
        cv2.putText[frame, f'person {person}', [x,y], cv2.FONT_HERSHEY_SIMPLEX, 0.5, [0,0,255], 1]
        person += 1
    
    cv2.putText[frame, 'Status : Detecting ', [40,40], cv2.FONT_HERSHEY_DUPLEX, 0.8, [255,0,0], 2]
    cv2.putText[frame, f'Total Persons : {person-1}', [40,70], cv2.FONT_HERSHEY_DUPLEX, 0.8, [255,0,0], 2]
    cv2.imshow['output', frame]

    return frame

Mọi thứ sẽ được thực hiện bởi detectMultiScale[]. Nó trả về 2-tuple

  1. Danh sách chứa Tọa độ giới hạn Hộp người.
    Tọa độ có dạng X, Y, W, H.
    Trong đó x,y là tọa độ bắt đầu của hộp và w, h lần lượt là chiều rộng và chiều cao của hộp.
  2. Giá trị tự tin rằng đó là một người

Bây giờ, chúng tôi có phương pháp phát hiện của chúng tôi. Hãy tạo một máy dò

4. Phương thức HumanDetector[]

Có hai cách để lấy Video

  1. máy ảnh web
  2. Đường dẫn của tập tin được lưu trữ

Trong dự án học sâu này, chúng ta đã học cách tạo bộ đếm người bằng cách sử dụng HOG và OpenCV để tạo bộ đếm người hiệu quả. Chúng tôi đã phát triển dự án nơi bạn có thể cung cấp đầu vào như. video, hình ảnh hoặc thậm chí là máy ảnh trực tiếp. Đây là một dự án trình độ trung cấp, chắc chắn sẽ giúp bạn thành thạo các thư viện python và deep learning

Mạng lưới thần kinh nhân tạo đã cách mạng hóa toàn bộ ngành công nghiệp AI. Học sâu là một sản phẩm phụ cũng như một kỹ thuật tiên tiến bên trong Trí tuệ nhân tạo. Học sâu giúp chúng tôi giải quyết các vấn đề liên quan đến ngành và thời gian thực phức tạp

Hôm nay chúng tôi sẽ phát triển hệ thống đếm và theo dõi người, trong đó chúng tôi sẽ lấy một đường tham chiếu trên khung và nếu một người đi xuống đường tham chiếu, chúng tôi sẽ tăng bộ đếm xuống và nếu người đó đi lên đường tham chiếu, chúng tôi sẽ tăng lên

Nội dung

1. phương pháp luận

2. Yêu cầu dự án

3. Theo dõi và đếm

4. Trình theo dõi trung tâm

5. Các tệp cần thiết trước

6. Dự án cuối cùng

Phương pháp cho Dự án Đếm và Theo dõi Người

Mục tiêu là xây dựng một hệ thống có các tính năng sau

  • Đọc các khung hình từ Video
  • Vẽ một đường tham chiếu mong muốn trên khung đầu vào
  • Phát hiện người sử dụng mô hình phát hiện đối tượng
  • Đánh dấu trọng tâm trên người được phát hiện
  • Theo dõi chuyển động của trọng tâm được đánh dấu đó
  • Tính toán hướng chuyển động của trọng tâm [cho dù nó đang di chuyển lên trên hay xuống dưới]
  • Đếm số người vào hoặc ra khỏi một dòng tham chiếu
  • Dựa trên việc đếm, tăng bộ đếm lên hoặc xuống

Đây là những bước cơ bản chúng ta cần làm theo để xây dựng dự án học sâu. Bây giờ chúng ta hãy chuyển sang các yêu cầu

Đếm người và theo dõi Yêu cầu dự án

Chúng tôi có thể xây dựng dự án deep learning  cục bộ vì dự án này không có nhiều thành phần phụ thuộc.
Cài đặt thư viện.

  • cài đặt pip opencv-python==3. 4. 2. 16

Sau đó, chúng tôi cần một tệp python cho Centroidtracker

Ở đây chúng tôi sẽ sử dụng YOLO v3 làm mô hình phát hiện người trong khung hình. Vì vậy, chúng tôi cần tải xuống các trọng số YOLO v3 và các tệp cấu hình YOLO v3 cũng như các lớp coco là coco. tập tin tên. Bạn có thể tải xuống tương tự từ đây

Đây là video thử nghiệm

Theo dõi và đếm

Các kỹ thuật theo dõi đối tượng sử dụng các phương thức như deep sort, centroid tracker, csrt, kcf và camshift để theo dõi đối tượng được phát hiện bằng cách so sánh sự giống nhau của các đối tượng được phát hiện với nhau trong mỗi khung được xử lý. Nếu đối tượng có cùng chỉ số tương tự trong toàn khung thì đối tượng sẽ theo dõi cùng một đối tượng trong chuỗi khung và giữ lại cùng một ID đối tượng cho đối tượng đó. ID đối tượng không đổi này cho một đối tượng cụ thể giúp chúng tôi thực hiện các thao tác đếm dễ dàng hơn

Chúng tôi có thể sử dụng bất kỳ một trong các phương pháp nêu trên để theo dõi. Thông thường, chúng tôi sử dụng phương pháp sắp xếp sâu, phương pháp này cho đầu ra rất tốt so với bất kỳ trình theo dõi nào khác và nó cũng cho khung hình mỗi giây [FPS] tốt hơn so với trình theo dõi trung tâm và phần còn lại, nhưng nhược điểm chính của phương pháp sắp xếp sâu . Ở đây chúng tôi sẽ sử dụng trình theo dõi centroid trong dự án của chúng tôi. Khi chúng tôi đã giữ đúng đối tượng được phát hiện trong suốt các khung, thì chúng tôi có thể thực hiện thao tác đếm, thao tác IN-OUT đối tượng trên đối tượng đó

Trình theo dõi trung tâm

Trình theo dõi centroid có các bước sau

    • Chấp nhận tọa độ hộp giới hạn và tính toán trọng tâm
    • Thuật toán chấp nhận tọa độ hộp giới hạn là xmin, ymin, xmax và ymax và tọa độ cho [x_center, y_center] cho từng đối tượng được phát hiện trong mỗi khung
    • Centroid được tính toán được đưa ra dưới đây

 X_cen = [[xmin + xmax] // 2
Y_cen = [[ymin + ymax] // 2]

trong đó xmin, ymin, xmax và ymax là tọa độ hộp giới hạn cho mô hình phát hiện đối tượng  [ở đây là YOLO v3]

    • Sau đó, nó tính toán khoảng cách euclidian giữa hộp giới hạn mới được phát hiện và đối tượng hiện có

    • Cập nhật trọng tâm cho đối tượng hiện có. Sau khi tính toán khoảng cách euclidian giữa hộp giới hạn được phát hiện và hộp giới hạn hiện có, nó sẽ cập nhật vị trí của tâm trong khung, ở đó bằng cách theo dõi đối tượng

    • Đăng ký đối tượng mới. Khi một đối tượng mới xâm nhập hoặc cùng một đối tượng được phát hiện, trình theo dõi trung tâm sẽ đăng ký đối tượng mới với một ID duy nhất, để nó trở nên hữu ích cho các ứng dụng khác nhau

    • Hủy đăng ký các đối tượng trước đó. Khi đối tượng không có trong khung, thuật toán sẽ hủy đăng ký ID đối tượng, cho biết đối tượng không có sẵn hoặc rời khỏi khung

Đây là hoạt động cơ bản của theo dõi centroid

Ở đây đối với mô hình phát hiện đối tượng, chúng tôi sẽ sử dụng mô hình YOLO v3, để phát hiện một lớp người trong khung. Tải xuống trọng lượng và cấu hình YOLO [. cfg] từ phần trên

Các tệp cần thiết trước để đếm và theo dõi người

Tạo một thư mục có tên 'utils' và bên trong thư mục 'utils' tạo một tệp python và đặt tên là 'centroidtracker [centroidtracker. py]’ và tạo một tệp python khác trong cùng thư mục ‘utils’ và đặt tên là ‘object_trackable [object_trackable. py]'

Mở centroidtracker. py và sao chép nội dung bên dưới vào đó. Chúng tôi làm theo các bước có trong trình theo dõi trung tâm như đã thảo luận trong phần trên. Về cơ bản, chúng tôi có ba chức năng bên trong lớp CentroidTracker, đó là chức năng đăng ký để đăng ký đối tượng được phát hiện, chức năng hủy đăng ký để xóa đối tượng khỏi sổ đăng ký và chức năng cập nhật cập nhật chuyển động của đối tượng được phát hiện trong các khung

###########################
# centroidtracker.py
###########################
# import the necessary packages
from scipy.spatial import distance as dist
from collections import OrderedDict
import numpy as np

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects

Bây giờ, hãy mở object_trackable. py và sao chép nội dung bên dưới. Ở đây bên trong lớp, chúng tôi sẽ lưu trữ ID đối tượng, sau đó khởi tạo danh sách các trọng tâm bằng cách sử dụng trọng tâm hiện tại. Sau đó, chúng tôi sẽ khởi tạo một boolean được sử dụng để cho biết đối tượng đã được đếm hay chưa

###########################
# object_trackable.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

Sau đó di chuyển trọng số YOLO v3 và tệp cấu hình, coco. tệp tên và video thử nghiệm đầu vào vào cùng một thư mục dự án. Khi mọi thứ đã sẵn sàng, thư mục dự án sẽ trông giống như thế này

Dự án theo dõi và đếm người cuối cùng

Tạo một tệp python và bắt đầu viết tập lệnh phát hiện cho dự án học sâu

Đầu tiên, chúng tôi sẽ nhập các thư viện cần thiết và chúng tôi sẽ nhập lớp CentroidTracker và TrackableObject từ thư mục utils

import cv2
import argparse
import sys
import numpy as np
import os.path
import math
from utils.centroidtracker import CentroidTracker
from utils.object_trackable import TrackableObject

Sau đó, Khởi tạo các tham số nhất định để phát hiện và chiều rộng và chiều cao của hình ảnh đầu vào

________số 8

Bây giờ, chúng tôi sẽ tạo trình phân tích cú pháp Đối số để chúng tôi có thể chuyển video thử nghiệm làm đối số đầu vào cho tập lệnh của mình. Sau đó, chúng ta sẽ đọc coco. tệp tên và lưu trữ các lớp trong một biến. Cung cấp các tệp cấu hình và trọng lượng cho mô hình và tải mạng bằng cách sử dụng chúng

parser = argparse.ArgumentParser[description='People Tracking and Counting Project']
parser.add_argument['--video', help='Path to video file.']
args = parser.parse_args[]
import cv2
import imutils
import numpy as np
import argparse
0
import cv2
import imutils
import numpy as np
import argparse
1

Tải mô hình được đăng nhiều kỳ, khởi chạy trình ghi video và sau đó tại đây, chúng tôi sẽ khởi tạo kích thước khung hình [chúng tôi sẽ đặt chúng ngay khi đọc khung hình đầu tiên từ video]

import cv2
import imutils
import numpy as np
import argparse
2____13
class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
0

Bây giờ, khởi tạo trình theo dõi trung tâm, sau đó khởi tạo danh sách để lưu trữ từng trình theo dõi tương quan và từ điển để ánh xạ ID đối tượng duy nhất của từng phát hiện thành TrackableObject. Sau đó, khởi tạo số lượng khung được xử lý, cùng với tổng số đối tượng đã di chuyển lên hoặc xuống

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
1
class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
2

Chúng ta sẽ viết một hàm nhỏ để lấy tên của các lớp đầu ra

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
3

Bây giờ, chúng ta hãy viết một hàm tiền xử lý để loại bỏ các hộp giới hạn với độ tin cậy thấp bằng cách sử dụng triệt tiêu không tối đa. Bên trong chức năng này, chúng tôi sẽ quét qua tất cả các hộp giới hạn đầu ra từ mạng và chỉ giữ lại những hộp có điểm tin cậy cao. Sau đó, thực hiện triệt tiêu không tối đa để loại bỏ các hộp giới hạn dư thừa với độ tin cậy thấp hơn. Cuối cùng, khi chúng tôi nhận được lớp [người] mong muốn, chúng tôi sẽ sử dụng trình theo dõi trọng tâm để liên kết trọng tâm đối tượng cũ với trọng tâm đối tượng mới được tính toán

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
4
class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
5

Viết hàm đếm lặp qua các đối tượng được theo dõi trong khung và kiểm tra xem đối tượng có tồn tại hay không đối với một ID đối tượng cụ thể, nếu không có đối tượng tồn tại, nó sẽ tạo một đối tượng. Nếu có một đối tượng có thể theo dõi, chúng ta cần tìm hướng chuyển động của trọng tâm, để chỉ định xem nó đang đi lên hay đi xuống. Kiểm tra xem đối tượng có được tính hay không và lưu trữ đối tượng có thể theo dõi trong từ điển và đặt các chi tiết cần thiết vào khung

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
6
class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
7

Bây giờ, chúng tôi sẽ lấy đầu vào. Nó có thể là video hoặc đầu vào thời gian thực từ webcam và chúng tôi cũng sẽ sử dụng cv2. VideoWriter để lưu video đầu ra

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
8

Phần chính, bên trong vòng lặp while, chúng tôi sẽ tích hợp mọi thứ, đầu tiên, chúng tôi sẽ đọc nguồn cấp dữ liệu video và sau đó dựa trên video, chúng tôi sẽ vẽ một đường tham chiếu trên khung để chúng tôi có thể duy trì số lượng tăng và giảm đối với điều đó . Chúng ta cần ngắt quá trình thực thi nếu đến cuối video. Bên trong vòng lặp, tạo một đốm màu từ khung, đặt đầu vào và sử dụng chức năng tiền xử lý để xóa các hộp giới hạn với độ tin cậy rất thấp, sau đó viết từng khung một rồi hiển thị

class CentroidTracker:
def __init__[self, maxDisappeared=50, maxDistance=50]:
# initialize the next unique object ID along with two ordered
# dictionaries used to keep track of mapping a given object
# ID to its centroid and number of consecutive frames it has
# been marked as "disappeared", respectively
self.nextObjectID = 0
self.objects = OrderedDict[]
self.disappeared = OrderedDict[]

# store the number of maximum consecutive frames a given
# object is allowed to be marked as "disappeared" until we
# need to deregister the object from tracking
self.maxDisappeared = maxDisappeared

# store the maximum distance between centroids to associate
# an object -- if the distance is larger than this maximum
# distance we'll start to mark the object as "disappeared"
self.maxDistance = maxDistance

def register[self, centroid]:
# when registering an object we use the next available object
# ID to store the centroid
self.objects[self.nextObjectID] = centroid
self.disappeared[self.nextObjectID] = 0
self.nextObjectID += 1

def deregister[self, objectID]:
# to deregister an object ID we delete the object ID from
# both of our respective dictionaries
del self.objects[objectID]
del self.disappeared[objectID]

def update[self, rects]:
# check to see if the list of input bounding box rectangles
# is empty
if len[rects] == 0:
# loop over any existing tracked objects and mark them
# as disappeared
for objectID in list[self.disappeared.keys[]]:
self.disappeared[objectID] += 1

# if we have reached a maximum number of consecutive
# frames where a given object has been marked as
# missing, deregister it
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# return early as there are no centroids or tracking info
# to update
return self.objects

# initialize an array of input centroids for the current frame
inputCentroids = np.zeros[[len[rects], 2], dtype="int"]

# loop over the bounding box rectangles
for [i, [startX, startY, endX, endY]] in enumerate[rects]:
# use the bounding box coordinates to derive the centroid
cX = int[[startX + endX] / 2.0]
cY = int[[startY + endY] / 2.0]
inputCentroids[i] = [cX, cY]

# if we are currently not tracking any objects take the input
# centroids and register each of them
if len[self.objects] == 0:
for i in range[0, len[inputCentroids]]:
self.register[inputCentroids[i]]

# otherwise, are are currently tracking objects so we need to
# try to match the input centroids to existing object
# centroids
else:
# grab the set of object IDs and corresponding centroids
objectIDs = list[self.objects.keys[]]
objectCentroids = list[self.objects.values[]]

# compute the distance between each pair of object
# centroids and input centroids, respectively -- our
# goal will be to match an input centroid to an existing
# object centroid
D = dist.cdist[np.array[objectCentroids], inputCentroids]

# in order to perform this matching we must [1] find the
# smallest value in each row and then [2] sort the row
# indexes based on their minimum values so that the row
# with the smallest value as at the *front* of the index
# list
rows = D.min[axis=1].argsort[]

# next, we perform a similar process on the columns by
# finding the smallest value in each column and then
# sorting using the previously computed row index list
cols = D.argmin[axis=1][rows]

# in order to determine if we need to update, register,
# or deregister an object we need to keep track of which
# of the rows and column indexes we have already examined
usedRows = set[]
usedCols = set[]

# loop over the combination of the [row, column] index
# tuples
for [row, col] in zip[rows, cols]:
# if we have already examined either the row or
# column value before, ignore it
if row in usedRows or col in usedCols:
continue

# if the distance between centroids is greater than
# the maximum distance, do not associate the two
# centroids to the same object
if D[row, col] > self.maxDistance:
continue

# otherwise, grab the object ID for the current row,
# set its new centroid, and reset the disappeared
# counter
objectID = objectIDs[row]
self.objects[objectID] = inputCentroids[col]
self.disappeared[objectID] = 0

# indicate that we have examined each of the row and
# column indexes, respectively
usedRows.add[row]
usedCols.add[col]

# compute both the row and column index we have NOT yet
# examined
unusedRows = set[range[0, D.shape[0]]].difference[usedRows]
unusedCols = set[range[0, D.shape[1]]].difference[usedCols]

# in the event that the number of object centroids is
# equal or greater than the number of input centroids
# we need to check and see if some of these objects have
# potentially disappeared
if D.shape[0] >= D.shape[1]:
# loop over the unused row indexes
for row in unusedRows:
# grab the object ID for the corresponding row
# index and increment the disappeared counter
objectID = objectIDs[row]
self.disappeared[objectID] += 1

# check to see if the number of consecutive
# frames the object has been marked "disappeared"
# for warrants deregistering the object
if self.disappeared[objectID] > self.maxDisappeared:
self.deregister[objectID]

# otherwise, if the number of input centroids is greater
# than the number of existing object centroids we need to
# register each new input centroid as a trackable object
else:
for col in unusedCols:
self.register[inputCentroids[col]]

# return the set of trackable objects
return self.objects
9

Sau tất cả các bước này, thư mục dự án trông như thế này

Toàn bộ đoạn mã để phát hiện được đưa ra dưới đây

import cv2
import argparse
import sys
import numpy as np
import os.path
import math
from utils.centroidtracker import CentroidTracker
from utils.object_trackable import TrackableObject
###########################
# object_trackable.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
1

Bây giờ, hãy để chúng tôi chạy tập tin của chúng tôi. Chỉ cần mở terminal và gõ lệnh dưới đây

###########################
# object_trackable.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
2

Trên đây là khung đầu ra. Khi nó chạy trên video hoàn chỉnh, video đầu ra sẽ được lưu trong cùng thư mục dự án

Toàn bộ dự án có sẵn ở đây

Hy vọng bạn thích nó

Sự kết luận

Dự án học sâu này có thể được triển khai trong nhiều ứng dụng cũng như cho nhiều đối tượng khác nhau. Tốc độ phát hiện có thể chậm, nhưng đây là điều cơ bản của việc đếm và theo dõi đối tượng trong một khung hình. Hơn nữa, bạn có thể triển khai các ý tưởng tương tự bằng cách sử dụng các trình theo dõi khác nhau như Deep sort, csrt, v.v. và các mô hình phát hiện đối tượng khác nhau để kiểm tra tốc độ suy luận và độ chính xác của nó

Ghi chú. Tất cả các hình ảnh được tạo ra bởi tác giả

LinkedIn của tôi

Cảm ơn

Phương tiện hiển thị trong bài viết này không thuộc sở hữu của Analytics Vidhya và được sử dụng theo quyết định của Tác giả

Chủ Đề