diff python/metadata.py @ 824:28526917a583

merged
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Mon, 27 Jun 2016 16:19:34 -0400
parents 26daf35180ad
children 6e4357e9116d
line wrap: on
line diff
--- 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)