- Messages
- 181
- Points
- 28
Greetings everyone,
Sharing some code which also a lot of parts were taken from Object Detection Course - Computer Vision Zone
This version is modified to suit my needs at home camera, so it wont be exactly the same. As well you will have to edit the line coordinates/mask.png yourself as well
Translate: Automobili = Cars/ Ljudi = Persons
TODO:
-Whenever object trigger linecrossing, send PUT request to textOverlay and change OSD on camera to show actual data instead of watching it on python frame.
-Update database with values to have history of crossing
-Option to make a report depending on time interval
-Separating Bicycle from persons, so it does not count both(when bicycle is added to detection)
-Fix wrong way counter for slow moving objects.
As i am polishing for my scene, i will be updating here the results.
Cheers.
Sharing some code which also a lot of parts were taken from Object Detection Course - Computer Vision Zone
This version is modified to suit my needs at home camera, so it wont be exactly the same. As well you will have to edit the line coordinates/mask.png yourself as well
Code:
import numpy as np
from ultralytics import YOLO
import cv2
import cvzone
import math
from sort import *
cap = cv2.VideoCapture(r"rtsp://admin:*****@192.168.100.25:554/Streaming/channels/102") # For Video 1280x720 substream
model = YOLO("../Yolo-Weights/yolov8l.pt")
classNames = ["person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", "boat",
"traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat",
"dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella",
"handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup",
"fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli",
"carrot", "hot dog", "pizza", "donut", "cake", "chair", "sofa", "pottedplant", "bed",
"diningtable", "toilet", "tvmonitor", "laptop", "mouse", "remote", "keyboard", "cell phone",
"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors",
"teddy bear", "hair drier", "toothbrush"
]
mask = cv2.imread("mask.png")
# Tracking
tracker = Sort(max_age=30, min_hits=3, iou_threshold=0.3)
# Line coordinates for counting
limits = [442, 138, 693, 426]
# Counters for different categories and directions
cars_left, cars_right = 0, 0
persons_left, persons_right = 0, 0
# To track previous positions for extrapolation and object count status
previous_positions = {}
counted_objects = {}
while True:
success, img = cap.read()
if not success:
break
imgRegion = cv2.bitwise_and(img, mask)
results = model(imgRegion, stream=True)
detections = np.empty((0, 5))
# Gather detections from the YOLO model
for r in results:
boxes = r.boxes
for box in boxes:
# Bounding Box
x1, y1, x2, y2 = box.xyxy[0]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
w, h = x2 - x1, y2 - y1
# Confidence
conf = math.ceil((box.conf[0] * 100)) / 100
# Class Name
cls = int(box.cls[0])
currentClass = classNames[cls]
# Consider persons and bicycles together, and vehicles separately
if currentClass in ["car", "truck", "motorbike", "person"] and conf > 0.3:
currentArray = np.array([x1, y1, x2, y2, conf])
detections = np.vstack((detections, currentArray))
# Update the tracker with detections
resultsTracker = tracker.update(detections)
# Draw the counting line
cv2.line(img, (limits[0], limits[1]), (limits[2], limits[3]), (0, 0, 255), 5)
# Process tracked objects
for result in resultsTracker:
x1, y1, x2, y2, id = result
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
w, h = x2 - x1, y2 - y1
cx, cy = x1 + w // 2, y1 + h // 2 # Calculate object center
# Draw the object bounding box and ID
cvzone.cornerRect(img, (x1, y1, w, h), l=9, rt=2, colorR=(255, 0, 255))
cvzone.putTextRect(img, f' {int(id)}', (max(0, x1), max(35, y1)), scale=2, thickness=3, offset=10)
# Initialize counted status for this object if not already tracked
if id not in counted_objects:
counted_objects[id] = {"counted_left": False, "counted_right": False}
# Determine if the object is moving left or right
if id in previous_positions:
prev_cx, prev_cy = previous_positions[id]
# If the object crosses the line, track its direction and type
if ((prev_cy < limits[1] and cy > limits[1]) or (prev_cy > limits[1] and cy < limits[1])
or (y1 < limits[1] < y2)): # Check if bounding box crosses the line
direction = "left" if cx < prev_cx else "right" # Determine the direction of movement
# Count cars, trucks, motorbikes
if currentClass in ["car", "truck", "motorbike"]:
if direction == "left" and not counted_objects[id]["counted_left"]:
cars_left += 1
counted_objects[id]["counted_left"] = True
elif direction == "right" and not counted_objects[id]["counted_right"]:
cars_right += 1
counted_objects[id]["counted_right"] = True
# Count persons and bicycles together
elif currentClass in ["person"]:
if direction == "left" and not counted_objects[id]["counted_left"]:
persons_left += 1
counted_objects[id]["counted_left"] = True
elif direction == "right" and not counted_objects[id]["counted_right"]:
persons_right += 1
counted_objects[id]["counted_right"] = True
print(f"Object {id} crossed the line! Direction: {direction}, Class: {currentClass}")
# Update the previous position for this object
previous_positions[id] = (cx, cy)
# Display counters for all categories
cv2.putText(img, f"Car <--: {cars_left}", (50, 100), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)
cv2.putText(img, f"Car -->: {cars_right}", (50, 140), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)
cv2.putText(img, f"Person <--: {persons_left}", (50, 180), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)
cv2.putText(img, f"Person -->: {persons_right}", (50, 220), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)
# Show the resulting image
cv2.imshow("Image", img)
# Break if 'q' is pressed
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Release the video capture and close windows
cap.release()
cv2.destroyAllWindows()
Translate: Automobili = Cars/ Ljudi = Persons
TODO:
-Whenever object trigger linecrossing, send PUT request to textOverlay and change OSD on camera to show actual data instead of watching it on python frame.
-Update database with values to have history of crossing
-Option to make a report depending on time interval
-Separating Bicycle from persons, so it does not count both(when bicycle is added to detection)
-Fix wrong way counter for slow moving objects.
As i am polishing for my scene, i will be updating here the results.
Cheers.