changeset 507:081a9da6f85b

first version with undistort implemented in the feature tracking process
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 01 May 2014 17:41:10 -0400
parents 13d4eb96a751 (current diff) b96ff16b1c81 (diff)
children 6f7fa0093162
files c/Parameters.cpp c/feature-based-tracking.cpp include/Parameters.hpp tracking.cfg
diffstat 4 files changed, 80 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/c/Parameters.cpp	Mon Apr 28 18:18:14 2014 -0400
+++ b/c/Parameters.cpp	Thu May 01 17:41:10 2014 -0400
@@ -33,33 +33,35 @@
     ("distortion-coefficients", po::value<std::vector<float> >(&distortionCoefficients)->multitoken(), "")
     ("undistorted-size-multiplication", po::value<float>(&undistortedImageMultiplication), "undistorted image multiplication")
     ("mask-filename", po::value<string>(&maskFilename), "filename of the mask image (where features are detected)")
+    ("undistort", po::value<bool>(&undistort), "undistort the video for feature tracking")
     ("load-features", po::value<bool>(&loadFeatures), "load features from database")
     ("display", po::value<bool>(&display), "display trajectories on the video")
     ("video-fps", po::value<float>(&videoFPS), "original video frame rate")
     ("frame1", po::value<unsigned int>(&frame1), "first frame to process")
     ("nframes", po::value<int>(&nFrames), "number of frame to process")
     // feature tracking
-    ("max-nfeatures", po::value<int>(&maxNFeatures), "maximum number of features added at each frame")
-    ("feature-quality", po::value<float>(&featureQuality), "quality level of the good features to track")
-    ("min-feature-distanceklt", po::value<float>(&minFeatureDistanceKLT), "minimum distance between features")
-    ("window-size", po::value<int>(&windowSize), "size of the search window at each pyramid level")
+    ("max-nfeatures", po::value<int>(&maxNFeatures), "maximum number of features added at each frame (1000s)")
+    ("feature-quality", po::value<float>(&featureQuality), "quality level of the good features to track (]0. 1?])")
+    ("min-feature-distanceklt", po::value<float>(&minFeatureDistanceKLT), "minimum distance between features (]0. 10?])")
+    ("block-size", po::value<int>(&blockSize), "size of the block for feature characteristics ([1 ?])")
     ("use-harris-detector", po::value<bool>(&useHarrisDetector), "use of Harris corner detector")
     ("k", po::value<float>(&k), "k parameter to detect good features to track (OpenCV)")
-    ("pyramid-level", po::value<int>(&pyramidLevel), "maximal pyramid level in the feature tracking algorithm")
-    ("ndisplacements", po::value<unsigned int>(&nDisplacements), "number of displacement to test minimum feature motion")
-    ("min-feature-displacement", po::value<float>(&minFeatureDisplacement), "minimum displacement to keep features")
-    ("acceleration-bound", po::value<float>(&accelerationBound), "maximum feature acceleration")
-    ("deviation-bound", po::value<float>(&deviationBound), "maximum feature deviation")
-    ("smoothing-halfwidth", po::value<int>(&nFramesSmoothing), "number of frames to smooth positions (half window)")
-    ("max-number-iterations", po::value<int>(&maxNumberTrackingIterations), "maximum number of iterations to stop feature tracking")
-    ("min-tracking-error", po::value<float>(&minTrackingError), "minimum error to reach to stop feature tracking")
-    ("min-feature-eig-threshold", po::value<float>(&minFeatureEigThreshold)->default_value(1e-4), "minimum eigen value of a 2x2 normal matrix of optical flow equations")
-    ("min-feature-time", po::value<unsigned int>(&minFeatureTime), "minimum length of a feature (number of frames) to consider a feature for grouping")
-    ("mm-connection-distance", po::value<float>(&mmConnectionDistance), "connection distance in feature grouping")
-    ("mm-segmentation-distance", po::value<float>(&mmSegmentationDistance), "segmentation distance in feature grouping")
-    ("max-distance", po::value<float>(&maxDistance), "maximum distance between features for grouping")
-    ("min-velocity-cosine", po::value<float>(&minVelocityCosine), "minimum cosine of the angle between the velocity vectors for grouping")
-    ("min-nfeatures-group", po::value<float>(&minNFeaturesPerGroup), "minimum average number of features per frame to create a vehicle hypothesis")
+    ("window-size", po::value<int>(&windowSize), "size of the search window at each pyramid level ([1 ?])")
+    ("pyramid-level", po::value<int>(&pyramidLevel), "maximal pyramid level in the feature tracking algorithm ([0 maxLevel=5?])")
+    ("ndisplacements", po::value<unsigned int>(&nDisplacements), "number of displacements to test minimum feature motion ([2 4])")
+    ("min-feature-displacement", po::value<float>(&minFeatureDisplacement), "minimum displacement per frame (in world space) to keep features (]0. 0.1?])")
+    ("acceleration-bound", po::value<float>(&accelerationBound), "maximum feature acceleration (]1 3+])")
+    ("deviation-bound", po::value<float>(&deviationBound), "maximum feature deviation (on cosine) (]0 1])")
+    ("smoothing-halfwidth", po::value<int>(&nFramesSmoothing), "number of frames to smooth positions (half window) ([0 inf[")
+    ("max-number-iterations", po::value<int>(&maxNumberTrackingIterations), "maximum number of iterations to stop optical flow (20-30?)")
+    ("min-tracking-error", po::value<float>(&minTrackingError), "minimum error to reach to stop optical flow (0.3-0.01)")
+    ("min-feature-eig-threshold", po::value<float>(&minFeatureEigThreshold)->default_value(1e-4), "minimum eigen value of a 2x2 normal matrix of optical flow equations (10^-4)")
+    ("min-feature-time", po::value<unsigned int>(&minFeatureTime), "minimum length of a feature (number of frames) to consider a feature for grouping [5 20+]")
+    ("mm-connection-distance", po::value<float>(&mmConnectionDistance), "connection distance in feature grouping (in world space) (ped: [0.5m 2m+], cars: [1.7m 4m+])")
+    ("mm-segmentation-distance", po::value<float>(&mmSegmentationDistance), "segmentation distance in feature grouping (in world space) (< mm-connection-distance, empirically ~ mm-connection-distance / 2.5)")
+    ("max-distance", po::value<float>(&maxDistance), "maximum distance between features for grouping (in world space) (unused)")
+    ("min-velocity-cosine", po::value<float>(&minVelocityCosine), "minimum cosine of the angle between the velocity vectors for grouping (unused)")
+    ("min-nfeatures-group", po::value<float>(&minNFeaturesPerGroup), "minimum average number of features per frame to create a vehicle hypothesis (]1 3+])")
     // ("max-uturn-cosine", po::value<float>(&maxUTurnCosine), "maximum cosine value to detect U-turn")
     // ("nframes-avoid-uturn", po::value<int>(&nFramesAvoidUTurn), "number of frames over which a feature should not make a U-turn")
     // Safety Analysis
--- a/c/feature-based-tracking.cpp	Mon Apr 28 18:18:14 2014 -0400
+++ b/c/feature-based-tracking.cpp	Thu May 01 17:41:10 2014 -0400
@@ -72,6 +72,8 @@
   Mat invHomography;
   if (params.display && !homography.empty())
     invHomography = homography.inv();
+  Mat intrinsicCameraMatrix = ::loadMat(params.intrinsicCameraFilename, " ");
+  //cout << intrinsicCameraMatrix << endl;
 
   float minTotalFeatureDisplacement = params.nDisplacements*params.minFeatureDisplacement;
   Size window = Size(params.windowSize, params.windowSize);
@@ -93,16 +95,31 @@
   }
   
   Size videoSize = capture->getSize();
+  //cout << capture->getSize() << " " << params.undistortedImageMultiplication*videoSize << endl;
   unsigned int nFrames = capture->getNbFrames();
   cout << "Video " << params.videoFilename <<
 	  ": width=" << videoSize.width <<
 	  ", height=" << videoSize.height <<
 	  ", nframes=" << nFrames << endl;
+
+  Mat newIntrinsicCameraMatrix = intrinsicCameraMatrix.clone(); 
+  Size newVideoSize = videoSize;
+  if (params.undistort) {
+    newVideoSize = Size(static_cast<int>(videoSize.width*params.undistortedImageMultiplication), static_cast<int>(videoSize.height*params.undistortedImageMultiplication));
+    newIntrinsicCameraMatrix.at<float>(0,2) = newVideoSize.width/2.;
+    newIntrinsicCameraMatrix.at<float>(1,2) = newVideoSize.height/2.;
+  }
   
+  Mat map1, map2;
+  Mat R = Mat::eye(3,3, CV_32FC1);
+  if (params.undistort)
+    initUndistortRectifyMap(intrinsicCameraMatrix, params.distortionCoefficients, R, newIntrinsicCameraMatrix, newVideoSize, CV_32FC1, map1, map2);
+  
+  // todo mask in new size
   Mat mask = imread(params.maskFilename, 0);
   if (mask.empty()) {
     cout << "Mask filename " << params.maskFilename << " could not be opened." << endl;
-    mask = Mat::ones(videoSize, CV_8UC1);
+    mask = Mat::ones(newVideoSize, CV_8UC1);
   }
 
   boost::shared_ptr<TrajectoryDBAccess<Point2f> > trajectoryDB = boost::shared_ptr<TrajectoryDBAccess<Point2f> >(new TrajectoryDBAccessList<Point2f>());
@@ -121,23 +138,23 @@
   std::vector<FeatureTrajectoryPtr> lostFeatures;
   std::vector<FeaturePointMatch> featurePointMatches;
 
-  //HOGDescriptor hog;
-  //hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
-
   int key = '?';
   unsigned int savedFeatureId=0;
-  Mat frame = Mat::zeros(1, 1, CV_8UC1), currentFrameBW, previousFrameBW;
+  Mat frame = Mat::zeros(1, 1, CV_8UC1), currentFrameBW, previousFrameBW, undistortedFrame;
 
   unsigned int lastFrameNum = nFrames;
   if (params.nFrames > 0)
     lastFrameNum = MIN(params.frame1+static_cast<unsigned int>(params.nFrames), nFrames);
-  
+
   capture->setFrameNumber(params.frame1);
   for (unsigned int frameNum = params.frame1; (frameNum < lastFrameNum) && !::interruptionKey(key); frameNum++) {
       bool success = capture->getNextFrame(frame);
-
-      if (!success || frame.empty() || frame.size() != videoSize)
-	break;
+      if (params.undistort) {
+	remap(frame, undistortedFrame, map1, map2, INTER_LINEAR, BORDER_CONSTANT, 0.);
+	frame = undistortedFrame;
+      }
+      //if (!success || frame.empty() || frame.size() != videoSize)
+      //break;
 
       if (frameNum%50 ==0)
 	cout << "frame " << frameNum << endl;
@@ -146,7 +163,7 @@
       
       if (!prevPts.empty()) {
 	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), /* int flags = */ 0, params.minFeatureEigThreshold);
+	calcOpticalFlowPyrLK(previousFrameBW, currentFrameBW, prevPts, currPts, status, errors, window, params.pyramidLevel, TermCriteria(static_cast<int>(TermCriteria::COUNT)+static_cast<int>(TermCriteria::EPS) /* = 3 */, params.maxNumberTrackingIterations, params.minTrackingError), /* int flags = */ 0, params.minFeatureEigThreshold);
 	/// \todo try calcOpticalFlowFarneback
 
 	std::vector<Point2f> trackedPts;
@@ -199,7 +216,7 @@
 	for (int j=MAX(0, currPts[n].x-params.minFeatureDistanceKLT); j<MIN(videoSize.width, currPts[n].x+params.minFeatureDistanceKLT+1); j++)
 	  for (int i=MAX(0, currPts[n].y-params.minFeatureDistanceKLT); i<MIN(videoSize.height, currPts[n].y+params.minFeatureDistanceKLT+1); i++)
 	    featureMask.at<uchar>(i,j)=0;
-      goodFeaturesToTrack(currentFrameBW, newPts, params.maxNFeatures, params.featureQuality, params.minFeatureDistanceKLT, featureMask, params.windowSize, params.useHarrisDetector, params.k);
+      goodFeaturesToTrack(currentFrameBW, newPts, params.maxNFeatures, params.featureQuality, params.minFeatureDistanceKLT, featureMask, params.blockSize, params.useHarrisDetector, params.k);
       BOOST_FOREACH(Point2f p, newPts) { //for (unsigned int i=0; i<newPts.size(); i++) {
 	FeatureTrajectoryPtr f = FeatureTrajectoryPtr(new FeatureTrajectory(frameNum, p, homography));
 	featurePointMatches.push_back(FeaturePointMatch(f, currPts.size()));
--- a/include/Parameters.hpp	Mon Apr 28 18:18:14 2014 -0400
+++ b/include/Parameters.hpp	Thu May 01 17:41:10 2014 -0400
@@ -24,6 +24,7 @@
   std::vector<float> distortionCoefficients;
   float undistortedImageMultiplication;
   std::string maskFilename;
+  bool undistort;
   bool loadFeatures;
   bool display;
   float videoFPS;
@@ -31,27 +32,50 @@
   unsigned int frame1;
   int nFrames;
   // feature tracking
+  /// "Maximum number of corners to return" (OpenCV goodFeaturesToTrack) (should be large enough not to limit the potential number of features)
   int maxNFeatures;
+  /// "Parameter characterizing the minimal accepted quality of image corners" (OpenCV goodFeaturesToTrack )
   float featureQuality;
+  /// "Minimum possible Euclidean distance between the returned corners" (OpenCV goodFeaturesToTrack)
   float minFeatureDistanceKLT;
-  int windowSize;
+  /// "Size of an average block for computing a derivative covariation matrix over each pixel neighborhood" (OpenCV goodFeaturesToTrack)
+  int blockSize;
+  /// "Parameter indicating whether to use a Harris detector" (OpenCV goodFeaturesToTrack)
   bool useHarrisDetector;
+  /// "Free parameter of the Harris detector" (OpenCV goodFeaturesToTrack)
   float k;
+  /// "size of the search window at each pyramid level" (OpenCV calcOpticalFlowPyrLK)
+  int windowSize;
+  /// "0-based maximal pyramid level number" (OpenCV calcOpticalFlowPyrLK) higher is higher quality
   int pyramidLevel;
+  /// Number of displacements (number of frames-1) over which minimum motion is computed 
   unsigned int nDisplacements;
+  /// Minimum displacement per frame (in world space) to keep features
   float minFeatureDisplacement;
+  /// Maximum feature acceleration
   float accelerationBound;
+  /// Maximum feature deviation
   float deviationBound;
+  /// Number of frames to smooth positions (half window)
   int nFramesSmoothing;
   //int nFramesVelocity;
+  /// Maximum number of iterations to stop optical flow (OpenCV calcOpticalFlowPyrLK)
   int maxNumberTrackingIterations;
+  /// Minimum error to reach to stop optical flow (OpenCV calcOpticalFlowPyrLK)
   float minTrackingError;
+  /// Minimum eigen value of a 2x2 normal matrix of optical flow equations (OpenCV calcOpticalFlowPyrLK)
   float minFeatureEigThreshold;
+  /// Minimum length of a feature (number of frames) to consider a feature for grouping
   unsigned int minFeatureTime;
+  /// Connection distance in feature grouping (in world space)
   float mmConnectionDistance;
+  /// Segmentation distance in feature grouping (in world space)
   float mmSegmentationDistance;
+  /// Maximum distance between features for grouping (in world space) (unused)
   float maxDistance;
+  /// Minimum cosine of the angle between the velocity vectors for grouping (unused)
   float minVelocityCosine;
+  /// Minimum average number of features per frame to create a vehicle hypothesis
   float minNFeaturesPerGroup;
   // safety analysis
   float maxPredictedSpeed;
--- a/tracking.cfg	Mon Apr 28 18:18:14 2014 -0400
+++ b/tracking.cfg	Thu May 01 17:41:10 2014 -0400
@@ -35,12 +35,14 @@
 feature-quality = 0.1
 # minimum distance between features
 min-feature-distanceklt = 5
-# size of the search window at each pyramid level
-window-size = 7
+# size of the block for feature characteristics
+block-size = 7
 # use of Harris corner detector
 use-harris-detector = false
 # k parameter to detect good features to track (OpenCV)
 k = 0.4
+# size of the search window at each pyramid level
+window-size = 7
 # maximal pyramid level in the feature tracking algorithm
 pyramid-level = 5
 # number of displacement to test minimum feature motion
@@ -56,9 +58,9 @@
 # number of frames to compute velocities
 #nframes-velocity = 5
 # maximum number of iterations to stop feature tracking
-max-number-iterations = 20
+max-number-iterations = 30
 # minimum error to reach to stop feature tracking
-min-tracking-error = 0.3
+min-tracking-error = 0.01
 # minimum eigen value of a 2x2 normal matrix of optical flow equations
 min-feature-eig-threshold = 1e-4
 # minimum length of a feature (number of frames) to consider a feature for grouping