opencvcomputer-visionvideo-tracking

Get the x and y pixel co-ordinates of the ROI that has been tracked in a tracking algorithm in OpenCV C++


I have a tracking program as given below. I draw two ROI's (rectangle boxes) in the first frame of a video and the object in these ROI's are tracked in the whole video. I want to obtain the x&y coordinates of the ROI's that will be tracked in the video (that is, position of the 2 ROI's from all frames of the video). I can see these value when debugging but when I try to print them using bboxes[0].x,bboxes[0].y,bboxes[1].x,bboxes[1].y for each frame, I am getting the same value for all the frames. What am I doing wrong here?

#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"

using namespace cv;
using namespace std;

// Convert to string
//#define SSTR( x ) static_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()

vector<string> trackerTypes = { "BOOSTING", "MIL", "KCF", "TLD", "MEDIANFLOW", "GOTURN", "MOSSE", "CSRT" };

// create tracker by name
Ptr<Tracker> createTrackerByName(string trackerType)
{
    Ptr<Tracker> tracker;
    if (trackerType == trackerTypes[0])
        tracker = TrackerBoosting::create();
    else if (trackerType == trackerTypes[1])
        tracker = TrackerMIL::create();
    else if (trackerType == trackerTypes[2])
        tracker = TrackerKCF::create();
    else if (trackerType == trackerTypes[3])
        tracker = TrackerTLD::create();
    else if (trackerType == trackerTypes[4])
        tracker = TrackerMedianFlow::create();
    else if (trackerType == trackerTypes[5])
        tracker = TrackerGOTURN::create();
    else if (trackerType == trackerTypes[6])
        tracker = TrackerMOSSE::create();
    else if (trackerType == trackerTypes[7])
        tracker = TrackerCSRT::create();
    else {
        cout << "Incorrect tracker name" << endl;
        cout << "Available trackers are: " << endl;
        for (vector<string>::iterator it = trackerTypes.begin(); it != trackerTypes.end(); ++it)
            std::cout << " " << *it << endl;
    }
    return tracker;
}

// Fill the vector with random colors
void getRandomColors(vector<Scalar> &colors, int numColors)
{
    RNG rng(0);
    for (int i = 0; i < numColors; i++)
        colors.push_back(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
}

int main(int argc, char * argv[])
{
    cout << "Available tracking algorithms are:" << endl;
    for (vector<string>::iterator it = trackerTypes.begin(); it != trackerTypes.end(); ++it)
        std::cout << " " << *it << endl;

    string trackerType = "KCF";
    cout << "The Selected tracker is " << trackerType << endl;

    string videoPath = "SS-100_zoom_Trim.mp4";

    // Initialize MultiTracker with tracking algo
    vector<Rect> bboxes;
    Mat frame;
    cv::VideoCapture cap(videoPath);
    //cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280);
    //cap.set(CV_CAP_PROP_FRAME_HEIGHT, 720);

    if (!cap.isOpened())
    {
        cout << "Error opening video file " << videoPath << endl;
        return -1;
    }
    cap >> frame;

    bool showCrosshair = true;
    bool fromCenter = false;

    cv::selectROIs("MultiTracker", frame, bboxes, showCrosshair, fromCenter);

    if (bboxes.size() < 1)
        return 0;

    vector<Scalar> colors;
    getRandomColors(colors, bboxes.size());

    // Create multitracker
    Ptr<MultiTracker> multiTracker = cv::MultiTracker::create();

    // initialize multitracker
    for (int i = 0; i < bboxes.size(); i++)
        multiTracker->add(createTrackerByName(trackerType), frame, Rect2d(bboxes[i]));

    cout << "Started tracking, press ESC to quit." << endl;

    while (cap.isOpened())
    {
        cap >> frame;
        if (frame.empty()) break;

        //update the tracking result with new frame
        multiTracker->update(frame);

        putText(frame, trackerType + " Tracker", Point(100, 20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50, 170, 50), 2);

        // draw tracked objects
        for (unsigned i = 0; i < multiTracker->getObjects().size(); i++)
        {                                                                               
            rectangle(frame, multiTracker->getObjects()[i], colors[i], 2, 1);
        }

        cout << "\nPosition of box1 in X-axis :" << bboxes[0].x << endl;
        cout << "\nPosition of box1 in Y-axis :" << bboxes[0].y << endl;   
        cout << "\nPosition of box2 in X-axis :" << bboxes[1].x << endl;
        cout << "\nPosition of box2 in Y-axis :" << bboxes[1].y << endl;

        resize(frame, frame, Size(1280, 720), 0, 0, INTER_CUBIC);
        imshow("MultiTracker", frame);
        if (waitKey(1) == 27) break; 

    }



}

The bboxes.size() is 2 , since i am drawing only 2 ROI's. I am using OpenCV 3.4.1 and Visual Studio 2015

This is the output sample i am getting Output


Solution

  • As mentioned by @Nicolas Gaborel, you are not updating the values of bboxes. There are two ways of doing this

    1. If order does not matter, then simply do bboxes[i] = multiTracker->getObjects()[i] inside your for-loop

    2. If you also want to keep track of the order, then you need to assign some sort of ID to the detected boxes. A quick way of doing so is by first computing the centroids of the rectangles and storing them. Once an object is detected, you compute the centroid of the object's rectangle. Thereafter compute the Euclidean distance of the detected object's centroid and those stored in bboxes. The rectangle with the minimum distance in bboxes is the correct one.