view c/feature-based-tracking.cpp @ 127:d19d6e63dd77

simple feature tracking and drawing working
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 17 Aug 2011 01:25:13 -0400
parents 28907fde9855
children 536510f60854
line wrap: on
line source

//#include "Feature.hpp"
#include "Parameters.hpp"
#include "cvutils.hpp"
#include "utils.hpp"

#include "src/Trajectory.h"

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
//#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"

#include <boost/shared_ptr.hpp>

#include <iostream>
//#include <list>
#include <vector>

using namespace std;
using namespace cv;
using namespace boost;

void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query, std::vector<cv::DMatch>& matches, Mat& img) {
  for (int i = 0; i < (int)matches.size(); i++)
    {
      Point2f pt_new = query[matches[i].queryIdx].pt;
      Point2f pt_old = train[matches[i].trainIdx].pt;
      Point2f dist = pt_new - pt_old;
      if (norm(dist) < 20) {
	line(img, pt_new, pt_old, Scalar(125, 255, 125), 1);
	circle(img, pt_old, 2, Scalar(255, 0, 125), 1);
      }
    }
}

void drawOpticalFlow(const vector<Point2f>& prevPts, const vector<Point2f>& currPts, const vector<uchar> status, Mat& img) {
  for (unsigned int i=0; i<status.size(); i++) {
    if (status[i]) {
 	line(img, prevPts[i], currPts[i], Scalar(125, 255, 125), 1);
	circle(img, prevPts[i], 2, Scalar(255, 0, 125), 1);     
    }
  }
}

int main(int argc, char *argv[]) {
  //vector<TrajectoryPoint2f> features;
  
  BriefDescriptorExtractor brief(32);
  const int DESIRED_FTRS = 500;
  //shared_ptr<FeatureDetector> detector = shared_ptr<FeatureDetector>(new GridAdaptedFeatureDetector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4));
  //GridAdaptedFeatureDetector detector(new FastFeatureDetector(10, true), DESIRED_FTRS, 4, 4);

  VideoCapture capture;
  Mat frame, currentFrameBW, previousFrameBW;

  KLTFeatureTrackingParameters params;
  params.frame1 = 0;
  params.nFrames = -1;
  params.maxNFeatures = 1000;
  params.featureQuality = 0.1;
  params.minFeatureDistanceKLT = 3;
  params.windowSize = 3; 
  params.useHarrisDetector = false;
  params.k = 0.4;
  GoodFeaturesToTrackDetector detector(params.maxNFeatures, params.featureQuality, params.minFeatureDistanceKLT, params.windowSize, params.useHarrisDetector, params.k);

  params.pyramidLevel = 3;
  params.maxNumberTrackingIterations = 20; // 30
  params.minTrackingError = 0.3; // 0.01
  params.derivLambda = 0.5;
  Size window = Size(params.windowSize, params.windowSize);

  BruteForceMatcher<Hamming> descMatcher;
  vector<DMatch> matches;

  if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) // if no parameter or number parameter
    capture.open(argc == 2 ? argv[1][0] - '0' : 0);
  else if( argc >= 2 )
    {
      capture.open(argv[1]);
      if( capture.isOpened() )
	cout << "Video " << argv[1] <<
	  ": width=" << capture.get(CV_CAP_PROP_FRAME_WIDTH) <<
	  ", height=" << capture.get(CV_CAP_PROP_FRAME_HEIGHT) <<
	  ", nframes=" << capture.get(CV_CAP_PROP_FRAME_COUNT) << endl;
      if( argc > 2 && isdigit(argv[2][0]) ) // could be used to reach first frame, dumping library messages to log file (2> /tmp/log.txt)
        {
	  sscanf(argv[2], "%d", &params.frame1);
      	  cout << "seeking to frame #" << params.frame1 << endl;
      	  //cap.set(CV_CAP_PROP_POS_FRAMES, pos);
	  for (int i=0; i<params.frame1; i++)
	    capture >> frame;
        }
    }

    //  capture.open(atoi(argv[1]));
  if (!capture.isOpened())
    {
      //help(argv);
      cout << "capture device " << argv[1] << " failed to open!" << endl;
      return 1;
    }
  
  vector<KeyPoint> prevKpts, currKpts;
  vector<Point2f> prevPts, currPts;
  vector<uchar> status;
  vector<float> errors;
  Mat prevDesc, currDesc;
  
  // TODO structure de donnee paires pointeur trajectory, numero de keypoint
  int key = '?'; 
  for (int frameNum = 0; ((params.frame1+frameNum < params.nFrames) || (params.nFrames < 0)) && !::interruptionKey(key); frameNum++) {
      capture >> frame;
      cout << capture.get(CV_CAP_PROP_POS_FRAMES) << endl;
      while (frame.empty())
	capture >> frame;//break;
      
      cvtColor(frame, currentFrameBW, CV_RGB2GRAY);
      
      detector.detect(currentFrameBW, currKpts);
      //cout << currKpts.size() << " kpts" << endl;
      
      brief.compute(currentFrameBW, currKpts, currDesc); //Compute brief descriptors at each keypoint location
      
      if (!prevKpts.empty()) {
	::keyPoints2Points(prevKpts, prevPts);
	currPts.clear();
	calcOpticalFlowPyrLK(previousFrameBW, currentFrameBW, prevPts, currPts, status, errors, window, params.pyramidLevel, TermCriteria(3 /*static_cast<int>(TermCriteria::COUNT)+static_cast<int>(TermCriteria::EPS)*/, params.maxNumberTrackingIterations, params.minTrackingError), params.derivLambda, 0); // OPTFLOW_USE_INITIAL_FLOW
	drawOpticalFlow(prevPts, currPts, status, frame);

	// cout << matches.size() << " matches" << endl;
	// descMatcher.match(currDesc, prevDesc, matches);
	// cout << matches.size() << " matches" << endl;
	drawMatchesRelative(prevKpts, currKpts, matches, frame);
	//drawMatches(frame, prevKpts, frame, currKpts, matches, display);//, Scalar::all(-1), Scalar::all(-1), vector<vector<char> >(), DrawMatchesFlags::DRAW_OVER_OUTIMG);
      }
      
      imshow("frame", frame);
      previousFrameBW = currentFrameBW.clone();
      prevKpts = currKpts;
      currDesc.copyTo(prevDesc);
      key = waitKey(2);
    }  
  
  return 0;
}


/* ------------------ DOCUMENTATION ------------------ */


/*! \mainpage 

This project is a collection of software tools for transportation called Traffic Intelligence. Other documents are:

- \ref feature_based_tracking

The code is partially self-described using the doxygen tool and comment formatting. The documentation can be extracted using doxygen, typing \c doxygen in the main directory (or <tt>make doc</tt> on a system with the Makefile tool installed). 

*/

/*! \page feature_based_tracking Feature-based Tracking: User Manual

This document describes a software tool for object tracking in video data, developed for road traffic monitoring and safety diagnosis. It is part of a larger collection of software tools for transportation called Traffic Intelligence. 

The tool relies on feature-based tracking, a robust object tracking methods, particularly suited for the extraction of traffic data such as trajectories and speeds. The best description of this method is given in <a href="http://nicolas.saunier.confins.net/data/saunier06crv.html">this paper</a>. The program has a command line interface and this document will shortly explain how to use the tool. Keep in mind this is a work in progress and major changes are continuously being made. 

\section License

The code is licensed under the MIT open source license (http://www.opensource.org/licenses/mit-license).

If you make use of this piece of software, please cite one of my paper, e.g. N. Saunier, T. Sayed and K. Ismail. Large Scale Automated Analysis of Vehicle Interactions and Collisions. Transportation Research Record: Journal of the Transportation Research Board, 2147:42-50, 2010. I would be very happy in any case to know about any use of the code, and to discuss any opportunity for collaboration. 

Contact me at nicolas.saunier@polymtl.ca and learn more about my work at http://nicolas.saunier.confins.net.

*/