Mercurial Hosting > traffic-intelligence
changeset 824:28526917a583
merged
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Mon, 27 Jun 2016 16:19:34 -0400 |
parents | f6790357f53b (current diff) 41558145e131 (diff) |
children | 6e4357e9116d 8b74a5176549 |
files | |
diffstat | 6 files changed, 184 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/python/cvutils.py Mon Jun 27 16:19:06 2016 -0400 +++ b/python/cvutils.py Mon Jun 27 16:19:34 2016 -0400 @@ -146,39 +146,53 @@ 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., step = 1): - '''Plays the video''' - windowName = 'frame' + def playVideo(filenames, windowNames = None, firstFrameNums = None, frameRate = -1, interactive = False, printFrames = True, text = None, rescale = 1., step = 1): + '''Plays the video(s)''' + if len(filenames) == 0: + print('Empty filename list') + return + if windowNames is None: + windowNames = ['frame{}'.format(i) for i in xrange(len(filenames))] wait = 5 if rescale == 1.: - cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) + for windowName in windowNames: + cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) if frameRate > 0: wait = int(round(1000./frameRate)) if interactive: wait = 0 - capture = cv2.VideoCapture(filename) - if capture.isOpened(): + captures = [cv2.VideoCapture(fn) for fn in filenames] + if array([cap.isOpened() for cap in captures]).all(): key = -1 ret = True - frameNum = firstFrameNum - capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) + nFramesShown = 0 + if firstFrameNums is not None: + for i in xrange(len(captures)): + captures[i].set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNums[i]) while ret and not quitKey(key): - ret, img = capture.read() - if ret: + rets = [] + images = [] + for cap in captures: + ret, img = cap.read() + rets.append(ret) + images.append(img) + if array(rets).all(): if printFrames: - print('frame {0}'.format(frameNum)) - if text is not None: - cv2.putText(img, text, (10,50), cv2.FONT_HERSHEY_PLAIN, 1, cvRed) - cv2.imshow('frame', img)#cvImshow(windowName, img, rescale) + print('frame shown {0}'.format(nFramesShown)) + for i in xrange(len(filenames)): + if text is not None: + cv2.putText(images[i], text, (10,50), cv2.FONT_HERSHEY_PLAIN, 1, cvRed) + cvImshow(windowNames[i], images[i], rescale) # cv2.imshow('frame', img) key = cv2.waitKey(wait) if saveKey(key): cv2.imwrite('image-{}.png'.format(frameNum), img) - frameNum += step + nFramesShown += step if step > 1: - capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frameNum) + for i in xrange(len(captures)): + captures.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNums[i]+nFramesShown) cv2.destroyAllWindows() else: - print('Video capture for {} failed'.format(filename)) + print('Video captures for {} failed'.format(filenames)) def infoVideo(filename): '''Provides all available info on video '''
--- a/python/metadata.py Mon Jun 27 16:19:06 2016 -0400 +++ b/python/metadata.py Mon Jun 27 16:19:34 2016 -0400 @@ -1,13 +1,14 @@ # from moving import Point -from datetime import datetime +from datetime import datetime, timedelta from os import path +from math import floor -from sqlalchemy import create_engine, Column, Integer, Float, DateTime, String, ForeignKey +from sqlalchemy import orm, create_engine, Column, Integer, Float, DateTime, String, ForeignKey, Boolean, Interval from sqlalchemy.orm import relationship, backref, sessionmaker from sqlalchemy.ext.declarative import declarative_base -from utils import datetimeFormat +from utils import datetimeFormat, removeExtension Base = declarative_base() @@ -20,14 +21,16 @@ ycoordinate = Column(Float) mapImageFilename = Column(String) # path to filename, relative to site name, ie sitename/mapImageFilename nUnitsPerPixel = Column(Float) # number of units of distance per pixel in map image + worldDistanceUnit = Column(String, default = 'm') # make sure it is default in the database - def __init__(self, name, description = "", xcoordinate = None, ycoordinate = None, mapImageFilename = None, nUnitsPerPixel = 1.): + def __init__(self, name, description = "", xcoordinate = None, ycoordinate = None, mapImageFilename = None, nUnitsPerPixel = 1., worldDistanceUnit = 'm'): self.name = name self.description = description self.xcoordinate = xcoordinate self.ycoordinate = ycoordinate self.mapImageFilename = mapImageFilename self.nUnitsPerPixel = nUnitsPerPixel + self.worldDistanceUnit = worldDistanceUnit def getFilename(self): return self.name @@ -53,23 +56,77 @@ self.description = description self.site = site +class CameraType(Base): + ''' Represents parameters of the specific camera used. + + Taken and adapted from tvalib''' + __tablename__ = 'camera_types' + idx = Column(Integer, primary_key=True) + name = Column(String) + resX = Column(Integer) + resY = Column(Integer) + frameRate = Column(Float) + frameRateTimeUnit = Column(String, default = 's') + undistort = Column(Boolean) + intrinsicCameraMatrixStr = Column(String) + distortionCoefficientsStr = Column(String) + undistortedImageMultiplication = Column(Float) + + def __init__(self, name, resX, resY, frameRate, frameRateTimeUnit = 's', trackingConfigurationFilename = None, undistort = None, intrinsicCameraMatrix = None, distortionCoefficients = None, undistortedImageMultiplication = None): + self.name = name + self.resX = resX + self.resY = resY + self.frameRate = frameRate + self.frameRateTimeUnit = frameRateTimeUnit + self.undistort = False + + if trackingConfigurationFilename is not None: + from storage import ProcessParameters + params = ProcessParameters(trackingConfigurationFilename) + if params.undistort: + self.undistort = params.undistort + self.intrinsicCameraMatrix = params.intrinsicCameraMatrix + self.distortionCoefficients = params.distortionCoefficients + self.undistortedImageMultiplication = params.undistortedImageMultiplication + elif undistort is not None: + self.undistort = undistort + self.intrinsicCameraMatrix = intrinsicCameraMatrix + self.distortionCoefficients = distortionCoefficients + self.undistortedImageMultiplication = undistortedImageMultiplication + + # populate the db + if hasattr(self, 'intrinsicCameraMatrix') and self.intrinsicCameraMatrix is not None\ + and hasattr(self, 'distortionCoefficients') and self.distortionCoefficients is not None: + self.intrinsicCameraMatrixStr = ' '.join('{}'.format(x) for x in self.intrinsicCameraMatrix.flatten('C')) + self.distortionCoefficientsStr = ' '.join('{}'.format(x)for x in self.distortionCoefficients) + + @orm.reconstructor + def initOnLoad(self): + from numpy import array + if len(self.intrinsicCameraMatrixStr) > 0: + self.intrinsicCameraMatrix = array([float(x) for x in self.intrinsicCameraMatrixStr.split(" ")]).reshape(3,3) + if len(self.distortionCoefficientsStr) > 0: + self.distortionCoefficients = [float(x) for x in self.distortionCoefficientsStr.split(" ")] + class CameraView(Base): __tablename__ = 'camera_views' idx = Column(Integer, primary_key=True) - frameRate = Column(Float) + description = Column(String) homographyFilename = Column(String) # path to homograph filename, relative to the site name - cameraCalibrationFilename = Column(String) # path to full camera calibration, relative to the site name siteIdx = Column(Integer, ForeignKey('sites.idx')) + cameraTypeIdx = Column(Integer, ForeignKey('camera_types.idx')) homographyDistanceUnit = Column(String, default = 'm') # make sure it is default in the database - configurationFilename = Column(String) # path to configuration .cfg file, relative to site name + trackingConfigurationFilename = Column(String) # path to configuration .cfg file, relative to site name - site = relationship("Site", backref=backref('camera_views', order_by = idx)) + site = relationship("Site", backref=backref('sites', order_by = idx)) + cameraType = relationship('CameraType', backref=backref('camera_views', order_by = idx)) - def __init__(self, frameRate, homographyFilename, cameraCalibrationFilename, site, configurationFilename): - self.frameRate = frameRate + def __init__(self, description, homographyFilename, site, cameraType, trackingConfigurationFilename): + self.description = description self.homographyFilename = homographyFilename self.site = site - self.configurationFilename = configurationFilename + self.cameraType = cameraType + self.trackingConfigurationFilename = trackingConfigurationFilename def getHomographyFilename(self, relativeToSiteFilename = True): if relativeToSiteFilename: @@ -77,6 +134,15 @@ else: return self.homographyFilename + def getTrackingConfigurationFilename(self, relativeToSiteFilename = True): + if relativeToSiteFilename: + return self.site.getFilename()+path.sep+self.trackingConfigurationFilename + else: + return self.trackingConfigurationFilename + + def getTrackingParameters(self): + return ProcessParameters(getTrackingConfigurationFilename()) + class Alignment(Base): __tablename__ = 'alignments' idx = Column(Integer, primary_key=True) @@ -107,23 +173,24 @@ idx = Column(Integer, primary_key=True) name = Column(String) # path relative to the the site name startTime = Column(DateTime) - duration = Column(Float) # video sequence duration - durationUnit = Column(String, default = 's') + duration = Column(Interval) # video sequence duration + databaseFilename = Column(String) # path relative to the the site name siteIdx = Column(Integer, ForeignKey('sites.idx')) cameraViewIdx = Column(Integer, ForeignKey('camera_views.idx')) - configurationFilename = Column(String) site = relationship("Site", backref=backref('video_sequences', order_by = idx)) cameraView = relationship("CameraView", backref=backref('video_sequences', order_by = idx)) - def __init__(self, name, startTime, duration, site, cameraView, configurationFilename = None): - 'startTime is passed as string in utils.datetimeFormat, eg 2011-06-22 10:00:39' + def __init__(self, name, startTime, duration, site, cameraView, databaseFilename = None): + '''startTime is passed as string in utils.datetimeFormat, eg 2011-06-22 10:00:39 + duration is a timedelta object''' self.name = name self.startTime = datetime.strptime(startTime, datetimeFormat) self.duration = duration self.site = site self.cameraView = cameraView - self.configurationFilename = configurationFilename + if databaseFilename is None and len(self.name) > 0: + self.databaseFilename = removeExtension(self.name)+'.sqlite' def getVideoSequenceFilename(self, relativeToSiteFilename = True): if relativeToSiteFilename: @@ -131,8 +198,16 @@ else: return self.name - #def getConfigurationFilename(self): - #'returns the local configuration filename, or the one of the camera view otherwise' + def containsInstant(self, instant): + 'instant is a datetime' + return self.startTime <= instant and self.startTime+self.duration + + def getFrameNum(self, instant): + 'Warning, there is no check of correct time units' + if self.containsInstant(instant): + return int(floor((instant-self.startTime).seconds*self.cameraView.cameraType.frameRate)) + else: + return None # add class for Analysis: foreign key VideoSequenceId, dataFilename, configFilename (get the one from camera view by default), mask? (no, can be referenced in the tracking cfg file)
--- a/scripts/learn-motion-patterns.py Mon Jun 27 16:19:06 2016 -0400 +++ b/scripts/learn-motion-patterns.py Mon Jun 27 16:19:34 2016 -0400 @@ -11,6 +11,7 @@ #parser.add_argument('--cfg', dest = 'configFilename', help = 'name of the configuration file') parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the Sqlite database file', required = True) parser.add_argument('-t', dest = 'trajectoryType', help = 'type of trajectories to display', choices = ['objectfeatures', 'feature', 'object'], default = 'objectfeatures') +parser.add_argument('--max-nobjectfeatures', dest = 'maxNObjectFeatures', help = 'maximum number of features per object to load', type = int, default = 3) parser.add_argument('-n', dest = 'nTrajectories', help = 'number of the object or feature trajectories to load', type = int, default = None) parser.add_argument('-e', dest = 'epsilon', help = 'distance for the similarity of trajectory points', type = float, required = True) parser.add_argument('--metric', dest = 'metric', help = 'metric for the similarity of trajectory points', default = 'cityblock') # default is manhattan distance @@ -34,7 +35,7 @@ features = [] for o in objects: tmp = utils.sortByLength(o.getFeatures(), reverse = True) - features += tmp[:min(len(tmp), 3)] + features += tmp[:min(len(tmp), args.maxNObjectFeatures)] objects = features trajectories = [o.getPositions().asArray().T for o in objects] @@ -50,8 +51,10 @@ prototypeIndices, labels = ml.prototypeCluster(trajectories, similarities, args.minSimilarity, lambda x,y : lcss.computeNormalized(x, y), args.minClusterSize) # this line can be called again without reinitializing similarities +print(ml.computeClusterSizes(labels, prototypeIndices, -1)) + if args.display: - from matplotlib.pyplot import figure + from matplotlib.pyplot import figure, show figure() for i,o in enumerate(objects): if i not in prototypeIndices: @@ -61,5 +64,6 @@ o.plot(utils.colors[labels[i]]) for i in prototypeIndices: objects[i].plot(utils.colors[i]+'o') + show() # TODO store the prototypes (if features, easy, if objects, info must be stored about the type)
--- a/scripts/learn-poi.py Mon Jun 27 16:19:06 2016 -0400 +++ b/scripts/learn-poi.py Mon Jun 27 16:19:34 2016 -0400 @@ -16,6 +16,7 @@ parser.add_argument('--covariance-type', dest = 'covarianceType', help = 'type of covariance of Gaussian model', default = "full") parser.add_argument('-w', dest = 'worldImageFilename', help = 'filename of the world image') parser.add_argument('-u', dest = 'unitsPerPixel', help = 'number of units of distance per pixel', type = float, default = 1.) +parser.add_argument('--display', dest = 'display', help = 'display points of interests', action = 'store_true') # default is manhattan distance args = parser.parse_args() @@ -44,18 +45,22 @@ if not model.converged_: print('Warning: model for '+gmmType+' points did not converge') # plot - fig = plt.figure() - if args.worldImageFilename is not None and args.unitsPerPixel is not None: - img = plt.imread(args.worldImageFilename) - plt.imshow(img) - labels = ml.plotGMMClusters(model, points, fig, nUnitsPerPixel = args.unitsPerPixel) - plt.axis('image') - plt.title(gmmType) - print(gmmType+' Clusters:\n{}'.format(ml.computeClusterSizes(labels, range(model.n_components)))) + if args.display: + fig = plt.figure() + if args.worldImageFilename is not None and args.unitsPerPixel is not None: + img = plt.imread(args.worldImageFilename) + plt.imshow(img) + labels = ml.plotGMMClusters(model, points, fig, nUnitsPerPixel = args.unitsPerPixel) + plt.axis('image') + plt.title(gmmType) + print(gmmType+' Clusters:\n{}'.format(ml.computeClusterSizes(labels, range(model.n_components)))) # save storage.savePOIs(args.databaseFilename, model, gmmType, gmmId) gmmId += 1 - + +if args.display: + plt.show() + # fig = plt.figure() # if args.worldImageFilename is not None and args.pixelsPerUnit is not None: # img = plt.imread(args.worldImageFilename)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/play-synced-videos.py Mon Jun 27 16:19:34 2016 -0400 @@ -0,0 +1,37 @@ +#! /usr/bin/env python + +import sys, argparse, os.path +import cvutils, utils +from metadata import createDatabase, Site, VideoSequence +from datetime import datetime, timedelta + +parser = argparse.ArgumentParser(description='The program displays several views of the same site synchronously.') +parser.add_argument('-i', dest = 'metadataFilename', help = 'name of the metadata file', required = True) +parser.add_argument('-n', dest = 'siteId', help = 'site id or site name', required = True) +parser.add_argument('-t', dest = 'startTime', help = 'time to start playing (format %Y-%m-%d %H:%M:%S, eg 2011-06-22 10:00:39)', required = True) +parser.add_argument('--fps', dest = 'frameRate', help = 'approximate frame rate to replay', default = -1, type = float) +parser.add_argument('-r', dest = 'rescale', help = 'rescaling factor for the displayed image', default = 1., type = float) +parser.add_argument('-s', dest = 'step', help = 'display every s image', default = 1, type = int) + +args = parser.parse_args() + +session = createDatabase(args.metadataFilename) + +if str.isdigit(args.siteId): + site = session.query(Site).filter(Site.idx == int(args.siteId)).first() +else: + site = session.query(Site).filter(Site.description.like('%'+args.siteId+'%')).first() + +if site is None: + print('Site {} was not found in {}. Exiting'.format(args.siteId, args.metadataFilename)) + sys.exit() + +dirname = os.path.split(args.metadataFilename)[0] + +startTime = datetime.strptime(args.startTime, utils.datetimeFormat) +videoSequences = session.query(VideoSequence).filter(VideoSequence.site == site).filter(VideoSequence.startTime <= startTime).all() +videoSequences = [v for v in videoSequences if v.containsInstant(startTime)] +filenames = [dirname+os.path.sep+v.getVideoSequenceFilename() for v in videoSequences] +firstFrameNums = [v.getFrameNum(startTime) for v in videoSequences] + +cvutils.playVideo(filenames, [v.cameraView.description for v in videoSequences], firstFrameNums, args.frameRate, rescale = args.rescale, step = args.step)
--- a/scripts/play-video.py Mon Jun 27 16:19:06 2016 -0400 +++ b/scripts/play-video.py Mon Jun 27 16:19:34 2016 -0400 @@ -7,7 +7,7 @@ parser = argparse.ArgumentParser(description='The program displays the video.') parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file', required = True) parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to display', default = 0, type = int) -parser.add_argument('--fps', dest = 'frameRate', help = 'approximate frame rate to replay', type = float) +parser.add_argument('--fps', dest = 'frameRate', help = 'approximate frame rate to replay', default = -1, type = float) parser.add_argument('-r', dest = 'rescale', help = 'rescaling factor for the displayed image', default = 1., type = float) parser.add_argument('-s', dest = 'step', help = 'display every s image', default = 1, type = int) @@ -17,8 +17,4 @@ if args.firstFrameNum is not None: firstFrameNum = args.firstFrameNum -frameRate = -1 -if args.frameRate is not None: - frameRate = args.frameRate - -cvutils.playVideo(args.videoFilename, firstFrameNum, frameRate, rescale = args.rescale, step = args.step) +cvutils.playVideo([args.videoFilename], None, [firstFrameNum], args.frameRate, rescale = args.rescale, step = args.step)