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
- 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. - 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
- máy ảnh web
- Đườ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ố 8Bâ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 argparse0
import cv2 import imutils import numpy as np import argparse1
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 argparse2____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.objects0
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.objects1
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.objects2
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.objects3
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.objects4
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.objects5
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.objects6
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.objects7
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.objects8
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.objects9
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 = False1
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 = False2
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ả