comparison c/feature-based-tracking.cpp @ 655:39fa1c998b29

removed the abstract class to represent folders of images or video files since the capability is now built in OpenCV
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 07 May 2015 16:30:58 +0200
parents 045d05cef9d0
children 576d9ea4b41a
comparison
equal deleted inserted replaced
654:045d05cef9d0 655:39fa1c998b29
1 #include "Motion.hpp" 1 #include "Motion.hpp"
2 #include "Parameters.hpp" 2 #include "Parameters.hpp"
3 #include "cvutils.hpp" 3 #include "cvutils.hpp"
4 #include "utils.hpp" 4 #include "utils.hpp"
5 #include "InputVideoFileModule.h"
6 #include "InputFrameListModule.h"
7 5
8 #include "src/Trajectory.h" 6 #include "src/Trajectory.h"
9 #include "src/TrajectoryDBAccessList.h" 7 #include "src/TrajectoryDBAccessList.h"
10 #include "src/TrajectoryDBAccessBlob.h" 8 #include "src/TrajectoryDBAccessBlob.h"
11 9
15 #include "opencv2/features2d/features2d.hpp" 13 #include "opencv2/features2d/features2d.hpp"
16 #include "opencv2/highgui/highgui.hpp" 14 #include "opencv2/highgui/highgui.hpp"
17 #include "opencv2/objdetect/objdetect.hpp" 15 #include "opencv2/objdetect/objdetect.hpp"
18 16
19 #include <boost/foreach.hpp> 17 #include <boost/foreach.hpp>
20 #include <boost/filesystem.hpp>
21 18
22 #include <iostream> 19 #include <iostream>
23 #include <vector> 20 #include <vector>
24 #include <ctime> 21 #include <ctime>
25 #include <cmath> 22 #include <cmath>
26 #include <memory> 23 #include <memory>
27 24
28 using namespace std; 25 using namespace std;
29 using namespace cv; 26 using namespace cv;
30 namespace fs = boost::filesystem;
31 27
32 void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query, std::vector<cv::DMatch>& matches, Mat& img) { 28 void drawMatchesRelative(const vector<KeyPoint>& train, const vector<KeyPoint>& query, std::vector<cv::DMatch>& matches, Mat& img) {
33 for (int i = 0; i < (int)matches.size(); i++) 29 for (int i = 0; i < (int)matches.size(); i++)
34 { 30 {
35 Point2f pt_new = query[matches[i].queryIdx].pt; 31 Point2f pt_new = query[matches[i].queryIdx].pt;
90 cout << "Unsupported option " << interpolationMethod << " for interpolation method" << endl; 86 cout << "Unsupported option " << interpolationMethod << " for interpolation method" << endl;
91 87
92 // BruteForceMatcher<Hamming> descMatcher; 88 // BruteForceMatcher<Hamming> descMatcher;
93 // vector<DMatch> matches; 89 // vector<DMatch> matches;
94 90
95 std::shared_ptr<InputFrameProviderIface> capture; 91 if(params.videoFilename.empty()) {
96 if (fs::is_directory(fs::path(params.videoFilename))) 92 cout << "Empty video filename. Exiting." << endl;
97 capture = std::shared_ptr<InputFrameListModule>(new InputFrameListModule(params.videoFilename)); 93 exit(0);
98 else if(!params.videoFilename.empty()) 94 }
99 capture = std::shared_ptr<InputVideoFileModule>(new InputVideoFileModule(params.videoFilename)); 95
100 else 96 VideoCapture capture(params.videoFilename);
101 cout << "No valid input parameters" << endl; 97 if(!capture.isOpened()) {
102
103 if(!capture->isOpen()) {
104 cout << "Video filename " << params.videoFilename << " could not be opened. Exiting." << endl; 98 cout << "Video filename " << params.videoFilename << " could not be opened. Exiting." << endl;
105 exit(0); 99 exit(0);
106 } 100 }
107 101
108 Size videoSize = capture->getSize(); 102 Size videoSize = Size(capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT));
109 unsigned int nFrames = capture->getNbFrames(); 103 unsigned int nFrames = capture.get(CV_CAP_PROP_FRAME_COUNT);
110 cout << "Video " << params.videoFilename << 104 cout << "Video " << params.videoFilename <<
111 ": width=" << videoSize.width << 105 ": width=" << videoSize.width <<
112 ", height=" << videoSize.height << 106 ", height=" << videoSize.height <<
113 ", nframes=" << nFrames << endl; 107 ", nframes=" << nFrames << endl;
114 108
153 147
154 unsigned int lastFrameNum = nFrames; 148 unsigned int lastFrameNum = nFrames;
155 if (params.nFrames > 0) 149 if (params.nFrames > 0)
156 lastFrameNum = MIN(params.frame1+static_cast<unsigned int>(params.nFrames), nFrames); 150 lastFrameNum = MIN(params.frame1+static_cast<unsigned int>(params.nFrames), nFrames);
157 151
158 capture->setFrameNumber(params.frame1); 152 capture.set(CV_CAP_PROP_POS_FRAMES, params.frame1);
159 for (unsigned int frameNum = params.frame1; (frameNum < lastFrameNum) && !::interruptionKey(key); frameNum++) { 153 for (unsigned int frameNum = params.frame1; (frameNum < lastFrameNum) && !::interruptionKey(key); frameNum++) {
160 bool success = capture->getNextFrame(frame); 154 capture >> frame;
161 if (!success || frame.empty()) { 155 if (frame.empty()) {
162 cout << "Empty frame " << frameNum << ", breaking (" << success << " " << frame.empty() << " [" << frame.size().width << "x" << frame.size().height << "])" << endl; 156 cout << "Empty frame " << frameNum << ", breaking (" << frame.empty() << " [" << frame.size().width << "x" << frame.size().height << "])" << endl;
157 break;
158 } else if (frameNum%50 ==0)
159 cout << "frame " << frameNum << endl;
160
161 if (params.undistort) {
162 remap(frame, undistortedFrame, map1, map2, interpolationMethod, BORDER_CONSTANT, 0.);
163 frame = undistortedFrame;
164
165 if (frame.size() != videoSize) {
166 cout << "Different frame size " << frameNum << ", breaking ([" << frame.size().width << "x" << frame.size().height << "])" << endl;
163 break; 167 break;
164 } else if (frameNum%50 ==0) 168 }
165 cout << "frame " << frameNum << endl; 169 }
166 170
167 if (params.undistort) { 171
168 remap(frame, undistortedFrame, map1, map2, interpolationMethod, BORDER_CONSTANT, 0.); 172 cvtColor(frame, currentFrameBW, CV_RGB2GRAY);
169 frame = undistortedFrame; 173
170 174 if (!prevPts.empty()) {
171 if (frame.size() != videoSize) { 175 currPts.clear();
172 cout << "Different frame size " << frameNum << ", breaking ([" << frame.size().width << "x" << frame.size().height << "])" << endl; 176 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);
173 break; 177 /// \todo try calcOpticalFlowFarneback
178
179 std::vector<Point2f> trackedPts;
180 std::vector<FeaturePointMatch>::iterator iter = featurePointMatches.begin();
181 while (iter != featurePointMatches.end()) {
182 bool deleteFeature = false;
183
184 if (status[iter->pointNum]) {
185 iter->feature->addPoint(frameNum, currPts[iter->pointNum], homography);
186
187 deleteFeature = iter->feature->isDisplacementSmall(params.nDisplacements, minTotalFeatureDisplacement)
188 || !iter->feature->isMotionSmooth(params.accelerationBound, params.deviationBound);
189 if (deleteFeature)
190 iter->feature->shorten();
191 } else
192 deleteFeature = true;
193
194 if (deleteFeature) {
195 if (iter->feature->length() >= params.minFeatureTime) {
196 iter->feature->setId(savedFeatureId);
197 savedFeatureId++;
198 iter->feature->movingAverage(params.nFramesSmoothing);
199 lostFeatures.push_back(iter->feature);
200 }
201 iter = featurePointMatches.erase(iter);
202 } else {
203 trackedPts.push_back(currPts[iter->pointNum]);
204 iter->pointNum = trackedPts.size()-1;
205 iter++;
174 } 206 }
175 } 207 }
176 208 currPts = trackedPts;
209 assert(currPts.size() == featurePointMatches.size());
210 saveFeatures(lostFeatures, *trajectoryDB, "positions", "velocities");
211
212 if (params.display) {
213 BOOST_FOREACH(FeaturePointMatch fp, featurePointMatches)
214 fp.feature->draw(frame, invHomography, Colors::red());
215 // object detection
216 // vector<Rect> locations;
217 // hog.detectMultiScale(frame, locations, 0, Size(8,8), Size(32,32), 1.05, 2);
218 // BOOST_FOREACH(Rect r, locations)
219 // rectangle(frame, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
220 }
221 }
177 222
178 cvtColor(frame, currentFrameBW, CV_RGB2GRAY); 223 // adding new features, using mask around existing feature positions
224 Mat featureMask = mask.clone();
225 for (unsigned int n=0;n<currPts.size(); n++)
226 for (int j=MAX(0, currPts[n].x-params.minFeatureDistanceKLT); j<MIN(videoSize.width, currPts[n].x+params.minFeatureDistanceKLT+1); j++)
227 for (int i=MAX(0, currPts[n].y-params.minFeatureDistanceKLT); i<MIN(videoSize.height, currPts[n].y+params.minFeatureDistanceKLT+1); i++)
228 featureMask.at<uchar>(i,j)=0;
229 goodFeaturesToTrack(currentFrameBW, newPts, params.maxNFeatures, params.featureQuality, params.minFeatureDistanceKLT, featureMask, params.blockSize, params.useHarrisDetector, params.k);
230 BOOST_FOREACH(Point2f p, newPts) { //for (unsigned int i=0; i<newPts.size(); i++) {
231 FeatureTrajectoryPtr f = FeatureTrajectoryPtr(new FeatureTrajectory(frameNum, p, homography));
232 featurePointMatches.push_back(FeaturePointMatch(f, currPts.size()));
233 currPts.push_back(p);
234 }
179 235
180 if (!prevPts.empty()) { 236 if (params.display) {
181 currPts.clear(); 237 imshow("mask", featureMask*256);
182 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); 238 imshow("frame", frame);
183 /// \todo try calcOpticalFlowFarneback 239 key = waitKey(2);
184 240 }
185 std::vector<Point2f> trackedPts; 241 previousFrameBW = currentFrameBW.clone();
186 std::vector<FeaturePointMatch>::iterator iter = featurePointMatches.begin(); 242 prevPts = currPts;
187 while (iter != featurePointMatches.end()) {
188 bool deleteFeature = false;
189
190 if (status[iter->pointNum]) {
191 iter->feature->addPoint(frameNum, currPts[iter->pointNum], homography);
192
193 deleteFeature = iter->feature->isDisplacementSmall(params.nDisplacements, minTotalFeatureDisplacement)
194 || !iter->feature->isMotionSmooth(params.accelerationBound, params.deviationBound);
195 if (deleteFeature)
196 iter->feature->shorten();
197 } else
198 deleteFeature = true;
199
200 if (deleteFeature) {
201 if (iter->feature->length() >= params.minFeatureTime) {
202 iter->feature->setId(savedFeatureId);
203 savedFeatureId++;
204 iter->feature->movingAverage(params.nFramesSmoothing);
205 lostFeatures.push_back(iter->feature);
206 }
207 iter = featurePointMatches.erase(iter);
208 } else {
209 trackedPts.push_back(currPts[iter->pointNum]);
210 iter->pointNum = trackedPts.size()-1;
211 iter++;
212 }
213 }
214 currPts = trackedPts;
215 assert(currPts.size() == featurePointMatches.size());
216 saveFeatures(lostFeatures, *trajectoryDB, "positions", "velocities");
217
218 if (params.display) {
219 BOOST_FOREACH(FeaturePointMatch fp, featurePointMatches)
220 fp.feature->draw(frame, invHomography, Colors::red());
221 // object detection
222 // vector<Rect> locations;
223 // hog.detectMultiScale(frame, locations, 0, Size(8,8), Size(32,32), 1.05, 2);
224 // BOOST_FOREACH(Rect r, locations)
225 // rectangle(frame, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
226 }
227 }
228
229 // adding new features, using mask around existing feature positions
230 Mat featureMask = mask.clone();
231 for (unsigned int n=0;n<currPts.size(); n++)
232 for (int j=MAX(0, currPts[n].x-params.minFeatureDistanceKLT); j<MIN(videoSize.width, currPts[n].x+params.minFeatureDistanceKLT+1); j++)
233 for (int i=MAX(0, currPts[n].y-params.minFeatureDistanceKLT); i<MIN(videoSize.height, currPts[n].y+params.minFeatureDistanceKLT+1); i++)
234 featureMask.at<uchar>(i,j)=0;
235 goodFeaturesToTrack(currentFrameBW, newPts, params.maxNFeatures, params.featureQuality, params.minFeatureDistanceKLT, featureMask, params.blockSize, params.useHarrisDetector, params.k);
236 BOOST_FOREACH(Point2f p, newPts) { //for (unsigned int i=0; i<newPts.size(); i++) {
237 FeatureTrajectoryPtr f = FeatureTrajectoryPtr(new FeatureTrajectory(frameNum, p, homography));
238 featurePointMatches.push_back(FeaturePointMatch(f, currPts.size()));
239 currPts.push_back(p);
240 }
241
242 if (params.display) {
243 imshow("mask", featureMask*256);
244 imshow("frame", frame);
245 key = waitKey(2);
246 }
247 previousFrameBW = currentFrameBW.clone();
248 prevPts = currPts;
249 } 243 }
250 244
251 // save the remaining currently tracked features 245 // save the remaining currently tracked features
252 std::vector<FeaturePointMatch>::iterator iter = featurePointMatches.begin(); 246 std::vector<FeaturePointMatch>::iterator iter = featurePointMatches.begin();
253 while (iter != featurePointMatches.end()) { 247 while (iter != featurePointMatches.end()) {