useSpatialAssociation flag. It is False by default, which means tracklets still carry spatial coordinates, but detection-to-track matching uses the standard 2D association path. Set it to True when depth is reliable and you want XYZ distance to help preserve IDs for overlapping or crossing objects.Demo

Pipeline
Source code
Python
PythonGitHub
1#!/usr/bin/env python3
2
3import cv2
4import depthai as dai
5import time
6
7
8fullFrameTracking = False
9useSpatialAssociation = False
10
11# Create pipeline
12with dai.Pipeline() as pipeline:
13 # Define sources and outputs
14 camRgb = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_A)
15 monoLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
16 monoRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C)
17
18 stereo = pipeline.create(dai.node.StereoDepth)
19 leftOutput = monoLeft.requestOutput((640, 400))
20 rightOutput = monoRight.requestOutput((640, 400))
21 leftOutput.link(stereo.left)
22 rightOutput.link(stereo.right)
23
24 spatialDetectionNetwork = pipeline.create(dai.node.SpatialDetectionNetwork).build(camRgb, stereo, "yolov6-nano")
25 objectTracker = pipeline.create(dai.node.ObjectTracker)
26
27 spatialDetectionNetwork.setConfidenceThreshold(0.6)
28 spatialDetectionNetwork.input.setBlocking(False)
29 spatialDetectionNetwork.setBoundingBoxScaleFactor(0.5)
30 spatialDetectionNetwork.setDepthLowerThreshold(100)
31 spatialDetectionNetwork.setDepthUpperThreshold(5000)
32 labelMap = spatialDetectionNetwork.getClasses()
33
34 objectTracker.setDetectionLabelsToTrack([0]) # track only person
35 # possible tracking types: ZERO_TERM_COLOR_HISTOGRAM, ZERO_TERM_IMAGELESS, SHORT_TERM_IMAGELESS, SHORT_TERM_KCF
36 objectTracker.setTrackerType(dai.TrackerType.SHORT_TERM_IMAGELESS)
37 # take the smallest ID when new object is tracked, possible options: SMALLEST_ID, UNIQUE_ID
38 objectTracker.setTrackerIdAssignmentPolicy(dai.TrackerIdAssignmentPolicy.SMALLEST_ID)
39 if useSpatialAssociation:
40 objectTracker.setSpatialAssociation(True)
41 objectTracker.setSpatialAssociationWeight(0.5)
42 objectTracker.setSpatialDistanceThreshold(1.5)
43 objectTracker.setSpatialDepthAwareScale(0.1)
44
45 preview = objectTracker.passthroughTrackerFrame.createOutputQueue()
46 tracklets = objectTracker.out.createOutputQueue()
47
48 if fullFrameTracking:
49 camRgb.requestFullResolutionOutput().link(objectTracker.inputTrackerFrame)
50 # do not block the pipeline if it's too slow on full frame
51 objectTracker.inputTrackerFrame.setBlocking(False)
52 objectTracker.inputTrackerFrame.setMaxSize(1)
53 else:
54 spatialDetectionNetwork.passthrough.link(objectTracker.inputTrackerFrame)
55
56 spatialDetectionNetwork.passthrough.link(objectTracker.inputDetectionFrame)
57 spatialDetectionNetwork.out.link(objectTracker.inputDetections)
58
59 startTime = time.monotonic()
60 counter = 0
61 fps = 0
62 color = (255, 255, 255)
63 pipeline.start()
64 while(pipeline.isRunning()):
65 imgFrame = preview.get()
66 track = tracklets.get()
67 assert isinstance(imgFrame, dai.ImgFrame), "Expected ImgFrame"
68 assert isinstance(track, dai.Tracklets), "Expected Tracklets"
69
70 counter+=1
71 current_time = time.monotonic()
72 if (current_time - startTime) > 1 :
73 fps = counter / (current_time - startTime)
74 counter = 0
75 startTime = current_time
76
77 frame = imgFrame.getCvFrame()
78 trackletsData = track.tracklets
79 for t in trackletsData:
80 roi = t.roi.denormalize(frame.shape[1], frame.shape[0])
81 x1 = int(roi.topLeft().x)
82 y1 = int(roi.topLeft().y)
83 x2 = int(roi.bottomRight().x)
84 y2 = int(roi.bottomRight().y)
85
86 try:
87 label = labelMap[t.label]
88 except:
89 label = t.label
90
91 cv2.putText(frame, str(label), (x1 + 10, y1 + 20), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
92 cv2.putText(frame, f"ID: {[t.id]}", (x1 + 10, y1 + 35), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
93 cv2.putText(frame, t.status.name, (x1 + 10, y1 + 50), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
94 cv2.rectangle(frame, (x1, y1), (x2, y2), color, cv2.FONT_HERSHEY_SIMPLEX)
95
96 cv2.putText(frame, f"X: {int(t.spatialCoordinates.x)} mm", (x1 + 10, y1 + 65), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
97 cv2.putText(frame, f"Y: {int(t.spatialCoordinates.y)} mm", (x1 + 10, y1 + 80), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
98 cv2.putText(frame, f"Z: {int(t.spatialCoordinates.z)} mm", (x1 + 10, y1 + 95), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
99 if t.velocity is not None and t.speed is not None:
100 cv2.putText(frame, f"Velocity X: {t.velocity.x:.2f} m/s", (x1 + 10, y1 + 110), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
101 cv2.putText(frame, f"Velocity Y: {t.velocity.y:.2f} m/s", (x1 + 10, y1 + 125), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
102 cv2.putText(frame, f"Velocity Z: {t.velocity.z:.2f} m/s", (x1 + 10, y1 + 140), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
103 cv2.putText(frame, f"Speed: {t.speed:.2f} m/s", (x1 + 10, y1 + 155), cv2.FONT_HERSHEY_TRIPLEX, 0.5, 255)
104
105 cv2.putText(frame, "NN fps: {:.2f}".format(fps), (2, frame.shape[0] - 4), cv2.FONT_HERSHEY_TRIPLEX, 0.4, color)
106
107 cv2.imshow("tracker", frame)
108
109 if cv2.waitKey(1) == ord('q'):
110 breakNeed assistance?
Head over to Discussion Forum for technical support or any other questions you might have.