changeset 971:9897a13772fb

added utils to load video sequence in metadata
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 13 Dec 2017 14:06:20 -0500
parents bf401567a933
children b50145235f9e
files python/metadata.py python/utils.py scripts/create-metadata.py scripts/merge-features.py scripts/play-synced-videos.py
diffstat 5 files changed, 74 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/python/metadata.py	Thu Dec 07 23:31:54 2017 -0500
+++ b/python/metadata.py	Wed Dec 13 14:06:20 2017 -0500
@@ -8,7 +8,7 @@
 from sqlalchemy.orm import relationship, backref, sessionmaker
 from sqlalchemy.ext.declarative import declarative_base
 
-from utils import datetimeFormat, removeExtension, getExtension
+from utils import datetimeFormat, removeExtension, getExtension, TimeConverter
 from cvutils import computeUndistortMaps, videoFilenameExtensions, infoVideo
 from moving import TimeInterval
 
@@ -70,15 +70,7 @@
         else:
             return self.mapImageFilename
 
-    @staticmethod
-    def getSite(session, siteId):
-        'Returns the site(s) matching the index or the name'
-        if str.isdigit(siteId):
-            return session.query(Site).filter(Site.idx == int(siteId)).all()
-        else:
-            return session.query(Site).filter(Site.description.like('%'+siteId+'%')).all()
 
-    
 class EnvironementalFactors(Base):
     '''Represents any environmental factors that may affect the results, in particular
     * changing weather conditions
@@ -358,34 +350,54 @@
     Session = sessionmaker(bind=engine)
     return Session()
 
-def initializeSites(session, directoryName):
-    '''Initializes default site objects and Camera Views
+def getSite(session, siteId):
+    'Returns the site(s) matching the index or the name'
+    if str.isdigit(siteId):
+        return session.query(Site).filter(Site.idx == int(siteId)).all()
+    else:
+        return session.query(Site).filter(Site.description.like('%'+siteId+'%')).all()
+
+def getCameraView(session, viewId):
+    'Returns the site(s) matching the index'
+    return session.query(CameraView).filter(CameraView.idx == int(viewId)).first()
+
+def initializeSites(session, directoryName, nViewsPerSite = 1):
+    '''Initializes default site objects and n camera views per site
     
     eg somedirectory/montreal/ contains intersection1, intersection2, etc.
-    The site names would be somedirectory/montreal/intersection1, somedirectory/montreal/intersection2, etc.'''
+    The site names would be somedirectory/montreal/intersection1, somedirectory/montreal/intersection2, etc.
+    The views should be directories in somedirectory/montreal/intersection1'''
     sites = []
     cameraViews = []
     names = listdir(directoryName)
-    cameraViewIdx = 1
     for name in names:
         if path.isdir(directoryName+sep+name):
             sites.append(Site(directoryName+sep+name, None))
-            cameraViews.append(CameraView('view{}'.format(cameraViewIdx), None, sites[-1], None, None, None))
-            cameraViewIdx += 1
+            for cameraViewIdx in range(1, nViewsPerSite+1):
+                cameraViews.append(CameraView('view{}'.format(cameraViewIdx), None, sites[-1], None, None, None))
     session.add_all(sites)
     session.add_all(cameraViews)
     session.commit()
-# TODO crawler for video files?
 
 def initializeVideos(session, cameraView, directoryName, startTime = None, datetimeFormat = None):
     '''Initializes videos with time or tries to guess it from filename
     directoryName should contain the videos to find and be the relative path from the site location'''
     names = listdir(directoryName)
     videoSequences = []
+    if datetimeFormat is not None:
+        timeConverter = TimeConverter(datetimeFormat)
     for name in names:
         prefix = removeExtension(name)
         extension = getExtension(name)
         if extension in videoFilenameExtensions:
+            if datetimeFormat is not None:
+                from argparse import ArgumentTypeError
+                try:
+                    prefix = name[:name.rfind('_')]
+                    t1 = timeConverter.convert(prefix)
+                    print('DB time {} / Time from filename {}'.format(startTime, t1))
+                except ArgumentTypeError as e:
+                    print('File format error for time {} (prefix {})'.format(name, prefix))
             vidinfo = infoVideo(directoryName+sep+name)
             duration = vidinfo['number of frames']#timedelta(minutes = 27, seconds = 33)
             fps = vidinfo['fps']
--- a/python/utils.py	Thu Dec 07 23:31:54 2017 -0500
+++ b/python/utils.py	Wed Dec 13 14:06:20 2017 -0500
@@ -4,6 +4,7 @@
 
 import matplotlib.pyplot as plt
 from datetime import time, datetime
+from argparse import ArgumentTypeError
 from math import sqrt, ceil, floor
 from scipy.stats import kruskal, shapiro, lognorm
 from scipy.spatial import distance
@@ -24,6 +25,17 @@
     lowerWords = [w[0].upper()+w[1:].lower() for w in words]
     return ' '.join(lowerWords)
 
+class TimeConverter:
+    def __init__(self, datetimeFormat = datetimeFormat):
+        self.datetimeFormat = datetimeFormat
+    
+    def convert(self, s):
+        try:
+            return datetime.strptime(s, self.datetimeFormat)
+        except ValueError:
+            msg = "Not a valid date: '{0}'.".format(s)
+            raise ArgumentTypeError(msg)
+
 #########################
 # Enumerations
 #########################
--- a/scripts/create-metadata.py	Thu Dec 07 23:31:54 2017 -0500
+++ b/scripts/create-metadata.py	Wed Dec 13 14:06:20 2017 -0500
@@ -1,14 +1,30 @@
 #! /usr/bin/env python
 
-import sys, argparse
-import cvutils
+import argparse
+from datetime import datetime
+import metadata, utils
 
+timeConverter = utils.TimeConverter()
 
-parser = argparse.ArgumentParser(description='The program displays the video.')
+parser = argparse.ArgumentParser(description='The program add camera views (metadata.CameraView) for a site or video sequences (metadata.VideoSequence) for a site and a view.')
 #parser.add_argument('-d', dest = 'siteDirectory', help = 'name of the directory for the site')#, required = True
-parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the metadata filename')
-parser.add_argument('-s', dest = 'site', help = 'site id')
-
+parser.add_argument('-i', dest = 'databaseFilename', help = 'name of the metadata filename', required = True)
+parser.add_argument('-d', dest = 'dirname', help = 'directory name containing sites or video sequences for a given view')
+#parser.add_argument('-s', dest = 'siteId', help = 'site id (if provided, the program adds video sequences for the camera view)')
+parser.add_argument('-v', dest = 'viewId', help = 'camera view id')
+parser.add_argument('--nviews', dest = 'nViewsPerSite', help = 'default number of camera views', type = int, default = 1)
+parser.add_argument('-s', dest = 'startTime', help = 'starting time of the first video (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)', type = timeConverter.convert)
+parser.add_argument('--timeformat', dest = 'timeFormat', help = 'time format of the video filenames (optional) (eg %%Y_%%m%%d_%%H%%M%%S, eg 2017_0627_163231)')
 args = parser.parse_args()
 
-print('Unfinished, look at methods in metadata module')
+session = metadata.createDatabase(args.databaseFilename)
+if args.viewId is not None:
+    # sites = metadata.getSite(session, args.siteId)
+    # if len(sites) > 1:
+    #     print('{} sites found matching {}, using the first {}'.format(len(sites), args.siteId, sites[0].name))
+    # site = sites[0]
+    cameraView = metadata.getCameraView(session, args.viewId)
+    metadata.initializeVideos(session, cameraView, args.dirname, args.startTime, args.timeFormat)
+else:
+    metadata.initializeSites(session, args.dirname, args.nViewsPerSite)
+
--- a/scripts/merge-features.py	Thu Dec 07 23:31:54 2017 -0500
+++ b/scripts/merge-features.py	Wed Dec 13 14:06:20 2017 -0500
@@ -2,21 +2,23 @@
 
 import sys, argparse, os.path, sqlite3
 import cvutils, utils, moving, storage
-from metadata import createDatabase, Site, VideoSequence, CameraView
+from metadata import createDatabase, Site, VideoSequence, CameraView, getSite
 from datetime import datetime, timedelta
 
+timeConverter = utils.TimeConverter()
+
 parser = argparse.ArgumentParser(description='The program merges feature trajectories recorded from the same site synchronously between start and end time.')
 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('-f', dest = 'startTime', help = 'time to start merging features (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)') # if not provided, take common time interval
-parser.add_argument('-l', dest = 'endTime', help = 'time to stop merging features (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)')
+parser.add_argument('-f', dest = 'startTime', help = 'time to start merging features (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)', type = timeConverter.convert) # if not provided, take common time interval
+parser.add_argument('-l', dest = 'endTime', help = 'time to stop merging features (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)', type = timeConverter.convert)
 parser.add_argument('-o', dest = 'outputDBFilename', help = 'name of the output SQLite file', required = True)
 
 args = parser.parse_args()
 
 session = createDatabase(args.metadataFilename)
 
-site = Site.getSite(session, args.siteId)
+site = getSite(session, args.siteId)
 if site is None:
     print('Site {} was not found in {}. Exiting'.format(args.siteId, args.metadataFilename))
     sys.exit()
--- a/scripts/play-synced-videos.py	Thu Dec 07 23:31:54 2017 -0500
+++ b/scripts/play-synced-videos.py	Wed Dec 13 14:06:20 2017 -0500
@@ -2,13 +2,15 @@
 
 import sys, argparse, os.path
 import cvutils, utils
-from metadata import createDatabase, Site, CameraView, VideoSequence
+from metadata import createDatabase, Site, CameraView, VideoSequence, getSite
 from datetime import datetime, timedelta
 
+timeConverter = utils.TimeConverter()
+
 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('-f', 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('-f', dest = 'startTime', help = 'time to start playing (format %%Y-%%m-%%d %%H:%%M:%%S, eg 2011-06-22 10:00:39)', required = True, type = timeConverter.convert)
 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,7 +19,7 @@
 
 session = createDatabase(args.metadataFilename)
 
-site = Site.getSite(session, args.siteId)
+site = getSite(session, args.siteId)
 if site is None:
     print('Site {} was not found in {}. Exiting'.format(args.siteId, args.metadataFilename))
     sys.exit()