loading...

Building an object tracker(I): Building/testing a tracker

mandrewcito profile image Andrés Baamonde Lozano Updated on ・3 min read

This post series will show a little 'how to'. For building an object tracker with opencv.

Setup environment

The setup it's quite simple, only create a virtual environment and install opencv.

python3 -m venv venv
source venv/bin/activate
pip install opencv-contrib-python
pip install opencv-python
Enter fullscreen mode Exit fullscreen mode

Our 'Detected' object

I have created a base object for any kind of detection, with common attributes. Positions, detection rectangles and a unique identifier.

class BaseObject(object):
    identifier = None
    position = None
    positions = []
    rectangle = None
    modified = None
    detections = []
Enter fullscreen mode Exit fullscreen mode

The tracker

The tracker has a 'track' method that manages new detections, associating it with a previous detection if it's necessary.

That association will be delegated to the detected objects 'equals ' magic method(implemented on the following post)


class ObjectTracker(object):
    def __init__(self):
        self.objects = []
        self._current_id = 1

    def track(self, obj):
        match = self.get(obj)
        if match is None:
            return self.insert(obj)
        else:
            return self.update(obj)

    def get(self, obj):
        matches = list(
            filter(
                lambda x: x == obj,
                self.objects))
        return matches[0] if len(matches) > 0 else None

    def insert(self, obj):
        obj.identifier = self._current_id
        obj.modified = datetime.now()
        obj.detections.append(obj.modified)
        obj.positions = [obj.position]
        self.objects.append(obj)
        self._current_id += 1
        return obj

    def update(self, obj):
        entity = self.get(obj)
        self.objects = list(
            filter(
                lambda x: x.identifier != entity.identifier,
                self.objects))
        entity.position = obj.position
        entity.positions.append(obj.position)
        entity.modified = datetime.now()
        entity.detections.append(entity.modified)
        self.objects.append(entity)
        return entity

Enter fullscreen mode Exit fullscreen mode

Testing it!

Previously to the test we create a object which we initialize with attributes associated to our detection (car attributes, person attributes, some keypoints detected with SIFT/SURF ...) any value that you consider relevant or a unique feature of your objects.

My custom object

class MycustomObjectClass(BaseObject):
    my_unique_field = None

    def __repr__(self):
        return "{0} {1}".format(self.identifier, self.my_unique_field)

    def __eq__(self, other):
        return self.my_unique_field == other.my_unique_field

Enter fullscreen mode Exit fullscreen mode

Tests

Now we test our tracker class, insert and update methods will the ones that need to be tested.


class ObjectTrackerTest(unittest.TestCase):
    def setUp(self):
        self.tracker = ObjectTracker()

    def tearDown(self):
        pass

    @classmethod
    def setUpClass(cls):
        pass

    @classmethod
    def tearDownClass(cls):
        pass

    def test_insert(self):
        obj = MycustomObjectClass()
        obj.my_unique_field = "secret"
        obj.position = 1
        self.tracker.track(obj)
        self.assertEquals(len(self.tracker.objects), 1)

    def test_update(self):
        obj = MycustomObjectClass()
        obj.my_unique_field = "secret"
        obj.position = 1

        obj2 = MycustomObjectClass()
        obj2.my_unique_field = "asdf"
        obj2.position = 2

        obj3 = MycustomObjectClass()
        obj3.my_unique_field = "secret"
        obj3.position = 3

        self.tracker.track(obj)
        self.tracker.track(obj2)
        self.assertEquals(len(self.tracker.objects), 2)
        self.tracker.track(obj3)
        self.assertEquals(len(self.tracker.objects), 2)

Enter fullscreen mode Exit fullscreen mode

The features

In the opencv tutorials, there are good examples of feature extration (also feature matching) that can be used for your toy feature extractor.

Delimiting our ROI

But if you are playing with a video. You will prefer delimiting rois(region of interest) because proccesing all image will be expensive, one technique you can apply is background substraction; in this example, you can see a result of a bg substract to give you an idea of the output of the function.

import cv2

video_path = "video/video.avi"

cap = cv2.VideoCapture(video_path)

fgbg = cv2.createBackgroundSubtractorMOG2()

while(1):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    cv2.imshow('frame-mask', fgmask)
    cv2.imshow('frame', frame)

    k = cv2.waitKey(30) & 0xff
    if k == 27:
        break

cap.release()
cv2.destroyAllWindows()

Enter fullscreen mode Exit fullscreen mode

background subtract

The result of that function is simple, will be a mask of the movement based on the previous state of the screen. Changes on the input frame will be 'marked' . So, you can use the result of that function for masking your current frame.

On the next episode ...

We will detect the object and extract a few of features from it. With the object already detected we put it into the tracker and track it along the video.

Discussion

pic
Editor guide