How reduce false detection in my code and how to improve tracking accuracy with opencv in c++?

Viewed 99

**Requirements: ** (1) Build OpenCV with Cuda and compile in C++ (2) Version = OpenCV Latest Version (3) Build and Compile OpenCV Link: https://techawarey.com/programming/install-opencv-c-c-in-ubuntu-18-04-lts-step-by-step-guide/#Summary (4) Library samples_utility is here: https://github.com/opencv/opencv_contrib/blob/master/modules/tracking/samples/samples_utility.hpp (4) Compile Program Command: g++ test.cpp -o testoutput -std=c++11 'pkg-config --cflags --libs opencv' (5) Run Program Command: ./testoutput

Code is working fine but not accurate Step: 1

  1. Read Frame from Camera
  2. Select ROI(Region of Interest)
  3. After that start KCF tracker with Sobal Features Extractor
  4. Tracking the selected object.

Step: 2

  1. Failure detect
  2. After that call template matching function called MatchingMethod()
  3. Run template matching
  4. Get x, y value from template matching
  5. After that reinitialize KCF tracker with Sobal Features Extractor.

This code is fine for still object when the object is moving the tracker false detection. I want to improve accuracy and reduce false detection.

#include <opencv2/core/utility.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/ocl.hpp>
#include <iostream>
#include <cstring>
#include <unistd.h>
#include "sample_utility.hpp"
#include <thread>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/cudaarithm.hpp>
#include <iomanip>
#include <stdlib.h>
#include <unistd.h>
//////////////////////////////
    
using namespace cv;
using namespace std;
    
////////////////////////////
// Convert to string
#define SSTR( x ) static_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()
/// Global Variables
struct Array {
    int arr[2];
    };
Mat img;
Mat templ;
Mat result_h;

bool flag = true;    
int match_method = 5;
int i=0;
int max_Trackbar = 5;
float fps;
int seconds = 0;
// Function Headers
void delay();
// prototype of the functino for feature extractor
void sobelExtractor(const Mat img, const Rect roi, Mat& feat);
struct Array MatchingMethod( int, void* );
int main(int argc, char **argv)
    {
    TrackerKCF::Params param;
    param.compress_feature = true;
    param.compressed_size = 2;
    param.desc_npca = 0;
    param.desc_pca = TrackerKCF::GRAY | TrackerKCF::CN;
    param.detect_thresh = 0.8;
    // create a tracker object
    Ptr<TrackerKCF> tracker = TrackerKCF::create(param);
    tracker->setFeatureExtractor(sobelExtractor);
    VideoCapture cap(0);
    // Exit if video is not opened
    if(!cap.isOpened())
        {
        //cout << "Could not read video file" << endl;
        return 1;
        }
    
    // Read first frame
    Mat frame;
    bool ok = cap.read(frame);
    // Define initial bounding box
    //Rect bbox(x, y, w, h);
    // Uncomment the line below to select a different bounding box
    Rect bbox = selectROI(frame, false);
    // Display bounding box.
    rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
    ///////////////////////////
    int H, W, cW, cH;
    // print(f"hight {H} , Width {W}")
    H = display_height;
    W = display_width;
    // Center point of the screen
    cW = int(W / 2);
    cH = int(H / 2);
    Point p1(cW, cH);
    // get bounding box
    Mat imCrop = frame(bbox);
    imwrite("1.png", imCrop);
    //quit if ROI was not selected
    if(bbox.width==0 || bbox.height==0)
        return 0;
    //////////////////////////
    //imshow("Tracking", frame);
    tracker->init(frame, bbox);
    while(true)
        {
        Mat frame;
        cap >> frame;
        circle(frame, p1, 3, Scalar(0,255,0), -1);
        // Start timer
        if(bbox.width!=0 || bbox.height!=0){
            double timer = (double)getTickCount();
            // Update the tracking result
            /////////////////////////////////////
            bool ok = tracker->update(frame, bbox);
            //////////////////////////////////////
            //ok, bbox = tracker->update(frame);
            // Calculate Frames per second (FPS)
            fps = getTickFrequency() / ((double)getTickCount() - timer);
            if (ok)
                {
                // Tracking success : Draw the tracked object
                rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
                ///////////////////////////////////////////////////
                int xxx, yyy, height, width;
                xxx = bbox.x;
                yyy = bbox.y;
                height = bbox.height;
                width = bbox.width;
                int diffX, diffY;
                float cxROI, cyROI;
                cxROI = int((xxx + (xxx + width)) / 2);
                cyROI = int((yyy + (yyy + height)) / 2);
                diffX = cxROI - cW;
                diffY = cH - cyROI;
                //cout<<diffX<<"\n";
                //cout<<diffY<<"\n";
                Point p(cxROI, cyROI);
                circle(frame, p, 3, Scalar(128,0,0), -1);
                putText(frame, "FPS : " + SSTR(int(fps)), Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);
                putText(frame, "Difference From X-Axis: "+SSTR(int(diffX)), Point(100, 50), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(100, 200, 200), 2);
                putText(frame, "Difference From Y-Axis: "+SSTR(int(diffY)), Point(100, 80), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(100, 200, 200), 2);
                }
                else
                {
                // Tracking failure detected.
                putText(frame, "Tracking failure detected", Point(100,110), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
                templ = imread( "1.png", 1 );
                img=frame.clone();
                struct Array a = MatchingMethod( 0, 0 );
                cout<<"X: "<<a.arr[0]<<"\n";
                cout<<"Y: "<<a.arr[1]<<"\n";
                cout<<"Width: "<<w<<"\n";
                cout<<"Height: "<<h<<"\n";
                int xx, yy, ww, hh;
                xx = a.arr[0];
                yy = a.arr[1];
                ww = w;
                hh = h;
                Rect bbox(xx, yy, ww, hh);
                tracker.release();
                tracker = TrackerKCF::create(param);
                tracker->setFeatureExtractor(sobelExtractor);
                tracker->init(frame, bbox);
                //roi.x = MatchingMethod.
                //waitKey(30);
                rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
                ////////////////////////////////////////////////////////////////////////
                int diffX, diffY;
                float cxROI, cyROI;
                cxROI = int((xx + (xx + ww)) / 2);
                cyROI = int((yy + (yy + hh)) / 2);
                diffX = cxROI - cW;
                diffY = cH - cyROI;
                //cout<<diffX<<"\n";
                //cout<<diffY<<"\n";
                Point p(cxROI, cyROI);
                circle(frame, p, 3, Scalar(128,0,0), -1);
                ///////////////////////////////////////////////////////////////////////////
                }
        }
        else{
    
        }
                
                // Display frame.
                imshow("Tracking", frame);
                // Exit if ESC pressed.
                int k = waitKey(1);
                if(k == 27)
                   {
                    break;
                    }
        }
return 0;
}
///////////////////////
void sobelExtractor(const Mat img, const Rect roi, Mat& feat){
    Mat sobel[2];
    Mat patch;
    Rect region=roi;
    // extract patch inside the image
    if(roi.x<0){region.x=0;region.width+=roi.x;}
    if(roi.y<0){region.y=0;region.height+=roi.y;}
    if(roi.x+roi.width>img.cols)region.width=img.cols-roi.x;
    if(roi.y+roi.height>img.rows)region.height=img.rows-roi.y;
    if(region.width>img.cols)region.width=img.cols;
    if(region.height>img.rows)region.height=img.rows;
    patch=img(region).clone();
    cvtColor(patch,patch, COLOR_BGR2GRAY);
    // add some padding to compensate when the patch is outside image border
    int addTop,addBottom, addLeft, addRight;
    addTop=region.y-roi.y;
    addBottom=(roi.height+roi.y>img.rows?roi.height+roi.y-img.rows:0);
    addLeft=region.x-roi.x;
    addRight=(roi.width+roi.x>img.cols?roi.width+roi.x-img.cols:0);
             
    copyMakeBorder(patch,patch,addTop,addBottom,addLeft,addRight,BORDER_REPLICATE);
    
    Sobel(patch, sobel[0], CV_32F,1,0,1);
    Sobel(patch, sobel[1], CV_32F,0,1,1);
    
    merge(sobel,2,feat);
    
    feat=feat/255.0-0.5; // normalize to range -0.5 .. 0.5
}
////////////////////////////////////////////////////
struct Array MatchingMethod( int, void* )
    {
    /// Source image to display
    Mat frame;
    struct Array a;
    /////////
    for(int i=1; i<=4; i++){
    img.copyTo( frame );
    //  break;
    //}
    //////////////////////////
    cv::cuda::setDevice(0); // initialize CUDA  
    // convert from mat to gpumat
    cv::cuda::GpuMat image_d(img);
    cv::cuda::GpuMat templ_d(templ);
    cv::cuda::GpuMat result;
    // GPU -> NG
    cv::Ptr<cv::cuda::TemplateMatching> alg = 
    cv::cuda::createTemplateMatching(image_d.type(), cv::TM_CCOEFF_NORMED);
    alg->match(image_d, templ_d, result);  // no return.
    
    //cv::cuda::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1);
    double max_value, min_value;
    cv::Point location;
    cv::cuda::minMaxLoc(result, &min_value, &max_value, 0, &location);
    /////////////////////////
    double THRESHOLD = 3e-09;  //0.3;
    
    if( min_value <= THRESHOLD) {
        //struct Array a;
        a.arr[0] = location.x;
        a.arr[1] = location.y;
        cout<<"Hi"<<endl;
    }   
 }
    if(flag==true){
    return a;
    flag = false;
        }
       
      //}
    }
1 Answers

Okey here is my answer to your question.

First of all, you are making a mistake by applying template matching when the tracker misses. Because template matching matches the feature if and only if it is totally same with the reference feature. So in your case, there will be shadows, light issues etc. in the environment, and you will never be able to get success results.

Secondly, if you delete the template matching scope, tracker will continue to search the target in the image effectively. Which changements I did in your code is listed below. With these changes, I got better results:

  1. Delete the template matching scope
  2. Decrease the detection threshold(param.detect_thresh) to 0.5
  3. Create more tracker objects to catch the target: This change is the most important part. What I am suggesting is that create more and more tracker objects(in my case I did 4 tracker objects, but you can increase the number). Each tracker should get as input rectangle similar to ROI user chose but not the same coordinates. For example, if user chooses cv::Rect(200,200,400,400) then other tracker should get target as cv::Rect(180,190,400,400) , cv::Rect(220,180,400,400) ... and so on. Why you should do it because, tracker algorithm is feature based, so it will always try to get a similar features to the reference. By doing this, you will increase the feature references.

And here is my code to guide you:

#include <opencv2/core/utility.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/ocl.hpp>
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <thread>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/cudaarithm.hpp>
#include <iomanip>
#include <stdlib.h>
#include <unistd.h>
//////////////////////////////

using namespace cv;
using namespace std;

////////////////////////////
// Convert to string
#define SSTR( x ) static_cast< std::ostringstream & >( \
( std::ostringstream() << std::dec << x ) ).str()
/// Global Variables
struct Array {
    int arr[2];
    };
Mat img;
Mat templ;
Mat result_h;

bool flag = true;
int match_method = 5;
int i=0;
int max_Trackbar = 5;
float fps;
int seconds = 0;
// Function Headers
void delay();
// prototype of the functino for feature extractor
void sobelExtractor(const Mat img, const Rect roi, Mat& feat);
struct Array MatchingMethod( int, void* );
int main(int argc, char **argv)
    {
    TrackerKCF::Params param;
    param.compress_feature = true;
    param.compressed_size = 2;
    param.desc_npca = 0;
    param.desc_pca = TrackerKCF::GRAY | TrackerKCF::CN;
    param.detect_thresh = 0.5;
    // create a tracker object
    Ptr<TrackerKCF> tracker = TrackerKCF::create(param);
    tracker->setFeatureExtractor(sobelExtractor);
    Ptr<TrackerKCF> tracker2 = TrackerKCF::create(param);
    tracker2->setFeatureExtractor(sobelExtractor);
    Ptr<TrackerKCF> tracker3 = TrackerKCF::create(param);
    tracker3->setFeatureExtractor(sobelExtractor);
    Ptr<TrackerKCF> tracker4 = TrackerKCF::create(param);
    tracker4->setFeatureExtractor(sobelExtractor);
    VideoCapture cap(0);
    // Exit if video is not opened
    if(!cap.isOpened())
        {
        //cout << "Could not read video file" << endl;
        return 1;
        }

    cv::imshow("Tracking",0);

    // Read first frame
    Mat frame;
    bool ok = cap.read(frame);
    // Define initial bounding box
    //Rect bbox(x, y, w, h);
    // Uncomment the line below to select a different bounding box
    Rect2d bbox = selectROI(frame, false);
    // Display bounding box.
    rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
    ///////////////////////////
    int H, W, cW, cH;
    // print(f"hight {H} , Width {W}")
    H = frame.rows;
    W = frame.cols;
    // Center point of the screen
    cW = int(W / 2);
    cH = int(H / 2);
    Point p1(cW, cH);

    //quit if ROI was not selected
    if(bbox.width==0 || bbox.height==0)
        return 0;
    //////////////////////////
    //imshow("Tracking", frame);
    tracker->init(frame, bbox);
    tracker2->init(frame, cv::Rect2d(bbox.x-10,bbox.y-10, bbox.width,bbox.height));
    tracker3->init(frame, cv::Rect2d(bbox.x+10,bbox.y+10, bbox.width,bbox.height));
    tracker4->init(frame, cv::Rect2d(bbox.x+20,bbox.y+20, bbox.width,bbox.height));

    while(true)
        {
        Mat frame;
        cap >> frame;
        circle(frame, p1, 3, Scalar(0,255,0), -1);
        // Start timer
        if(bbox.width!=0 || bbox.height!=0){
            double timer = (double)getTickCount();
            // Update the tracking result
            /////////////////////////////////////
            bool ok = tracker->update(frame, bbox);
            bool ok2 = tracker->update(frame, bbox);
            bool ok3 = tracker->update(frame, bbox);
            bool ok4 = tracker->update(frame, bbox);

            //////////////////////////////////////
            //ok, bbox = tracker->update(frame);
            // Calculate Frames per second (FPS)
            fps = getTickFrequency() / ((double)getTickCount() - timer);
            if (ok || ok2 || ok3 || ok4)
                {
                // Tracking success : Draw the tracked object
                rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
                ///////////////////////////////////////////////////
                int xxx, yyy, height, width;
                xxx = bbox.x;
                yyy = bbox.y;
                height = bbox.height;
                width = bbox.width;
                int diffX, diffY;
                float cxROI, cyROI;
                cxROI = int((xxx + (xxx + width)) / 2);
                cyROI = int((yyy + (yyy + height)) / 2);
                diffX = cxROI - cW;
                diffY = cH - cyROI;
                //cout<<diffX<<"\n";
                //cout<<diffY<<"\n";
                Point p(cxROI, cyROI);
                circle(frame, p, 3, Scalar(128,0,0), -1);
                putText(frame, "FPS : " + SSTR(int(fps)), Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);
                putText(frame, "Difference From X-Axis: "+SSTR(int(diffX)), Point(100, 50), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(100, 200, 200), 2);
                putText(frame, "Difference From Y-Axis: "+SSTR(int(diffY)), Point(100, 80), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(100, 200, 200), 2);
                }
        }
        else{

        }

                // Display frame.
                imshow("Tracking", frame);
                // Exit if ESC pressed.
                int k = waitKey(1);
                if(k == 27)
                   {
                    break;
                    }
        }
return 0;
}
///////////////////////
void sobelExtractor(const Mat img, const Rect roi, Mat& feat){
    Mat sobel[2];
    Mat patch;
    Rect region=roi;
    // extract patch inside the image
    if(roi.x<0){region.x=0;region.width+=roi.x;}
    if(roi.y<0){region.y=0;region.height+=roi.y;}
    if(roi.x+roi.width>img.cols)region.width=img.cols-roi.x;
    if(roi.y+roi.height>img.rows)region.height=img.rows-roi.y;
    if(region.width>img.cols)region.width=img.cols;
    if(region.height>img.rows)region.height=img.rows;
    patch=img(region).clone();
    cvtColor(patch,patch, COLOR_BGR2GRAY);
    // add some padding to compensate when the patch is outside image border
    int addTop,addBottom, addLeft, addRight;
    addTop=region.y-roi.y;
    addBottom=(roi.height+roi.y>img.rows?roi.height+roi.y-img.rows:0);
    addLeft=region.x-roi.x;
    addRight=(roi.width+roi.x>img.cols?roi.width+roi.x-img.cols:0);

    copyMakeBorder(patch,patch,addTop,addBottom,addLeft,addRight,BORDER_REPLICATE);

    Sobel(patch, sobel[0], CV_32F,1,0,1);
    Sobel(patch, sobel[1], CV_32F,0,1,1);

    merge(sobel,2,feat);

    feat=feat/255.0-0.5; // normalize to range -0.5 .. 0.5
}
////////////////////////////////////////////////////
struct Array MatchingMethod( int, void* )
    {
    /// Source image to display
    Mat frame;
    struct Array a;
    /////////
    for(int i=1; i<=4; i++){
    img.copyTo( frame );
    //  break;
    //}
    //////////////////////////
    cv::cuda::setDevice(0); // initialize CUDA
    // convert from mat to gpumat
    cv::cuda::GpuMat image_d(img);
    cv::cuda::GpuMat templ_d(templ);
    cv::cuda::GpuMat result;
    // GPU -> NG
    cv::Ptr<cv::cuda::TemplateMatching> alg =
    cv::cuda::createTemplateMatching(image_d.type(), cv::TM_CCOEFF_NORMED);
    alg->match(image_d, templ_d, result);  // no return.

    //cv::cuda::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1);
    double max_value, min_value;
    cv::Point location;
    cv::cuda::minMaxLoc(result, &min_value, &max_value, 0, &location);
    /////////////////////////
    double THRESHOLD = 3e-09;  //0.3;

    if( min_value <= THRESHOLD) {
        //struct Array a;
        a.arr[0] = location.x;
        a.arr[1] = location.y;
        cout<<"Hi"<<endl;
    }
 }
    if(flag==true){
    return a;
    flag = false;
        }

      //}
    }
Related