Mercurial Hosting > traffic-intelligence
changeset 513:dbf4b83afbb9
pulled in and merged the new functionalities to deal with camera distortion (eg GoPro cameras)
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Wed, 04 Jun 2014 10:57:09 -0400 |
parents | 35c99776e593 (current diff) 81ff62a7c39f (diff) |
children | 1ba618fb0f70 |
files | |
diffstat | 9 files changed, 269 insertions(+), 148 deletions(-) [+] |
line wrap: on
line diff
--- a/c/Parameters.cpp Wed Jun 04 10:56:12 2014 -0400 +++ b/c/Parameters.cpp Wed Jun 04 10:57:09 2014 -0400 @@ -29,7 +29,12 @@ ("video-filename", po::value<string>(&videoFilename), "filename of the video to process") ("database-filename", po::value<string>(&databaseFilename), "filename of the database where results are saved") ("homography-filename", po::value<string>(&homographyFilename), "filename of the homography matrix") + ("intrinsic-camera-filename", po::value<string>(&intrinsicCameraFilename), "filename of the homography matrix") + ("distortion-coefficients", po::value<std::vector<float> >(&distortionCoefficients)->multitoken(), "") + ("undistorted-size-multiplication", po::value<float>(&undistortedImageMultiplication), "undistorted image multiplication") + ("interpolation-method", po::value<int>(&interpolationMethod), "Interpolation method for remapping image when correcting for distortion: 0 for INTER_NEAREST - a nearest-neighbor interpolation; 1 for INTER_LINEAR - a bilinear interpolation (used by default); 2 for INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood; 3 for INTER_LANCZOS4") ("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") @@ -126,7 +131,10 @@ stream << boost::any_cast<float>(value) << separator; else if (value.type() == typeid(string)) stream << boost::any_cast<string>(value) << separator; - else + else if (value.type() == typeid(vector<float>)) { + for (unsigned int j=0; j<boost::any_cast<vector<float> >(value).size(); j++) + stream << boost::any_cast<vector<float> >(value)[j] << separator; + } else cerr << "the type of the option " << optionsVec[i]->long_name() << " (" << i << ") is not int, float or string." << endl; }
--- a/c/feature-based-tracking.cpp Wed Jun 04 10:56:12 2014 -0400 +++ b/c/feature-based-tracking.cpp Wed Jun 04 10:57:09 2014 -0400 @@ -23,6 +23,7 @@ #include <iostream> #include <vector> #include <ctime> +#include <cmath> using namespace std; using namespace cv; @@ -59,7 +60,6 @@ }; inline void saveFeatures(vector<FeatureTrajectoryPtr>& features, TrajectoryDBAccess<Point2f>& db, const string& positionsTableName, const string& velocitiesTableName) { - /// \todo smoothing BOOST_FOREACH(FeatureTrajectoryPtr f, features) f->write(db, positionsTableName, velocitiesTableName); features.clear(); } @@ -73,10 +73,24 @@ 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); + int interpolationMethod = -1; + if (params.interpolationMethod == 0) + interpolationMethod = INTER_NEAREST; + else if (params.interpolationMethod == 1) + interpolationMethod = INTER_LINEAR; + else if (params.interpolationMethod == 2) + interpolationMethod = INTER_CUBIC; + else if (params.interpolationMethod == 3) + interpolationMethod = INTER_LANCZOS4; + else + cout << "Unsupported option " << interpolationMethod << " for interpolation method" << endl; + // BruteForceMatcher<Hamming> descMatcher; // vector<DMatch> matches; @@ -99,6 +113,18 @@ ": width=" << videoSize.width << ", height=" << videoSize.height << ", nframes=" << nFrames << endl; + + Mat newIntrinsicCameraMatrix = intrinsicCameraMatrix.clone(); + Mat map1, map2; + if (params.undistort) { + videoSize = Size(static_cast<int>(round(videoSize.width*params.undistortedImageMultiplication)), static_cast<int>(round(videoSize.height*params.undistortedImageMultiplication))); + newIntrinsicCameraMatrix.at<float>(0,2) = videoSize.width/2.; + newIntrinsicCameraMatrix.at<float>(1,2) = videoSize.height/2.; + initUndistortRectifyMap(intrinsicCameraMatrix, params.distortionCoefficients, Mat::eye(3,3, CV_32FC1), newIntrinsicCameraMatrix, videoSize, CV_32FC1, map1, map2); + + cout << "Undistorted width=" << videoSize.width << + ", height=" << videoSize.height << endl; + } Mat mask = imread(params.maskFilename, 0); if (mask.empty()) { @@ -122,12 +148,9 @@ 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) @@ -136,9 +159,12 @@ 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, interpolationMethod, BORDER_CONSTANT, 0.); + frame = undistortedFrame; + } + //if (!success || frame.empty() || frame.size() != videoSize) + //break; if (frameNum%50 ==0) cout << "frame " << frameNum << endl;
--- a/include/Parameters.hpp Wed Jun 04 10:56:12 2014 -0400 +++ b/include/Parameters.hpp Wed Jun 04 10:57:09 2014 -0400 @@ -4,6 +4,7 @@ /// \todo Class for parameters, with utilities to save and load from configuration files #include <string> +#include <vector> namespace boost{ namespace program_options { @@ -19,7 +20,12 @@ std::string videoFilename; std::string databaseFilename; std::string homographyFilename; + std::string intrinsicCameraFilename; + std::vector<float> distortionCoefficients; + float undistortedImageMultiplication; + int interpolationMethod; std::string maskFilename; + bool undistort; bool loadFeatures; bool display; float videoFPS;
--- a/python/cvutils.py Wed Jun 04 10:56:12 2014 -0400 +++ b/python/cvutils.py Wed Jun 04 10:57:09 2014 -0400 @@ -110,6 +110,15 @@ else: cv2.imshow(windowName, img) + def computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients): + from copy import deepcopy + from numpy import identity, array + newImgSize = (int(round(width*undistortedImageMultiplication)), int(round(height*undistortedImageMultiplication))) + newCameraMatrix = deepcopy(intrinsicCameraMatrix) + newCameraMatrix[0,2] = newImgSize[0]/2. + newCameraMatrix[1,2] = newImgSize[1]/2. + return cv2.initUndistortRectifyMap(intrinsicCameraMatrix, array(distortionCoefficients), identity(3), newCameraMatrix, newImgSize, cv2.CV_32FC1) + def playVideo(filename, firstFrameNum = 0, frameRate = -1, interactive = False, printFrames = True, text = None, rescale = 1.): '''Plays the video''' wait = 5 @@ -202,13 +211,17 @@ return imgcrop, yCropMin, yCropMax, xCropMin, xCropMax - def displayTrajectories(videoFilename, objects, boundingBoxes = {}, homography = None, firstFrameNum = 0, lastFrameNumArg = None, printFrames = True, rescale = 1., nFramesStep = 1, saveAllImages = False): + def displayTrajectories(videoFilename, objects, boundingBoxes = {}, homography = None, firstFrameNum = 0, lastFrameNumArg = None, printFrames = True, rescale = 1., nFramesStep = 1, saveAllImages = False, undistort = False, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = 1.): '''Displays the objects overlaid frame by frame over the video ''' from moving import userTypeNames from math import ceil, log10 + capture = cv2.VideoCapture(videoFilename) width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)) height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)) + + if undistort: # setup undistortion + [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) if capture.isOpened(): key = -1 ret = True @@ -223,6 +236,8 @@ while ret and not quitKey(key) and frameNum < lastFrameNum: ret, img = capture.read() if ret: + if undistort: + img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR) if printFrames: print('frame {0}'.format(frameNum)) for obj in objects:
--- a/python/storage.py Wed Jun 04 10:56:12 2014 -0400 +++ b/python/storage.py Wed Jun 04 10:57:09 2014 -0400 @@ -9,6 +9,10 @@ __metaclass__ = type +commentChar = '#' + +delimiterChar = '%'; + ngsimUserTypes = {'twowheels':1, 'car':2, 'truck':3} @@ -352,6 +356,69 @@ # txt files ######################### +def openCheck(filename, option = 'r', quit = False): + '''Open file filename in read mode by default + and checks it is open''' + try: + return open(filename, option) + except IOError: + print 'File %s could not be opened.' % filename + if quit: + from sys import exit + exit() + return None + +def readline(f, commentChar = commentChar): + '''Modified readline function to skip comments.''' + s = f.readline() + while (len(s) > 0) and s.startswith(commentChar): + s = f.readline() + return s.strip() + +def getLines(f, commentChar = commentChar): + '''Gets a complete entry (all the lines) in between delimiterChar.''' + dataStrings = [] + s = readline(f, commentChar) + while len(s) > 0: + dataStrings += [s.strip()] + s = readline(f, commentChar) + return dataStrings + +def writeList(filename, l): + f = utils.openCheck(filename, 'w') + for x in l: + f.write('{}\n'.format(x)) + f.close() + +def loadListStrings(filename, commentChar = commentChar): + f = utils.openCheck(filename, 'r') + result = getLines(f, commentChar) + f.close() + return result + +def getValuesFromINIFile(filename, option, delimiterChar = '=', commentChar = commentChar): + values = [] + for l in loadListStrings(filename, commentChar): + if l.startswith(option): + values.append(l.split(delimiterChar)[1].strip()) + return values + +class FakeSecHead(object): + '''Add fake section header [asection] + + from http://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788 + use read_file in Python 3.2+ + ''' + def __init__(self, fp): + self.fp = fp + self.sechead = '[main]\n' + + def readline(self): + if self.sechead: + try: return self.sechead + finally: self.sechead = None + else: return self.fp.readline() + def loadTrajectoriesFromNgsimFile(filename, nObjects = -1, sequenceNum = -1): '''Reads data from the trajectory data provided by NGSIM project and returns the list of Feature objects''' @@ -454,18 +521,89 @@ writePositionsToCsv(f, obj) f.close() -def writeList(filename, l): - f = utils.openCheck(filename, 'w') - for x in l: - f.write('{}\n'.format(x)) - f.close() + +######################### +# Utils to read .ini type text files for configuration, meta data... +######################### + +class TrackingParameters: + '''Class for tracking and safety parameters + + Note: framerate is already taken into account''' + + def loadConfigFile(self, filename): + from ConfigParser import ConfigParser + from numpy import loadtxt + from os import path + + config = ConfigParser() + config.readfp(FakeSecHead(openCheck(filename))) + self.sectionHeader = config.sections()[0] + self.videoFilename = config.get(self.sectionHeader, 'video-filename') + self.databaseFilename = config.get(self.sectionHeader, 'database-filename') + self.homographyFilename = config.get(self.sectionHeader, 'homography-filename') + if (path.exists(self.homographyFilename)): + self.homography = loadtxt(self.homographyFilename) + else: + self.homography = None + self.intrinsicCameraFilename = config.get(self.sectionHeader, 'intrinsic-camera-filename') + if (path.exists(self.intrinsicCameraFilename)): + self.intrinsicCameraMatrix = loadtxt(self.intrinsicCameraFilename) + else: + self.intrinsicCameraMatrix = None + distortionCoefficients = getValuesFromINIFile(filename, 'distortion-coefficients', '=') + self.distortionCoefficients = [float(x) for x in distortionCoefficients] + self.undistortedImageMultiplication = config.getfloat(self.sectionHeader, 'undistorted-size-multiplication') + self.undistort = config.getboolean(self.sectionHeader, 'undistort') + self.firstFrameNum = config.getint(self.sectionHeader, 'frame1') + self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps') -def loadListStrings(filename): - f = utils.openCheck(filename, 'r') - result = [l.strip() for l in f] - f.close() - return result - + self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate + self.predictionTimeHorizon = config.getfloat(self.sectionHeader, 'prediction-time-horizon')*self.videoFrameRate + self.collisionDistance = config.getfloat(self.sectionHeader, 'collision-distance') + self.crossingZones = config.getboolean(self.sectionHeader, 'crossing-zones') + self.predictionMethod = config.get(self.sectionHeader, 'prediction-method') + self.nPredictedTrajectories = config.getint(self.sectionHeader, 'npredicted-trajectories') + self.maxNormalAcceleration = config.getfloat(self.sectionHeader, 'max-normal-acceleration')/self.videoFrameRate**2 + self.maxNormalSteering = config.getfloat(self.sectionHeader, 'max-normal-steering')/self.videoFrameRate + self.minExtremeAcceleration = config.getfloat(self.sectionHeader, 'min-extreme-acceleration')/self.videoFrameRate**2 + self.maxExtremeAcceleration = config.getfloat(self.sectionHeader, 'max-extreme-acceleration')/self.videoFrameRate**2 + self.maxExtremeSteering = config.getfloat(self.sectionHeader, 'max-extreme-steering')/self.videoFrameRate + self.useFeaturesForPrediction = config.getboolean(self.sectionHeader, 'use-features-prediction') + + def __init__(self, filename = None): + if filename != None: + self.loadConfigFile(filename) + +class SceneParameters: + def __init__(self, config, sectionName): + from ConfigParser import NoOptionError + from ast import literal_eval + try: + self.sitename = config.get(sectionName, 'sitename') + self.databaseFilename = config.get(sectionName, 'data-filename') + self.homographyFilename = config.get(sectionName, 'homography-filename') + self.calibrationFilename = config.get(sectionName, 'calibration-filename') + self.videoFilename = config.get(sectionName, 'video-filename') + self.frameRate = config.getfloat(sectionName, 'framerate') + self.date = datetime.strptime(config.get(sectionName, 'date'), datetimeFormat) # 2011-06-22 11:00:39 + self.translation = literal_eval(config.get(sectionName, 'translation')) # = [0.0, 0.0] + self.rotation = config.getfloat(sectionName, 'rotation') + self.duration = config.getint(sectionName, 'duration') + except NoOptionError as e: + print(e) + print('Not a section for scene meta-data') + + @staticmethod + def loadConfigFile(filename): + from ConfigParser import ConfigParser + config = ConfigParser() + config.readfp(openCheck(filename)) + configDict = dict() + for sectionName in config.sections(): + configDict[sectionName] = SceneParameters(config, sectionName) + return configDict + if __name__ == "__main__": import doctest
--- a/python/utils.py Wed Jun 04 10:56:12 2014 -0400 +++ b/python/utils.py Wed Jun 04 10:57:09 2014 -0400 @@ -7,10 +7,6 @@ __metaclass__ = type -commentChar = '#' - -delimiterChar = '%'; - datetimeFormat = "%Y-%m-%d %H:%M:%S" ######################### @@ -467,50 +463,6 @@ # file I/O section ######################### -def openCheck(filename, option = 'r', quit = False): - '''Open file filename in read mode by default - and checks it is open''' - try: - return open(filename, option) - except IOError: - print 'File %s could not be opened.' % filename - if quit: - from sys import exit - exit() - return None - -def readline(f, commentCharacter = commentChar): - '''Modified readline function to skip comments.''' - s = f.readline() - while (len(s) > 0) and s.startswith(commentCharacter): - s = f.readline() - return s.strip() - -def getLines(f, delimiterCharacter = delimiterChar): - '''Gets a complete entry (all the lines) in between delimiterChar.''' - dataStrings = [] - s = readline(f) - while (len(s) > 0) and (not s.startswith(delimiterCharacter)): - dataStrings += [s.strip()] - s = readline(f) - return dataStrings - -class FakeSecHead(object): - '''Add fake section header [asection] - - from http://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788 - use read_file in Python 3.2+ - ''' - def __init__(self, fp): - self.fp = fp - self.sechead = '[main]\n' - - def readline(self): - if self.sechead: - try: return self.sechead - finally: self.sechead = None - else: return self.fp.readline() - def removeExtension(filename, delimiter = '.'): '''Returns the filename minus the extension (all characters after last .)''' i = filename.rfind(delimiter) @@ -594,74 +546,6 @@ ######################### -# Utils to read .ini type text files for configuration, meta data... -######################### - -class TrackingParameters: - '''Class for tracking and safety parameters - - Note: framerate is already taken into account''' - def loadConfigFile(self, filename): - from ConfigParser import ConfigParser - from numpy import loadtxt - from os import path - - config = ConfigParser() - config.readfp(FakeSecHead(openCheck(filename))) - self.sectionHeader = config.sections()[0] - self.videoFilename = config.get(self.sectionHeader, 'video-filename') - self.databaseFilename = config.get(self.sectionHeader, 'database-filename') - self.homographyFilename = config.get(self.sectionHeader, 'homography-filename') - if (path.exists(self.homographyFilename)): - self.homography = loadtxt(self.homographyFilename) - else: - self.homography = None - self.firstFrameNum = config.getint(self.sectionHeader, 'frame1') - self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps') - - self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate - self.predictionTimeHorizon = config.getfloat(self.sectionHeader, 'prediction-time-horizon')*self.videoFrameRate - self.collisionDistance = config.getfloat(self.sectionHeader, 'collision-distance') - self.crossingZones = config.getboolean(self.sectionHeader, 'crossing-zones') - self.predictionMethod = config.get(self.sectionHeader, 'prediction-method') - self.nPredictedTrajectories = config.getint(self.sectionHeader, 'npredicted-trajectories') - self.maxNormalAcceleration = config.getfloat(self.sectionHeader, 'max-normal-acceleration')/self.videoFrameRate**2 - self.maxNormalSteering = config.getfloat(self.sectionHeader, 'max-normal-steering')/self.videoFrameRate - self.minExtremeAcceleration = config.getfloat(self.sectionHeader, 'min-extreme-acceleration')/self.videoFrameRate**2 - self.maxExtremeAcceleration = config.getfloat(self.sectionHeader, 'max-extreme-acceleration')/self.videoFrameRate**2 - self.maxExtremeSteering = config.getfloat(self.sectionHeader, 'max-extreme-steering')/self.videoFrameRate - self.useFeaturesForPrediction = config.getboolean(self.sectionHeader, 'use-features-prediction') - -class SceneParameters: - def __init__(self, config, sectionName): - from ConfigParser import NoOptionError - from ast import literal_eval - try: - self.sitename = config.get(sectionName, 'sitename') - self.databaseFilename = config.get(sectionName, 'data-filename') - self.homographyFilename = config.get(sectionName, 'homography-filename') - self.calibrationFilename = config.get(sectionName, 'calibration-filename') - self.videoFilename = config.get(sectionName, 'video-filename') - self.frameRate = config.getfloat(sectionName, 'framerate') - self.date = datetime.strptime(config.get(sectionName, 'date'), datetimeFormat) # 2011-06-22 11:00:39 - self.translation = literal_eval(config.get(sectionName, 'translation')) # = [0.0, 0.0] - self.rotation = config.getfloat(sectionName, 'rotation') - self.duration = config.getint(sectionName, 'duration') - except NoOptionError as e: - print(e) - print('Not a section for scene meta-data') - - @staticmethod - def loadConfigFile(filename): - from ConfigParser import ConfigParser - config = ConfigParser() - config.readfp(openCheck(filename)) - configDict = dict() - for sectionName in config.sections(): - configDict[sectionName] = SceneParameters(config, sectionName) - return configDict - -######################### # running tests #########################
--- a/scripts/compute-homography.py Wed Jun 04 10:56:12 2014 -0400 +++ b/scripts/compute-homography.py Wed Jun 04 10:57:09 2014 -0400 @@ -25,6 +25,10 @@ parser.add_argument('-n', dest = 'nPoints', help = 'number of corresponding points to input', default = 4, type = int) parser.add_argument('-u', dest = 'unitsPerPixel', help = 'number of units per pixel', default = 1., type = float) parser.add_argument('--display', dest = 'displayPoints', help = 'display original and projected points on both images', action = 'store_true') +parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file') +parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float) +parser.add_argument('--undistorted-multiplication', dest = 'undistortedImageMultiplication', help = 'undistorted image multiplication', type = float) +parser.add_argument('--undistort', dest = 'undistort', help = 'undistort the video (because features have been extracted that way)', action = 'store_true') args = parser.parse_args() @@ -76,6 +80,9 @@ elif args.videoFrameFilename != None and args.worldFilename != None: worldImg = plt.imread(args.worldFilename) videoImg = plt.imread(args.videoFrameFilename) + if args.undistort: + [map1, map2] = cvutils.computeUndistortMaps(videoImg.shape[1], videoImg.shape[0], args.undistortedImageMultiplication, np.loadtxt(args.intrinsicCameraMatrixFilename), args.distortionCoefficients) + videoImg = cv2.remap(videoImg, map1, map2, interpolation=cv2.INTER_LINEAR) print('Click on {0} points in the video frame'.format(args.nPoints)) plt.figure() plt.imshow(videoImg) @@ -98,6 +105,9 @@ if args.displayPoints and args.videoFrameFilename != None and args.worldFilename != None and homography.size>0: worldImg = cv2.imread(args.worldFilename) videoImg = cv2.imread(args.videoFrameFilename) + if args.undistort: + [map1, map2] = cvutils.computeUndistortMaps(videoImg.shape[1], videoImg.shape[0], args.undistortedImageMultiplication, np.loadtxt(args.intrinsicCameraMatrixFilename), args.distortionCoefficients) + videoImg = cv2.remap(videoImg, map1, map2, interpolation=cv2.INTER_LINEAR) invHomography = np.linalg.inv(homography) projectedWorldPts = cvutils.projectArray(invHomography, worldPts.T).T projectedVideoPts = cvutils.projectArray(homography, videoPts.T).T
--- a/scripts/display-trajectories.py Wed Jun 04 10:56:12 2014 -0400 +++ b/scripts/display-trajectories.py Wed Jun 04 10:57:09 2014 -0400 @@ -13,32 +13,52 @@ parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file') parser.add_argument('-t', dest = 'trajectoryType', help = 'type of trajectories to display', choices = ['feature', 'object'], default = 'feature') parser.add_argument('-o', dest = 'homographyFilename', help = 'name of the image to world homography file') -parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to display', default = 0, type = int) +parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file') +parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float) +parser.add_argument('--undistorted-multiplication', dest = 'undistortedImageMultiplication', help = 'undistorted image multiplication', type = float) +parser.add_argument('-u', dest = 'undistort', help = 'undistort the video (because features have been extracted that way)', action = 'store_true') +parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to display', type = int) parser.add_argument('-r', dest = 'rescale', help = 'rescaling factor for the displayed image', default = 1., type = float) parser.add_argument('-s', dest = 'nFramesStep', help = 'number of frames between each display', default = 1, type = int) parser.add_argument('--save-images', dest = 'saveAllImages', help = 'save all images', action = 'store_true') -parser.add_argument('--last-frame', dest = 'lastFrameNum', help = 'number of last frame number to save (for image saving, no display is made)', default = None, type = int) +parser.add_argument('--last-frame', dest = 'lastFrameNum', help = 'number of last frame number to save (for image saving, no display is made)', type = int) args = parser.parse_args() -homography = None if args.configFilename: # consider there is a configuration file - params = utils.TrackingParameters() - params.loadConfigFile(args.configFilename) + params = storage.TrackingParameters(args.configFilename) videoFilename = params.videoFilename databaseFilename = params.databaseFilename - homography = inv(loadtxt(params.homographyFilename)) + homography = inv(params.homography) + intrinsicCameraMatrix = params.intrinsicCameraMatrix + distortionCoefficients = params.distortionCoefficients + undistortedImageMultiplication = params.undistortedImageMultiplication + undistort = params.undistort firstFrameNum = params.firstFrameNum +else: + homography = None + undistort = False + intrinsicCameraMatrix = None + distortionCoefficients = [] + undistortedImageMultiplication = None + firstFrameNum = 0 -if args.videoFilename != None: +if not args.configFilename and args.videoFilename != None: videoFilename = args.videoFilename -if args.databaseFilename != None: +if not args.configFilename and args.databaseFilename != None: databaseFilename = args.databaseFilename -if args.homographyFilename != None: +if not args.configFilename and args.homographyFilename != None: homography = inv(loadtxt(args.homographyFilename)) -if args.firstFrameNum != None: +if not args.configFilename and args.intrinsicCameraMatrixFilename != None: + intrinsicCameraMatrix = loadtxt(args.intrinsicCameraMatrixFilename) +if not args.configFilename and args.distortionCoefficients != None: + distortionCoefficients = args.distortionCoefficients +if not args.configFilename and args.undistortedImageMultiplication != None: + undistortedImageMultiplication = args.undistortedImageMultiplication +if not args.configFilename and args.firstFrameNum != None: firstFrameNum = args.firstFrameNum + objects = storage.loadTrajectoriesFromSqlite(databaseFilename, args.trajectoryType) boundingBoxes = storage.loadBoundingBoxTable(databaseFilename) -cvutils.displayTrajectories(videoFilename, objects, boundingBoxes, homography, firstFrameNum, args.lastFrameNum, rescale = args.rescale, nFramesStep = args.nFramesStep, saveAllImages = args.saveAllImages) +cvutils.displayTrajectories(videoFilename, objects, boundingBoxes, homography, firstFrameNum, args.lastFrameNum, rescale = args.rescale, nFramesStep = args.nFramesStep, saveAllImages = args.saveAllImages, undistort = (undistort or args.undistort), intrinsicCameraMatrix = intrinsicCameraMatrix, distortionCoefficients = distortionCoefficients, undistortedImageMultiplication = undistortedImageMultiplication)
--- a/tracking.cfg Wed Jun 04 10:56:12 2014 -0400 +++ b/tracking.cfg Wed Jun 04 10:57:09 2014 -0400 @@ -4,8 +4,22 @@ database-filename = laurier.sqlite # filename of the homography matrix homography-filename = laurier-homography.txt +# filename of the homography matrix +intrinsic-camera-filename = intrinsic-camera.txt +# -0.11759321 0.0148536 0.00030756 -0.00020578 -0.00091816 +distortion-coefficients = -0.11759321 +distortion-coefficients = 0.0148536 +distortion-coefficients = 0.00030756 +distortion-coefficients = -0.00020578 +distortion-coefficients = -0.00091816 +# undistorted image multiplication +undistorted-size-multiplication = 1.31 +# Interpolation method for remapping image when correcting for distortion: 0 for INTER_NEAREST - a nearest-neighbor interpolation; 1 for INTER_LINEAR - a bilinear interpolation (used by default); 2 for INTER_CUBIC - a bicubic interpolation over 4x4 pixel neighborhood; 3 for INTER_LANCZOS4 +interpolation-method = 1 # filename of the mask image (where features are detected) mask-filename = none +# undistort the video for feature tracking +undistort = true # load features from database load-features = false # display trajectories on the video