Object tracker
An object tracker will follow the detected objects during the intermediate frames between model executions and match existing objects to new detections. This reduces the possibility of duplication of recognitions for the same object in different frames, and can provide a smoother experience by updating an object's location more frequently than a model can execute.
To use an object tracker, call its onFrame()
method on each new frame and trackResults()
method on each model recognition result. The parameters for each method vary based on the tracker used, but the function of each remains the same. Detections from the tracker can be received by calling the getTrackedObjects()
method.
onFrame()
method processes each new frame and updates the location of any currently tracked objects. trackResults()
method adds new objects to the tracker and finds a correlation between the new object and existing tracked objects to determine if they are the same objects.
Based on the tracked feature type, there are two kinds of trackers:
-
BasicObjectTracker
- Best suited when tracking the features' presence / existence is of greater importance than their instantaneous changes in position. Recommended for small and static objects (ex. traffic signs, cones).
-
MultiBoxObjectTracker
- Best suited when features' instantaneous position is of greater importance as that is required for alerting a user of a potential collision. Recommended for constantly moving objects (ex. cars, rider, bicycle, motorcycle).
using namespace cv;
using namespace ls;
std::atomic<bool> isDetectionRunning(false);
MultiBoxObjectTracker objectTracker
BasicObjectTracker basicTracker
long timestamp = 1;
std::set<std::string> multiBoxTrackerClasses{
"rider",
"car",
"bus",
"truck",
"bicycle",
"motorcycle",
"car-brake-light-on",
};
std::vector<LivesenseModel *> livesenseModels;
void processFrameWithTracker(Mat frame) {
Mat frameLuminance;
cvtColor(frame, frameLuminance, cv::COLOR_BGR2YUV);
Mat yuv[3];
split(frameLuminance, yuv);
objectTracker.onFrame(
frame_width,
frame_height,
frame_width,
0,
yuv[0].data,
timestamp);
basicTracker.onFrame(timestamp);
if (isDetectionRunning == false) {
isDetectionRunning = true;
Mat frameRGB;
cvtColor(frame, frameRGB, COLOR_BGR2RGB);
std::thread th(runDetectionInBackground, livesenseModels, &objectTracker,
&basicTracker, frameRGB, yuv[0].data, timestamp);
th.detach();
}
auto trackedObjects = objectTracker.getTrackedObjects();
auto basicTrackedObject = basicTracker.getTrackedObjects()
timestamp = timestamp + 1
}
The model inference is executed in the background with the model results processed by the trackers as shown below.
void runDetectionInBackground(const vector<ls::LivesenseModel *> models,
ls::MultiBoxObjectTracker *objectTracker,
ls::BasicObjectTracker *basicTracker,
const cv::Mat frame,
const uint8_t frameLuminance[],
const long timestamp) {
using namespace ls;
isDetectionRunning = true;
unsigned char *resizedInput = NULL;
unsigned char *origInput = &frame.data[0];
int origWidth = frame.cols;
int origHeight = frame.rows;
cv::Mat resizedFrame;
std::vector<Recognition> trackMultiBox;
std::vector<Recognition> trackBasic;
for (auto livesenseModel : models) {
int resizedInputWidth = livesenseModel->getInputWidth();
int resizedInputHeight = livesenseModel->getInputHeight();
cv::resize(frame, resizedFrame, cv::Size(resizedInputWidth, resizedInputHeight));
resizedInput = &resizedFrame.data[0];
auto recognitions = livesenseModel->recognizeImage(resizedInput,
resizedInputWidth,
resizedInputHeight,
origWidth,
origHeight,
origInput);
for (auto r : recognitions) {
if (multiBoxTrackerClasses.find(r.getTitle()) != multiBoxTrackerClasses.end()) {
trackMultiBox.push_back(r);
} else {
trackBasic.push_back(r);
}
}
}
objectTracker->trackResults(trackMultiBox, frameLuminance, timestamp);
basicTracker->trackResults(trackBasic, timestamp);
isDetectionRunning = false;
}