changeset 588:c5406edbcf12

added loading ground truth annotations (ground truth) from polytrack format
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Fri, 05 Dec 2014 00:54:38 -0500
parents cf578ba866da
children 5800a87f11ae 5e09583275a4
files python/moving.py python/storage.py python/utils.py
diffstat 3 files changed, 66 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/python/moving.py	Thu Dec 04 17:46:32 2014 -0500
+++ b/python/moving.py	Fri Dec 05 00:54:38 2014 -0500
@@ -924,7 +924,8 @@
 
 class MovingObject(STObject):
     '''Class for moving objects: a spatio-temporal object 
-    with a trajectory and a geometry (constant volume over time) and a usertype (e.g. road user) coded as a number (see 
+    with a trajectory and a geometry (constant volume over time) 
+    and a usertype (e.g. road user) coded as a number (see userTypeNames)
     '''
 
     def __init__(self, num = None, timeInterval = None, positions = None, velocities = None, geometry = None, userType = userType2Num['unknown']):
@@ -1278,22 +1279,21 @@
 
 
 ##################
-# Bounding Boxes
+# Annotations
 ##################
 
-# class BoundingBoxes(STObject):
-#     '''Class for : a spatio-temporal object 
-#     with a trajectory and a geometry (constant volume over time) and a usertype (e.g. road user) coded as a number (see 
-#     '''
+class BBAnnotation(MovingObject):
+    '''Class for : a series of ground truth annotations using bounding boxes
+    Its center is the center of the containing shape
+    '''
 
-#     def __init__(self, num = None, timeInterval = None, positions = None, velocities = None, geometry = None, userType = userType2Num['unknown']):
-#         super(MovingObject, self).__init__(num, timeInterval)
-#         self.positions = positions
-#         self.velocities = velocities
-#         self.geometry = geometry
-#         self.userType = userType
-#         self.features = []
-#         # compute bounding polygon from trajectory
+    def __init__(self, num = None, timeInterval = None, topPositions = None, bottomPositions = None, userType = userType2Num['unknown']):
+        super(BBAnnotation, self).__init__(num, timeInterval, Trajectory(), userType = userType)
+        self.topPositions = topPositions.getPositions()
+        self.bottomPositions = bottomPositions.getPositions()
+        for i in xrange(int(topPositions.length())):
+            self.positions.addPosition((topPositions.getPositionAt(i) + bottomPositions.getPositionAt(i)).multiply(0.5))
+        
 
 def plotRoadUsers(objects, colors):
     '''Colors is a PlottingPropertyValues instance'''
--- a/python/storage.py	Thu Dec 04 17:46:32 2014 -0500
+++ b/python/storage.py	Fri Dec 05 00:54:38 2014 -0500
@@ -34,6 +34,7 @@
     except sqlite3.OperationalError as error:
         printDBError(error)
 
+# TODO: add test if database connection is open
 # IO to sqlite
 def writeTrajectoriesToSqlite(objects, outputFilename, trajectoryType, objectNumbers = -1):
     """
@@ -271,16 +272,16 @@
     cursor = connection.cursor()
 
     try:
-        trajectoryIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
+        idQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
         if trajectoryType == 'feature':
-            queryStatement = 'SELECT * from '+tableName+' '+trajectoryIdQuery+'ORDER BY trajectory_id, frame_number'
+            queryStatement = 'SELECT * from '+tableName+' '+idQuery+'ORDER BY trajectory_id, frame_number'
             cursor.execute(queryStatement)
             logging.debug(queryStatement)
         elif trajectoryType == 'object':
-            queryStatement = 'SELECT OF.object_id, P.frame_number, avg(P.x_coordinate), avg(P.y_coordinate) from '+tableName+' P, objects_features OF where P.trajectory_id = OF.trajectory_id '+objectIdQuery+'group by OF.object_id, P.frame_number ORDER BY OF.object_id, P.frame_number'
+            queryStatement = 'SELECT OF.object_id, P.frame_number, avg(P.x_coordinate), avg(P.y_coordinate) from '+tableName+' P, objects_features OF where P.trajectory_id = OF.trajectory_id '+idQuery+'group by OF.object_id, P.frame_number ORDER BY OF.object_id, P.frame_number'
             cursor.execute(queryStatement)
             logging.debug(queryStatement)
-        elif trajectoryType == 'bbtop' or trajectoryType == 'bbbottom':
+        elif trajectoryType in ['bbtop', 'bbbottom']:
             if trajectoryType == 'bbtop':
                 corner = 'top_left'
             elif trajectoryType == 'bbbottom':
@@ -300,21 +301,36 @@
     for row in cursor:
         if row[0] != objId:
             objId = row[0]
-            if obj != None:
+            if obj != None and obj.length() == obj.positions.length():
                 objects.append(obj)
+            elif obj != None:
+                print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length()))
             obj = moving.MovingObject(row[0], timeInterval = moving.TimeInterval(row[1], row[1]), positions = moving.Trajectory([[row[2]],[row[3]]]))
         else:
             obj.timeInterval.last = row[1]
             obj.positions.addPositionXY(row[2],row[3])
 
-    if obj:
+    if obj != None and obj.length() == obj.positions.length():
         objects.append(obj)
+    elif obj != None:
+        print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length()))
 
     return objects
 
+def loadUserTypesFromTable(cursor, trajectoryType, objectNumbers):
+    objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
+    if objectIdQuery == '':
+        cursor.execute('SELECT object_id, road_user_type from objects')
+    else:
+        cursor.execute('SELECT object_id, road_user_type from objects where '+objectIdQuery[7:])
+    userTypes = {}
+    for row in cursor:
+        userTypes[row[0]] = row[1]
+    return userTypes
+
 def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None):
     '''Loads the first objectNumbers objects or the indices in objectNumbers from the database'''
-    connection = sqlite3.connect(filename) # add test if it open
+    connection = sqlite3.connect(filename)
 
     objects = loadTrajectoriesFromTable(connection, 'positions', trajectoryType, objectNumbers)
     objectVelocities = loadTrajectoriesFromTable(connection, 'velocities', trajectoryType, objectNumbers)
@@ -348,24 +364,38 @@
                 obj.featureNumbers = featureNumbers[obj.getNum()]
 
             # load userType
-            if objectIdQuery == '':
-                cursor.execute('SELECT object_id, road_user_type from objects')
-            else:
-                cursor.execute('SELECT object_id, road_user_type from objects where '+objectIdQuery[7:])
-            userTypes = {}
-            for row in cursor:
-                userTypes[row[0]] = row[1]
-            
+            userTypes = loadUserTypesFromTable(cursor, trajectoryType, objectNumbers)
             for obj in objects:
                 obj.userType = userTypes[obj.getNum()]
              
         except sqlite3.OperationalError as error:
             printDBError(error)
-            return []
+            objects = []
 
     connection.close()
     return objects
 
+def loadGroundTruthFromSqlite(filename, gtType, gtNumbers = None):
+    'Loads bounding box annotations (ground truth) from an SQLite '
+    connection = sqlite3.connect(filename)
+    gt = []
+
+    if gtType == 'bb':
+        topCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbtop', gtNumbers)
+        bottomCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbbottom', gtNumbers)
+        userTypes = loadUserTypesFromTable(connection.cursor(), 'object', gtNumbers) # string format is same as object
+        
+        for t, b in zip(topCorners, bottomCorners):
+            num = t.getNum()
+            if t.getNum() == b.getNum():
+                annotation = moving.BBAnnotation(num, t.getTimeInterval(), t, b, userTypes[num])
+                gt.append(annotation)
+    else:
+        print ('Unknown type of annotation {}'.format(gtType))
+
+    connection.close()
+    return gt
+
 def deleteFromSqlite(filename, dataType):
     'Deletes (drops) some tables in the filename depending on type of data'
     import os
--- a/python/utils.py	Thu Dec 04 17:46:32 2014 -0500
+++ b/python/utils.py	Fri Dec 05 00:54:38 2014 -0500
@@ -61,15 +61,13 @@
     def nSamples(self):
         return sum(self.counts)
 
-def cumulativeDensityFunction(sample):
+def cumulativeDensityFunction(sample, normalized = False):
     '''Returns the cumulative density function of the sample of a random variable'''
-    from numpy.core.multiarray import array
-    from numpy.lib.function_base import unique
-    from numpy.core.fromnumeric import sum
-    a = array(sample)
-    a.sort()
-    xaxis = unique(a)
-    counts = [sum(a <= x) for x in xaxis]
+    from numpy import arange, cumsum
+    xaxis = sorted(sample)
+    counts = arange(1,len(sample)+1) # dtype = float
+    if normalized:
+        counts /= float(len(sample))
     return xaxis, counts
 
 class EmpiricalDiscreteDistribution(EmpiricalDistribution):