├── LICENSE ├── README.md ├── multi_object_tracker.py └── single_object_tracker.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Abhi Goswami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Object Tracking using OpenCV 2 | 3 | 4 | 5 | ### dependencies 6 | ```python 7 | pip install opencv-contrib-python==3.4.5.20 8 | ``` 9 | 10 | 11 | ### Brief highlight of each object tracker below: 12 | 13 | 1. BOOSTING Tracker: Based on the same algorithm used to power the machine learning behind Haar cascades (AdaBoost), but like Haar cascades, is over a decade old. This tracker is slow and doesn’t work very well. Interesting only for legacy reasons and comparing other algorithms. 14 | 15 | 2. MIL Tracker: Better accuracy than BOOSTING tracker but does a poor job of reporting failure. 16 | 17 | 3. KCF Tracker: Kernelized Correlation Filters. Faster than BOOSTING and MIL. Similar to MIL and KCF, does not handle full occlusion well. ation Filter (with Channel and Spatial Reliability). Tends to be more accurate than KCF but slightly slower. 18 | 19 | 4. CSRT Tracker: Discriminative Correlation Filter (with Channel and Spatial Reliability). Tends to be more accurate than KCF but slightly slower. 20 | 21 | 5. MedianFlow Tracker: Does a nice job reporting failures; however, if there is too large of a jump in motion, such as fast moving objects, or objects that change quickly in their appearance, the model will fail. 22 | 23 | 6. TLD Tracker: I’m not sure if there is a problem with the OpenCV implementation of the TLD tracker or the actual algorithm itself, but the TLD tracker was incredibly prone to false-positives. I do not recommend using this OpenCV object tracker. 24 | 25 | 7. MOSSE Tracker: Very, very fast. Not as accurate as CSRT or KCF but a good choice if you need pure speed. 26 | 27 | 8. GOTURN Tracker: The only deep learning-based object detector included in OpenCV. It requires additional caffe model files to run. 28 | 29 | 30 | 31 | ### My personal suggestion is to: 32 | 33 | 1. Use CSRT when you need higher object tracking accuracy and can tolerate slower FPS throughput 34 | 2. Use KCF when you need faster FPS throughput but can handle slightly lower object tracking accuracy 35 | 3. Use MOSSE when you need pure speed -------------------------------------------------------------------------------- /multi_object_tracker.py: -------------------------------------------------------------------------------- 1 | # USAGE 2 | # python multi_object_tracking.py --video videos/soccer_01.mp4 --tracker csrt 3 | 4 | # import the necessary packages 5 | import time 6 | import cv2 7 | import sys 8 | 9 | # initialize a dictionary that maps strings to their corresponding 10 | # OpenCV object tracker implementations 11 | 12 | (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.') 13 | 14 | tracker_types = ['BOOSTING', 'MIL', 'KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT'] 15 | tracker_type = tracker_types[2] 16 | 17 | if int(minor_ver) < 3: 18 | tracker_class = cv2.Tracker_create(tracker_type) 19 | else: 20 | if tracker_type == 'BOOSTING': 21 | tracker_class = cv2.TrackerBoosting_create 22 | elif tracker_type == 'MIL': 23 | tracker_class = cv2.TrackerMIL_create 24 | elif tracker_type == 'KCF': 25 | tracker_class = cv2.TrackerKCF_create 26 | elif tracker_type == 'TLD': 27 | tracker_class = cv2.TrackerTLD_create 28 | elif tracker_type == 'MEDIANFLOW': 29 | tracker_class = cv2.TrackerMedianFlow_create 30 | # elif tracker_type == 'GOTURN': 31 | # tracker = cv2.TrackerGOTURN_create() 32 | elif tracker_type == 'MOSSE': 33 | tracker_class = cv2.TrackerMOSSE_create 34 | elif tracker_type == "CSRT": 35 | tracker_class = cv2.TrackerCSRT_create 36 | 37 | # initialize OpenCV's special multi-object tracker 38 | trackers = cv2.MultiTracker_create() 39 | 40 | # if a video path was not supplied, grab the reference to the web cam 41 | video = cv2.VideoCapture('videos/video.mp4') 42 | if not video.isOpened(): 43 | print("Could not open video") 44 | sys.exit() 45 | 46 | # loop over frames from the video stream 47 | while True: 48 | # grab the current frame, then handle if we are using a 49 | # VideoStream or VideoCapture object 50 | ok, frame = video.read() 51 | 52 | # check to see if we have reached the end of the stream 53 | if ok is None or frame is None: 54 | break 55 | 56 | # resize the frame (so we can process it faster) 57 | frame = cv2.resize(frame, (720, 640)) 58 | 59 | # grab the updated bounding box coordinates (if any) for each 60 | # object that is being tracked 61 | success, boxes = trackers.update(frame) 62 | 63 | # loop over the bounding boxes and draw then on the frame 64 | if success: 65 | for bbox in boxes: 66 | # Tracking success 67 | p1 = (int(bbox[0]), int(bbox[1])) 68 | p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) 69 | cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1) 70 | else: 71 | # Tracking failure 72 | cv2.putText(frame, "Tracking failure detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) 73 | 74 | # show the output frame 75 | cv2.imshow("Frame", frame) 76 | key = cv2.waitKey(1) & 0xFF 77 | 78 | # if the 's' key is selected, we are going to "select" a bounding 79 | # box to track 80 | if key == ord("s"): 81 | # select the bounding box of the object we want to track (make 82 | # sure you press ENTER or SPACE after selecting the ROI) 83 | box = cv2.selectROI("Frame", frame, fromCenter=False, 84 | showCrosshair=True) 85 | 86 | # create a new object tracker for the bounding box and add it 87 | # to our multi-object tracker 88 | tracker = tracker_class() 89 | trackers.add(tracker, frame, box) 90 | 91 | # if the `q` key was pressed, break from the loop 92 | elif key == ord("q"): 93 | break 94 | 95 | # if we are using a webcam, release the pointer 96 | video.release() 97 | 98 | # close all windows 99 | cv2.destroyAllWindows() 100 | -------------------------------------------------------------------------------- /single_object_tracker.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import sys 3 | 4 | (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.') 5 | 6 | if __name__ == '__main__' : 7 | 8 | # Set up tracker. 9 | # Instead of MIL, you can also use 10 | 11 | tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT'] 12 | tracker_type = tracker_types[2] 13 | 14 | if int(minor_ver) < 3: 15 | tracker = cv2.Tracker_create(tracker_type) 16 | else: 17 | if tracker_type == 'BOOSTING': 18 | tracker = cv2.TrackerBoosting_create() 19 | elif tracker_type == 'MIL': 20 | tracker = cv2.TrackerMIL_create() 21 | elif tracker_type == 'KCF': 22 | tracker = cv2.TrackerKCF_create() 23 | elif tracker_type == 'TLD': 24 | tracker = cv2.TrackerTLD_create() 25 | elif tracker_type == 'MEDIANFLOW': 26 | tracker = cv2.TrackerMedianFlow_create() 27 | # elif tracker_type == 'GOTURN': 28 | # tracker = cv2.TrackerGOTURN_create() 29 | elif tracker_type == 'MOSSE': 30 | tracker = cv2.TrackerMOSSE_create() 31 | elif tracker_type == "CSRT": 32 | tracker = cv2.TrackerCSRT_create() 33 | 34 | # Read video 35 | # video = cv2.VideoCapture("videos/video.mp4") 36 | video = cv2.VideoCapture(0) # for using CAM 37 | 38 | # Exit if video not opened. 39 | if not video.isOpened(): 40 | print("Could not open video") 41 | sys.exit() 42 | 43 | # Read first frame. 44 | ok, frame = video.read() 45 | if not ok: 46 | print ('Cannot read video file') 47 | sys.exit() 48 | 49 | # Define an initial bounding box 50 | bbox = (287, 23, 86, 320) 51 | 52 | # Uncomment the line below to select a different bounding box 53 | bbox = cv2.selectROI(frame, False) 54 | 55 | # Initialize tracker with first frame and bounding box 56 | ok = tracker.init(frame, bbox) 57 | 58 | while True: 59 | # Read a new frame 60 | ok, frame = video.read() 61 | if not ok: 62 | break 63 | 64 | # Start timer 65 | timer = cv2.getTickCount() 66 | 67 | # Update tracker 68 | ok, bbox = tracker.update(frame) 69 | 70 | # Calculate Frames per second (FPS) 71 | fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer); 72 | 73 | # Draw bounding box 74 | if ok: 75 | # Tracking success 76 | p1 = (int(bbox[0]), int(bbox[1])) 77 | p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) 78 | cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1) 79 | else : 80 | # Tracking failure 81 | cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2) 82 | 83 | # Display tracker type on frame 84 | cv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2); 85 | 86 | # Display FPS on frame 87 | cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2); 88 | 89 | # Display result 90 | cv2.imshow("Tracking", frame) 91 | 92 | # Exit if ESC pressed 93 | if cv2.waitKey(1) & 0xFF == ord('q'): # if press SPACE bar 94 | break 95 | video.release() 96 | cv2.destroyAllWindows() --------------------------------------------------------------------------------