changeset 312:6c068047edbf

merged with Mohamed s work
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 11 Apr 2013 22:46:33 -0400
parents 273c200ec32e (diff) 80cbafd69109 (current diff)
children 43e62b9cb652
files python/indicators.py python/ml.py python/utils.py
diffstat 19 files changed, 579 insertions(+), 223 deletions(-) [+]
line wrap: on
line diff
--- a/python/calibration-translation.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/calibration-translation.py	Thu Apr 11 22:46:33 2013 -0400
@@ -58,7 +58,7 @@
     frameFilename = utils.removeExtension(f)+'-frame.png' # TODO if frame image already exists, no need to search for it again
     if not os.path.exists(frameFilename):
         key = -1
-        while key != cvutils.cvKeyNumbers['y']:
+        while chr(key&255) != 'y':
             (ret, img) = captures[f].read()
             cv2.imshow('Image',img)
             print('Can one see the reference points in the image? (y/n)')
@@ -91,15 +91,15 @@
             cv2.circle(displayImg, tuple(p+t[0]), 3, (255,0,0))
         cv2.imshow('Image',displayImg)
 
-        while not(key == cvutils.cvKeyNumbers['y'] or key == cvutils.cvKeyNumbers['n']):
+        while not(chr(key&255) == 'y' or chr(key&255) == 'n'):
             print('Are the translated points rightly located (y/n)?')
             key = cv2.waitKey(0)
-        if key == cvutils.cvKeyNumbers['y']: # compute homography with translated numbers
+        if chr(key&255) == 'y': # compute homography with translated numbers
             newImgPts = np.array([p+t[0] for p in imgPts])
     else:
         print('No translation could be found automatically. You will have to manually input world reference points.')
 
-    if t==None or key != cvutils.cvKeyNumbers['y']:# if no translation could computed or it is not satisfactory
+    if t==None or chr(key&255) != 'y':# if no translation could computed or it is not satisfactory
         print('Select the corresponding points in the same order as in the reference image')
         plt.figure(1)
         plt.imshow(displayRef)
--- a/python/compute-homography.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/compute-homography.py	Thu Apr 11 22:46:33 2013 -0400
@@ -71,7 +71,7 @@
 
 homography = np.array([])
 if '-p' in options.keys():
-    worldPts, videoPts = cvutils.loadPointCorrespondences(args[0])
+    worldPts, videoPts = cvutils.loadPointCorrespondences(options['-p'])
     homography, mask = cv2.findHomography(videoPts, worldPts) # method=0, ransacReprojThreshold=3
 elif '-i' in options.keys() and '-w' in options.keys():
     nPoints = 4
--- a/python/cvutils.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/cvutils.py	Thu Apr 11 22:46:33 2013 -0400
@@ -24,9 +24,11 @@
                                          cvGreen,
                                          cvBlue])
 
-cvKeyNumbers = {'a':1048673,
-                'n': 1048686,
-                'y': 1048697}
+def quitKey(key):
+    return chr(key&255)== 'q' or chr(key&255) == 'Q'
+
+def saveKey(key):
+    return chr(key&255) == 's'
 
 def drawLines(filename, origins, destinations, w = 1, resultFilename='image.png'):
     '''Draws lines over the image '''
@@ -59,14 +61,6 @@
     points = loadtxt(filename, dtype=float32)
     return  (points[:2,:].T, points[2:,:].T) # (world points, image points)
 
-def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=0.0):
-    '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)'''
-    #cvSrcPoints = arrayToCvMat(srcPoints);
-    #cvDstPoints = arrayToCvMat(dstPoints);
-    #H = cv.CreateMat(3, 3, cv.CV_64FC1)
-    H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold)
-    return H
-
 def cvMatToArray(cvmat):
     '''Converts an OpenCV CvMat to numpy array.'''
     from numpy.core.multiarray import zeros
@@ -77,6 +71,11 @@
     return a
 
 if opencvExists:
+    def computeHomography(srcPoints, dstPoints, method=0, ransacReprojThreshold=0.0):
+        '''Returns the homography matrix mapping from srcPoints to dstPoints (dimension Nx2)'''
+        H, mask = cv2.findHomography(srcPoints, dstPoints, method, ransacReprojThreshold)
+        return H
+
     def arrayToCvMat(a, t = cv2.cv.CV_64FC1):
         '''Converts a numpy array to an OpenCV CvMat, with default type CV_64FC1.'''
         cvmat = cv2.cv.CreateMat(a.shape[0], a.shape[1], t)
@@ -92,21 +91,24 @@
         for i in range(0, last-1):
             cv2.line(img, positions[i].asint().astuple(), positions[i+1].asint().astuple(), color)
 
-    def playVideo(filename, firstFrameNum = 0):
+    def playVideo(filename, firstFrameNum = 0, frameRate = -1):
         '''Plays the video'''
+        wait = 5
+        if frameRate > 0:
+            wait = int(round(1000./frameRate))
         capture = cv2.VideoCapture(filename)
         if capture.isOpened():
             key = -1
             ret = True
             frameNum = firstFrameNum
             capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum)
-            while ret and key!= 113: # 'q'
+            while ret and not quitKey(key):
                 ret, img = capture.read()
                 if ret:
                     print('frame {0}'.format(frameNum))
                     frameNum+=1
                     cv2.imshow('frame', img)
-                    key = cv2.waitKey(5)
+                    key = cv2.waitKey(wait)
 
     def getImagesFromVideo(filename, nImages = 1, saveImage = False):
         '''Returns nImages images from the video sequence'''
@@ -142,7 +144,7 @@
                 lastFrameNum = maxint
             else:
                 lastFrameNum = lastFrameNumArg
-            while ret and key!= 113 and frameNum < lastFrameNum: # 'q'
+            while ret and not quitKey(key) and frameNum < lastFrameNum:
                 ret, img = capture.read()
                 if ret:
                     print('frame {0}'.format(frameNum))
@@ -157,7 +159,7 @@
                             cv2.putText(img, '{0}'.format(obj.num), obj.projectedPositions[frameNum-obj.getFirstInstant()].asint().astuple(), cv2.FONT_HERSHEY_PLAIN, 1, cvRed)
                     cv2.imshow('frame', img)
                     key = cv2.waitKey()
-                    if key == 115:
+                    if saveKey(key):
                         cv2.imwrite('image.png', img)
                     frameNum += 1
     
--- a/python/display-trajectories.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/display-trajectories.py	Thu Apr 11 22:46:33 2013 -0400
@@ -4,30 +4,47 @@
 
 import storage
 import cvutils
+from utils import FakeSecHead
 
 from numpy.linalg.linalg import inv
 from numpy import loadtxt
+from ConfigParser import ConfigParser
 
 options, args = getopt.getopt(sys.argv[1:], 'hi:d:t:o:f:',['help']) 
 # alternative long names are a pain to support ,'video-filename=','database-filename=', 'type='
-# todo parse the cfg file (problem, python ConfigParser needs section headers)
+
 options = dict(options)
 
-if '--help' in options.keys() or '-h' in options.keys() or len(sys.argv) == 1 or not '-i' in options.keys() or not '-d' in options.keys():
-    print('Usage: {0} --help|-h -i video-filename -d database-filename [-t object_type] [-o image2world_homography] [-f first_frame]'.format(sys.argv[0]))
+print options, args
+
+if '--help' in options.keys() or '-h' in options.keys() or len(sys.argv) == 1:
+    print('Usage: '+sys.argv[0]+' --help|-h -i video-filename -d database-filename [-t object_type] [-o image2world_homography] [-f first_frame]\n'
+          +'Or   : '+sys.argv[0]+' [-t object_type] config_file.cfg\n\n'
+          'Order matters between positional and named arguments\n'
+          'object_type can be feature or object')
     sys.exit()
 
 objectType = 'feature'
 if '-t' in options.keys():
     objectType = options['-t']
 
-objects = storage.loadTrajectoriesFromSqlite(options['-d'], objectType)
+if len(args)>0: # consider there is a configuration file
+    config = ConfigParser()
+    config.readfp(FakeSecHead(open(args[0])))
+    sectionHeader = config.sections()[0]
+    videoFilename = config.get(sectionHeader, 'video-filename')
+    databaseFilename = config.get(sectionHeader, 'database-filename')
+    homography = inv(loadtxt(config.get(sectionHeader, 'homography-filename')))
+    firstFrameNum = config.getint(sectionHeader, 'frame1')
+else:
+    videoFilename = options['-i']
+    databaseFilename = options['-d']
+    homography = None
+    if '-o' in options.keys():
+        homography = inv(loadtxt(options['-o']))            
+    firstFrameNum = 0
+    if '-f' in options.keys():
+        firstFrameNum = int(options['-f'])
 
-homography = None
-if '-o' in options.keys():
-    homography = inv(loadtxt(options['-o']))
-firstFrameNum = 0
-if '-f' in options.keys():
-    firstFrameNum = int(options['-f'])
-
-cvutils.displayTrajectories(options['-i'], objects, homography, firstFrameNum)
+objects = storage.loadTrajectoriesFromSqlite(databaseFilename, objectType)
+cvutils.displayTrajectories(videoFilename, objects, homography, firstFrameNum)
--- a/python/event.py	Tue Dec 25 02:24:21 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-#! /usr/bin/env python
-'''Libraries for events
-Interactions, pedestrian crossing...'''
-
-#import utils;
-import moving
-
-__metaclass__ = type
-
-class Interaction(moving.STObject):
-    '''Class for an interaction between two road users 
-    or a road user and an obstacle
-    
-    link to the moving objects
-    '''
-
-    categories = {'headon': 0,
-                  'rearend': 1,
-                  'side': 2,
-                  'parallel': 3}
-
-    def __init__(self, num = None, timeInterval = None, roaduserNum1 = None, roaduserNum2 = None, movingObject1 = None, movingObject2 = None, categoryNum = None):
-        moving.STObject.__init__(self, num, timeInterval)
-        self.roaduserNumbers = set([roaduserNum1, roaduserNum2])
-        self.movingObject1 = movingObject1
-        self.movingObject2 = movingObject2
-        self.categoryNum = categoryNum
-
-    def getIndicator(self, indicatorName):
-        if hasattr(self, 'indicators'):
-            for i in self.indicators:
-                if i.name == indicatorName:
-                    return i
-        else:
-            return None
-
-    def computeIndicators(self):
-        '''Computes the collision course cosine only if the cosine is positive'''
-        collisionCourseDotProduct = [0]*int(self.timeInterval.length())
-        collisionCourseCosine = {}
-        distances = [0]*int(self.timeInterval.length())
-        for i,instant in enumerate(self.timeInterval):
-            deltap = self.movingObject1.getPositionAtInstant(instant)-self.movingObject2.getPositionAtInstant(instant)
-            deltav = self.movingObject2.getVelocityAtInstant(instant)-self.movingObject1.getVelocityAtInstant(instant)
-            collisionCourseDotProduct[i] = moving.Point.dot(deltap, deltav)
-            distances[i] = deltap.norm2()
-            if collisionCourseDotProduct[i] > 0:
-                collisionCourseCosine[instant] = collisionCourseDotProduct[i]/(distances[i]*deltav.norm2())
-        self.indicators = [moving.SeverityIndicator('Collision Course Dot Product', collisionCourseDotProduct, self.timeInterval),
-                           moving.SeverityIndicator('Distances', distances, self.timeInterval),
-                           moving.SeverityIndicator('Collision Course Cosine', collisionCourseCosine)]
-
-def createInteractions(objects):
-    '''Create all interactions of two co-existing road users
-
-    todo add test to compute categories?'''
-    interactions = []
-    num = 0
-    for i in xrange(len(objects)):
-        for j in xrange(i):
-            commonTimeInterval = objects[i].commonTimeInterval(objects[j])
-            if not commonTimeInterval.empty():
-                interactions.append(Interaction(num, commonTimeInterval, objects[i].num, objects[j].num, objects[i], objects[j]))
-                num += 1
-    return interactions
-
-class Crossing(moving.STObject):
-    '''Class for the event of a street crossing
-
-    TODO: detecter passage sur la chaussee
-    identifier origines et destination (ou uniquement chaussee dans FOV)
-    carac traversee
-    detecter proximite veh (retirer si trop similaire simultanement
-    carac interaction'''
-    
-    def __init__(self, roaduserNum = None, num = None, timeInterval = None):
-        moving.STObject.__init__(self, num, timeInterval)
-        self.roaduserNum = roaduserNum
-
-    
-
-if __name__ == "__main__":
-    import doctest
-    import unittest
-    #suite = doctest.DocFileSuite('tests/moving.txt')
-    suite = doctest.DocTestSuite()
-    unittest.TextTestRunner().run(suite)
-    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/events.py	Thu Apr 11 22:46:33 2013 -0400
@@ -0,0 +1,235 @@
+#! /usr/bin/env python
+'''Libraries for events
+Interactions, pedestrian crossing...'''
+
+import numpy as np
+from numpy import arccos
+
+import multiprocessing
+import itertools
+
+import moving
+import prediction
+import indicators
+
+__metaclass__ = type
+
+class Interaction(moving.STObject):
+    '''Class for an interaction between two road users 
+    or a road user and an obstacle
+    
+    link to the moving objects
+    contains the indicators in a dictionary with the names as keys
+    '''
+
+    categories = {'headon': 0,
+                  'rearend': 1,
+                  'side': 2,
+                  'parallel': 3}
+
+    def __init__(self, num = None, timeInterval = None, roaduserNum1 = None, roaduserNum2 = None, movingObject1 = None, movingObject2 = None, categoryNum = None):
+        moving.STObject.__init__(self, num, timeInterval)
+        self.roaduserNumbers = set([roaduserNum1, roaduserNum2])
+        self.movingObject1 = movingObject1
+        self.movingObject2 = movingObject2
+        self.categoryNum = categoryNum
+        self.indicators = {}
+
+    def getIndicator(self, indicatorName):
+        return self.indicators[indicatorName]
+
+    def addIndicator(self, indicator):
+        self.indicators[indicator.name] = indicator
+
+    def computeIndicators(self):
+        '''Computes the collision course cosine only if the cosine is positive'''
+        collisionCourseDotProducts = {}#[0]*int(self.timeInterval.length())
+        collisionCourseCosines = {}
+        distances = {}#[0]*int(self.timeInterval.length())
+        speedDifferentials = {}
+        for instant in self.timeInterval:
+            deltap = self.movingObject1.getPositionAtInstant(instant)-self.movingObject2.getPositionAtInstant(instant)
+            deltav = self.movingObject2.getVelocityAtInstant(instant)-self.movingObject1.getVelocityAtInstant(instant)
+            collisionCourseDotProducts[instant] = moving.Point.dot(deltap, deltav)
+            distances[instant] = deltap.norm2() # todo compute closest feature distance, if features
+            speedDifferentials[instant] = deltav.norm2()
+            if collisionCourseDotProducts[instant] > 0:
+                collisionCourseCosines[instant] = arccos(collisionCourseDotProducts[instant]/(distances[instant]*speedDifferentials[instant]))
+
+        # todo shorten the time intervals based on the interaction definition
+        self.addIndicator(indicators.SeverityIndicator('Collision Course Dot Product', collisionCourseDotProducts))
+        self.addIndicator(indicators.SeverityIndicator('Distance', distances))
+        self.addIndicator(indicators.SeverityIndicator('Speed Differential', speedDifferentials))
+        self.addIndicator(indicators.SeverityIndicator('Collision Course Cosine', collisionCourseCosines))
+
+        # todo test for interaction instants and interval, compute indicators
+
+    def addVideoFilename(self,videoFilename):
+        self.videoFilename= videoFilename	
+
+    def addInteractionType(self,interactionType):
+	''' interaction types: conflict or collision if they are known'''
+        self.interactionType= interactionType			
+
+def createInteractions(objects):
+    '''Create all interactions of two co-existing road users
+
+    todo add test to compute categories?'''
+    interactions = []
+    num = 0
+    for i in xrange(len(objects)):
+        for j in xrange(i):
+            commonTimeInterval = objects[i].commonTimeInterval(objects[j])
+            if not commonTimeInterval.empty():
+                interactions.append(Interaction(num, commonTimeInterval, objects[i].num, objects[j].num, objects[i], objects[j]))
+                num += 1
+    return interactions
+
+
+# TODO:
+#http://stackoverflow.com/questions/3288595/multiprocessing-using-pool-map-on-a-function-defined-in-a-class
+#http://www.rueckstiess.net/research/snippets/show/ca1d7d90
+def calculateIndicatorPipe(pairs, predParam, timeHorizon=75,collisionDistanceThreshold=1.8):  
+    collisionPoints, crossingZones = prediction.computeCrossingsCollisions(pairs.movingObject1, pairs.movingObject2, predParam, collisionDistanceThreshold, timeHorizon)      
+    #print pairs.num    
+    # Ignore empty collision points
+    empty = 1
+    for i in collisionPoints:
+        if(collisionPoints[i] != []):
+            empty = 0
+    if(empty == 1):
+        pairs.hasCP = 0
+    else:
+        pairs.hasCP = 1
+    pairs.CP = collisionPoints
+    
+    # Ignore empty crossing zones
+    empty = 1
+    for i in crossingZones:
+        if(crossingZones[i] != []):
+            empty = 0
+    if(empty == 1):
+        pairs.hasCZ = 0
+    else:
+        pairs.hasCZ = 1
+    pairs.CZ = crossingZones
+    return pairs
+
+def calculateIndicatorPipe_star(a_b):
+    """Convert `f([1,2])` to `f(1,2)` call."""
+    return calculateIndicatorPipe(*a_b)
+
+class VehPairs():
+    '''Create a veh-pairs object from objects list'''
+    def __init__(self,objects):
+        self.pairs = createInteractions(objects)
+        self.interactionCount = 0
+        self.CPcount = 0
+        self.CZcount = 0
+    
+    # Process indicator calculation with support for multi-threading
+    def calculateIndicators(self,predParam,threads=1,timeHorizon=75,collisionDistanceThreshold=1.8):       
+        if(threads > 1):
+            pool = multiprocessing.Pool(threads)
+            self.pairs = pool.map(calculateIndicatorPipe_star, itertools.izip(self.pairs, itertools.repeat(predParam)))
+            pool.close()
+        else:
+            #prog = Tools.ProgressBar(0, len(self.pairs), 77) #Removed in traffic-intelligenc port
+            for j in xrange(len(self.pairs)):
+                #prog.updateAmount(j) #Removed in traffic-intelligenc port
+                collisionPoints, crossingZones = prediction.computeCrossingsCollisions(self.pairs[j].movingObject1, self.pairs[j].movingObject2, predParam, collisionDistanceThreshold, timeHorizon)      
+                
+                # Ignore empty collision points
+                empty = 1
+                for i in collisionPoints:
+                    if(collisionPoints[i] != []):
+                        empty = 0
+                if(empty == 1):
+                    self.pairs[j].hasCP = 0
+                else:
+                    self.pairs[j].hasCP = 1
+                self.pairs[j].CP = collisionPoints
+                
+                # Ignore empty crossing zones
+                empty = 1
+                for i in crossingZones:
+                    if(crossingZones[i] != []):
+                        empty = 0
+                if(empty == 1):
+                    self.pairs[j].hasCZ = 0
+                else:
+                    self.pairs[j].hasCZ = 1
+                self.pairs[j].CZ = crossingZones       
+                
+        for j in self.pairs:
+            self.interactionCount = self.interactionCount + len(j.CP)
+        self.CPcount = len(self.getCPlist())
+        self.Czcount = len(self.getCZlist())
+    
+    
+    def getPairsWCP(self):
+        lists = []
+        for j in self.pairs:
+            if(j.hasCP):
+                lists.append(j.num)
+        return lists
+        
+    def getPairsWCZ(self):
+        lists = []
+        for j in self.pairs:
+            if(j.hasCZ):
+                lists.append(j.num)
+        return lists
+    
+    def getCPlist(self,indicatorThreshold=99999):
+        lists = []
+        for j in self.pairs:
+            if(j.hasCP):
+                for k in j.CP:
+                    if(j.CP[k] != [] and j.CP[k][0].indicator < indicatorThreshold):
+                        lists.append([k,j.CP[k][0]])
+        return lists
+     
+    def getCZlist(self,indicatorThreshold=99999):
+        lists = []
+        for j in self.pairs:
+            if(j.hasCZ):
+                for k in j.CZ:
+                    if(j.CZ[k] != [] and j.CZ[k][0].indicator < indicatorThreshold):
+                        lists.append([k,j.CZ[k][0]])
+        return lists
+        
+    def genIndicatorHistogram(self, CPlist=False, bins=range(0,100,1)):
+        if(not CPlist):
+            CPlist = self.getCPlist()
+        if(not CPlist):
+            return False
+        TTC_list = []
+        for i in CPlist:
+            TTC_list.append(i[1].indicator)
+        histo = np.histogram(TTC_list,bins=bins)
+        histo += (histo[0].astype(float)/np.sum(histo[0]),)
+        return histo
+
+class Crossing(moving.STObject):
+    '''Class for the event of a street crossing
+
+    TODO: detecter passage sur la chaussee
+    identifier origines et destination (ou uniquement chaussee dans FOV)
+    carac traversee
+    detecter proximite veh (retirer si trop similaire simultanement
+    carac interaction'''
+    
+    def __init__(self, roaduserNum = None, num = None, timeInterval = None):
+        moving.STObject.__init__(self, num, timeInterval)
+        self.roaduserNum = roaduserNum
+
+    
+
+if __name__ == "__main__":
+    import doctest
+    import unittest
+    #suite = doctest.DocFileSuite('tests/moving.txt')
+    suite = doctest.DocTestSuite()
+    unittest.TextTestRunner().run(suite)
+    
--- a/python/indicators.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/indicators.py	Thu Apr 11 22:46:33 2013 -0400
@@ -4,7 +4,7 @@
 __metaclass__ = type
 
 import moving
-from utils import LCSS
+
 # need for a class representing the indicators, their units, how to print them in graphs...
 class TemporalIndicator:
     '''Class for temporal indicators
@@ -18,7 +18,7 @@
     
     def __init__(self, name, values, timeInterval=None, maxValue = None):
         self.name = name
-        self.isCosine = name.find('Cosine')
+        self.isCosine = (name.find('Cosine') >= 0)
         if timeInterval:
             assert len(values) == timeInterval.length()
             self.timeInterval = timeInterval
@@ -34,15 +34,26 @@
                 self.timeInterval = moving.TimeInterval()
         self.maxValue = maxValue
 
+    def __len__(self):
+        return len(self.values)
+
     def empty(self):
         return len(self.values) == 0
 
     def __getitem__(self, i):
+        'Returns ith value in time interval'
         if i in self.values.keys():
             return self.values[i]
         else:
             return None
 
+    def getIthValue(self, i):
+        sortedKeys = sorted(self.values.keys())
+        if 0<=i<len(sortedKeys):
+            return self.values[sortedKeys[i]]
+        else:
+            return None
+
     def __iter__(self):
         self.iterInstantNum = 0 # index in the interval or keys of the dict
         return self
@@ -53,13 +64,13 @@
             raise StopIteration
         else:
             self.iterInstantNum += 1
-            return self.values[self.values.keys()[self.iterInstantNum-1]]
+            return self.getIthValue(self.iterInstantNum-1)
 
     def getTimeInterval(self):
         return self.timeInterval
 
     def getValues(self):
-        return self.values.values()
+        return [self.__getitem__(t) for t in self.timeInterval]
 
     def getAngleValues(self):
         '''if the indicator is a function of an angle, 
@@ -67,7 +78,7 @@
         (no transformation otherwise)'''
         from numpy import arccos
         values = self.getValues()
-        if self.isCosine >= 0:
+        if self.isCosine:
             return [arccos(c) for c in values]
         else: 
             return values
@@ -84,13 +95,15 @@
             ylim(ymax = self.maxValue)
 	
     def valueSorted(self):
-	''' return the values after sort the keys in the indicator''' 
+	''' return the values after sort the keys in the indicator
+    This should probably not be used: to delete''' 
         values=[]
         keys = self.values.keys()
         keys.sort()
         for key in keys:
             values.append(self.values[key]) 
         return values
+
     @staticmethod
 	def getDLCSS(TemporalIndicator1,TemporalIndicator2, threshold, delta= np.inf , method='min' ):
 	''' compute the distance between two indicators using LCSS
@@ -104,25 +117,43 @@
 			DLCSS= 1- ((LCSS(l1,l2, threshold, delta, distance))/average)
 		return DLCSS
 		
+
+def computeDLCSS(indicator1, indicator2, threshold, delta = float('inf'), method= 'min'):
+    ''' compute the distance between two indicators using LCSS
+    two common methods are used: min or mean of the indicators length'''
+    from utils import LCSS
+
+    def distance(x, y): # lambda x,y:abs(x-y)
+        if x == None or y == None:
+            return float('inf')
+        else: 
+            return abs(x-y)
+
+    lcss = LCSS(indicator1.getValues(), indicator2.getValues(), threshold, distance, delta)
+    if method == 'min':
+        denominator = min(len(indicator1), len(indicator2))
+    elif method == 'mean':
+        denominator = float(len(indicator1) + len(indicator2))/2
+    else:
+        print('Unknown denominator method name')
+        denominator = 1.
+    return 1-float(lcss)/denominator
+
 class SeverityIndicator(TemporalIndicator):
     '''Class for severity indicators 
     field mostSevereIsMax is True 
     if the most severe value taken by the indicator is the maximum'''
 
-    def __init__(self, name, values, timeInterval=None, mostSevereIsMax=True, ignoredValue = None, maxValue = None): 
+    def __init__(self, name, values, timeInterval=None, mostSevereIsMax=True, maxValue = None): 
         TemporalIndicator.__init__(self, name, values, timeInterval, maxValue)
         self.mostSevereIsMax = mostSevereIsMax
-        self.ignoredValue = ignoredValue
 
-    def getMostSevereValue(self, minNInstants=1):
+    def getMostSevereValue(self, minNInstants=1): # TODO use scoreatpercentile
         from matplotlib.mlab import find
         from numpy.core.multiarray import array
         from numpy.core.fromnumeric import mean
         values = array(self.values.values())
-        if self.ignoredValue:
-            indices = find(values != self.ignoredValue)
-        else:
-            indices = range(len(values))
+        indices = range(len(values))
         if len(indices) >= minNInstants:
             values = sorted(values[indices], reverse = self.mostSevereIsMax) # inverted if most severe is max -> take the first values
             return mean(values[:minNInstants])
--- a/python/ml.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/ml.py	Thu Apr 11 22:46:33 2013 -0400
@@ -58,10 +58,9 @@
 
     return centroids
 
-
-def spectralClustering(similarityMatrix,k):	
-	''' Steps of Spectral Clustering'''
-	n= len(similarityMatrix)
+def spectralClustering(similarityMatrix, k, iter=20):
+	'''Spectral Clustering algorithm'''
+	n = len(similarityMatrix)
 	# create Laplacian matrix
 	rowsum = np.sum(similarityMatrix,axis=0)
 	D = np.diag(1 / np.sqrt(rowsum))
@@ -75,6 +74,6 @@
 	# k-means
 	from scipy.cluster.vq import kmeans, whiten, vq
 	features = whiten(features)
-	centroids,distortion = kmeans(features,k,iter=20) # default iter = 20
+	centroids,distortion = kmeans(features,k, iter)
 	code,distance = vq(features,centroids) # code starting from 0 (represent first cluster) to k-1 (last cluster)
 	return code,sigma	
--- a/python/moving.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/moving.py	Thu Apr 11 22:46:33 2013 -0400
@@ -10,10 +10,9 @@
 
 __metaclass__ = type
 
-class Interval:
-    '''Generic Interval'''
+class Interval(object):
+    '''Generic interval: a subset of real numbers (not iterable)'''
     def __init__(self, first=0, last=-1, revert = False):
-        'Warning, do not revert if last<first, it contradicts the definition of empty'
         if revert and last<first:
             self.first=last
             self.last=first
@@ -44,19 +43,21 @@
         return (self.first<=instant and self.last>=instant)
 
     def inside(self, interval2):
-        'indicates if the temporal interval of self is comprised in interval2'
+        '''Indicates if the temporal interval of self is comprised in interval2'''
         return (self.first >= interval2.first) and (self.last <= interval2.last)
 
-    def union(self, interval2):
+    @classmethod
+    def union(cls, interval1, interval2):
         '''Smallest interval comprising self and interval2'''
-        return Interval(min(self.first, interval2.first), max(self.last, interval2.last))
+        return cls(min(interval1.first, interval2.first), max(interval2.last, interval2.last))
         
-    def intersection(self, interval2):
+    @classmethod
+    def intersection(cls, interval1, interval2):
         '''Largest interval comprised in both self and interval2'''
-        return Interval(max(self.first, interval2.first), min(self.last, interval2.last))
+        return cls(max(interval1.first, interval2.first), min(interval1.last, interval2.last))
 
     def distance(self, interval2):
-        if not self.intersection(interval2).empty():
+        if not Interval.intersection(self, interval2).empty():
             return 0
         elif self.first > interval2.last:
             return self.first - interval2.last
@@ -70,16 +71,22 @@
     'returns the smallest interval containing all intervals'
     inter = intervals[0]
     for i in intervals[1:]:
-        inter = inter.union(i)
+        inter = Interval.union(inter, i)
     return inter
 
 
 class TimeInterval(Interval):
-    '''Temporal interval based on frame numbers (hence the modified length method)
-    may be modified directly by setting first and last'''
+    '''Temporal interval: set of instants at fixed time step, between first and last, included
+    
+    For example: based on frame numbers (hence the modified length method)
+    It may be modified directly by setting first and last'''
 
     def __init__(self, first=0, last=-1):
-        Interval.__init__(self, first, last, False)
+        super(TimeInterval, self).__init__(first, last, False)
+
+    @staticmethod
+    def fromInterval(inter):
+        return TimeInterval(inter.first, inter.last)
 
     def __getitem__(self, i):
         if not self.empty():
@@ -106,11 +113,11 @@
 #     '''
 # We will use the polygon class of Shapely
 
-class STObject:
-    '''Class for spatio-temporal object
-    i.e. with temporal and spatial existence 
+class STObject(object):
+    '''Class for spatio-temporal object, i.e. with temporal and spatial existence 
     (time interval and bounding polygon for positions (e.g. rectangle)).
-    It does not mean that the object is defined 
+
+    It may not mean that the object is defined 
     for all time instants within the time interval'''
 
     def __init__(self, num = None, timeInterval = None, boundingPolygon = None):
@@ -137,9 +144,9 @@
         return self.timeInterval.contains(t)
 
     def commonTimeInterval(self, obj2):
-        return self.getTimeInterval().intersection(obj2.getTimeInterval())
+        return TimeInterval.intersection(self.getTimeInterval(), obj2.getTimeInterval())
 
-class Point:
+class Point(object):
     def __init__(self, x, y):
         self.x = x
         self.y = y
@@ -168,7 +175,7 @@
         return self.x*self.x+self.y*self.y
 
     def norm2(self):
-        '2-norm distance (Euclidean distance)'
+        '''2-norm distance (Euclidean distance)'''
         return sqrt(self.norm2Squared())
 
     def norm1(self):
@@ -234,8 +241,8 @@
         from matplotlib.pyplot import scatter
         scatter([p.x for p in points],[p.y for p in points], c=color)
 
-class NormAngle:
-    'alternate encoding of a point, by its norm and orientation'
+class NormAngle(object):
+    '''Alternate encoding of a point, by its norm and orientation'''
 
     def __init__(self, norm, angle):
         self.norm = norm
@@ -273,7 +280,7 @@
     return predictedPosition, predictedSpeedTheta
 
 
-class FlowVector:
+class FlowVector(object):
     '''Class to represent 4-D flow vectors,
     ie a position and a velocity'''
     def __init__(self, position, velocity):
@@ -301,8 +308,7 @@
     from numpy import matrix
     from numpy.linalg import linalg, det
 
-    if (Interval(p1.x,p2.x, True).intersection(Interval(p3.x,p4.x, True)).empty()
-        or Interval(p1.y,p2.y, True).intersection(Interval(p3.y,p4.y, True)).empty()):
+    if (Interval.intersection(Interval(p1.x,p2.x,True), Interval(p3.x,p4.x,True)).empty()) or (Interval.intersection(Interval(p1.y,p2.y,True), Interval(p3.y,p4.y,True)).empty()):
         return None
     else:
         dp1 = p2-p1#[s1[0][1]-s1[0][0], s1[1][1]-s1[1][0]]
@@ -327,11 +333,10 @@
 
 # TODO: implement a better algorithm for intersections of sets of segments http://en.wikipedia.org/wiki/Line_segment_intersection
 
-class Trajectory:
-    '''Class for trajectories
-    i.e. a temporal sequence of positions
+class Trajectory(object):
+    '''Class for trajectories: temporal sequence of positions
 
-    the class is iterable.'''
+    The class is iterable'''
 
     def __init__(self, positions=None):
         if positions != None:
@@ -526,22 +531,21 @@
 userType2Num = utils.inverseEnumeration(userTypeNames)
 
 class MovingObject(STObject):
-    '''Class for moving objects
-    i.e. with a trajectory and a geometry (volume) (constant)
-    and a usertype (e.g. road user)
+    '''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)
     '''
 
     def __init__(self, num = None, timeInterval = None, positions = None, geometry = None, userType = None):
-        STObject.__init__(self, num, timeInterval)
+        super(MovingObject, self).__init__(num, timeInterval)
         self.positions = positions
         self.geometry = geometry
         self.userType = userType
         # compute bounding polygon from trajectory
-
+        
     def getObjectInTimeInterval(self, inter):
         '''Returns a new object extracted from self,
         restricted to time interval inter'''
-        intersection = inter.intersection(self.getTimeInterval())
+        intersection = TimeInterval.intersection(inter, self.getTimeInterval())
         if not intersection.empty():
             trajectoryInterval = TimeInterval(intersection.first-self.getFirstInstant(), intersection.last-self.getFirstInstant())
             obj = MovingObject(self.num, intersection, self.positions.getTrajectoryInInterval(trajectoryInterval), self.geometry, self.userType)
@@ -637,4 +641,3 @@
     unittest.TextTestRunner().run(suite)
     #doctest.testmod()
     #doctest.testfile("example.txt")
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/play-video.py	Thu Apr 11 22:46:33 2013 -0400
@@ -0,0 +1,22 @@
+#! /usr/bin/env python
+
+import sys,getopt
+import cvutils
+
+options, args = getopt.getopt(sys.argv[1:], 'hi:f:',['help', 'fps=']) 
+options = dict(options)
+print options
+
+if '--help' in options.keys() or '-h' in options.keys() or len(sys.argv) == 1:
+    print('Usage: '+sys.argv[0]+' --help|-h -i video-filename [-f first_frame] [--fps frame_rate]')
+    sys.exit()
+
+firstFrameNum = 0
+if '-f' in options.keys():
+    firstFrameNum = int(options['-f'])
+
+frameRate = -1
+if '--fps' in options.keys():
+    frameRate = int(options['--fps'])
+
+cvutils.playVideo(options['-i'], firstFrameNum, frameRate)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/poly_utils.py	Thu Apr 11 22:46:33 2013 -0400
@@ -0,0 +1,49 @@
+#! /usr/bin/env python
+'''Various utilities to load data saved by the POLY new output(s)'''
+import sys
+import utils
+from moving import  TimeInterval
+import numpy as np
+
+__metaclass__ = type
+
+# inputs variables	
+#dirname= 'G:/0-phdstart/Code/trial/indicatorsNew/'
+#extension= '-indicatorsNew.csv'
+#indicatorsNames= {1:'Distance',2:'Cosine',3:'collision Course Angle',4:'Velocity Cosine',5:'Velocity Angle',6:'Speed Differential',7:'Collision Probability',8:'Severity Index',9:'TTC'}
+''' min Distance case'''
+dirname= 'G:/0-phdstart/Code/trial/minDistanceIndicator/'
+extension= '-minDistanceInd.csv'
+indicatorsNames= {1:'minDistance'}
+
+def loadNewInteractions(videoFilename,interactionType, roaduserNum1,roaduserNum2, selectedIndicators=[]):
+    '''Loads interactions from the POLY traffic event format'''
+    from events import Interaction 
+    from indicators import SeverityIndicator
+    #filename= dirname + videoFilename + extension
+    filename= dirname + interactionType+ '-' + videoFilename + extension # case of min distance todo: change the saving format to be matched with all outputs
+    file = utils.openCheck(filename)
+    if (not file):
+        return []
+    interactions = []
+    interactionNum = 0
+    data= np.loadtxt(filename)
+    indicatorFrameNums= data[:,0]
+    inter = Interaction(interactionNum, TimeInterval(indicatorFrameNums[0],indicatorFrameNums[-1]), roaduserNum1, roaduserNum2) 
+    inter.addVideoFilename(videoFilename)
+    inter.addInteractionType(interactionType)
+    for key in indicatorsNames.keys():
+        values= {}
+        for i,t in enumerate(indicatorFrameNums):
+            values[t] = data[i,key]
+        inter.addIndicator(SeverityIndicator(indicatorsNames[key], values))
+    if selectedIndicators !=[]:
+        values= {}
+        for i,t in enumerate(indicatorFrameNums):
+            values[t] = [data[i,index] for index in selectedIndicators]
+        inter.addIndicator(SeverityIndicator('selectedIndicators', values))	
+		
+    interactions.append(inter)
+    file.close()
+    return interactions
+
--- a/python/prediction.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/prediction.py	Thu Apr 11 22:46:33 2013 -0400
@@ -15,8 +15,8 @@
         self.probability = 0.
         self.predictedPositions = {}
         self.predictedSpeedOrientations = {}
-        self.collisionPoints = {}
-        self.crossingZones = {}
+        #self.collisionPoints = {}
+        #self.crossingZones = {}
 
     def predictPosition(self, nTimeSteps):
         if nTimeSteps > 0 and not nTimeSteps in self.predictedPositions.keys():
@@ -167,16 +167,20 @@
         self.probability = probability
         self.indicator = indicator
 
+    def __str__(self):
+        return '{0} {1} {2} {3}'.format(self.x, self.y, self.probability, self.indicator)
+
     @staticmethod
-    def save(out, points, objNum1, objNum2, instant):
+    def save(out, points, predictionInstant, objNum1, objNum2):
         for p in points:
-            out.write('{0} {1} {2} {3} {4} {5} {6}\n'.format(objNum1, objNum2, instant, p.x, p.y, p.probability, p.indicator))
+            out.write('{0} {1} {2} {3}\n'.format(objNum1, objNum2, predictionInstant, p))
 
 def computeExpectedIndicator(points):
     from numpy import sum
     return sum([p.indicator*p.probability for p in points])/sum([p.probability for p in points])
 
 def computeCollisionTime(predictedTrajectory1, predictedTrajectory2, collisionDistanceThreshold, timeHorizon):
+    '''Computes the first instant at which two predicted trajectories are within some distance threshold'''
     t = 1
     p1 = predictedTrajectory1.predictPosition(t)
     p2 = predictedTrajectory2.predictPosition(t)
@@ -186,12 +190,12 @@
         t += 1
     return t, p1, p2
 
-def computeCrossingsCollisionsAtInstant(i, obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, debug = False):
+def computeCrossingsCollisionsAtInstant(currentInstant, obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False):
     '''returns the lists of collision points and crossing zones
     
     Check: Predicting all the points together, as if they represent the whole vehicle'''
-    predictedTrajectories1 = predictionParameters.generatePredictedTrajectories(obj1, i)
-    predictedTrajectories2 = predictionParameters.generatePredictedTrajectories(obj2, i)
+    predictedTrajectories1 = predictionParameters.generatePredictedTrajectories(obj1, currentInstant)
+    predictedTrajectories2 = predictionParameters.generatePredictedTrajectories(obj2, currentInstant)
 
     collisionPoints = []
     crossingZones = []
@@ -201,7 +205,7 @@
             
             if t <= timeHorizon:
                 collisionPoints.append(SafetyPoint((p1+p2).multiply(0.5), et1.probability*et2.probability, t))
-            else: # check if there is a crossing zone
+            elif computeCZ: # check if there is a crossing zone
                 # TODO? zone should be around the points at which the traj are the closest
                 # look for CZ at different times, otherwise it would be a collision
                 # an approximation would be to look for close points at different times, ie the complementary of collision points
@@ -235,7 +239,8 @@
 
     return collisionPoints, crossingZones
     
-def computeCrossingsCollisions(obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, outCP, outCZ, debug = False, timeInterval = None):
+def computeCrossingsCollisions(obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False, timeInterval = None):
+    '''Computes all crossing and collision points at each common instant for two road users. '''
     collisionPoints={}
     crossingZones={}
     if timeInterval:
@@ -243,14 +248,13 @@
     else:
         commonTimeInterval = obj1.commonTimeInterval(obj2)
     for i in list(commonTimeInterval)[:-1]: # do not look at the 1 last position/velocities, often with errors
-        print(obj1.num, obj2.num, i)
-        collisionPoints[i], crossingZones[i] = computeCrossingsCollisionsAtInstant(i, obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, debug)
-        SafetyPoint.save(outCP, collisionPoints[i], obj1.num, obj2.num, i)
-        SafetyPoint.save(outCZ, crossingZones[i], obj1.num, obj2.num, i)
+        collisionPoints[i], crossingZones[i] = computeCrossingsCollisionsAtInstant(i, obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ, debug)
 
     return collisionPoints, crossingZones
  
-def computeCollisionProbability(obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, out, debug = False, timeInterval = None):
+def computeCollisionProbability(obj1, obj2, predictionParameters, collisionDistanceThreshold, timeHorizon, debug = False, timeInterval = None):
+    '''Computes only collision probabilities
+    Returns for each instant the collision probability and number of samples drawn'''
     collisionProbabilities = {}
     if timeInterval:
         commonTimeInterval = timeInterval
@@ -268,8 +272,7 @@
                     nCollisions += 1
         # take into account probabilities ??
         nSamples = float(len(predictedTrajectories1)*len(predictedTrajectories2))
-        collisionProbabilities[i] = float(nCollisions)/nSamples
-        out.write('{0} {1} {2} {3} {4}\n'.format(obj1.num, obj2.num, nSamples, i, collisionProbabilities[i]))
+        collisionProbabilities[i] = [nSamples, float(nCollisions)/nSamples]
 
         if debug:
             from matplotlib.pyplot import figure, axis, title
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/requirements.txt	Thu Apr 11 22:46:33 2013 -0400
@@ -0,0 +1,11 @@
+matplotlib
+numpy
+
+The following libraries are necessary for (sometimes very) specific classes/functions.
+
+CV functionalities (cvutils.py): opencv
+Image functionalities (cvutils.py): Python Image Library
+
+Machine learning (ml.py): scipy
+
+Moving object geometry (currently commented) (moving.py) and plotting shapely polygons (utils.py): shapely
--- a/python/tests/indicators.txt	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/tests/indicators.txt	Thu Apr 11 22:46:33 2013 -0400
@@ -4,17 +4,20 @@
 >>> indic1 = TemporalIndicator('bla', [0,3,-4], TimeInterval(4,6))
 >>> indic1.empty()
 False
->>> indic1[5]
+>>> indic1.getIthValue(1)
 3
->>> indic1[3]
+>>> indic1.getIthValue(3)
+>>> indic1[6]
+-4
+>>> indic1[7]
 >>> [v for v in indic1]
 [0, 3, -4]
 >>> indic1 = TemporalIndicator('bla', {2:0,4:3,5:-5})
->>> indic1[4]
+>>> indic1.getIthValue(1)
 3
->>> indic1[3]
->>> [v for v in indic1]
-[0, 3, -5]
+>>> indic1.getIthValue(3)
+>>> indic1[2]
+0
 
 >>> t1 = Trajectory([[0.5,1.5,2.5],[0.5,3.5,6.5]])
 >>> indicatorMap([1,2,3], t1, 1)
--- a/python/tests/prediction.txt	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/tests/prediction.txt	Thu Apr 11 22:46:33 2013 -0400
@@ -23,3 +23,8 @@
 >>> from numpy import max
 >>> max(et.getPredictedSpeeds()) <= 2.
 True
+
+>>> p = moving.Point(3,4)
+>>> sp = prediction.SafetyPoint(p, 0.1, 0)
+>>> print(sp)
+3 4 0.1 0
--- a/python/tests/utils.txt	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/tests/utils.txt	Thu Apr 11 22:46:33 2013 -0400
@@ -40,3 +40,14 @@
 71.5...
 >>> values[-1]
 6.0
+
+>>> stepPlot([3, 5, 7, 8], 1, 10, 0)
+([1, 3, 3, 5, 5, 7, 7, 8, 8, 10], [0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
+
+>>> LCSS(range(5), range(5), 0.1, lambda x,y:abs(x-y))
+5
+>>> LCSS(range(1,5), range(5), 0.1, lambda x,y:abs(x-y))
+4
+>>> LCSS(range(5,10), range(5), 0.1, lambda x,y:abs(x-y))
+0
+
--- a/python/traffic_engineering.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/traffic_engineering.py	Thu Apr 11 22:46:33 2013 -0400
@@ -3,6 +3,8 @@
 
 from math import ceil
 
+import prediction
+
 __metaclass__ = type
 
 
@@ -11,21 +13,34 @@
 #########################
 
 class Vehicle:
-    'Generic vehicle class'
-    def __init__(self, position = 0, speed = 0, acceleration = 0, prt = 2.5, leader = None, log=True):
-        self.position = position
-        self.speed = speed
-        self.acceleration = acceleration
+    '''Generic vehicle class
+    1D coordinates for now'''
+    class PredictedTrajectory1D(prediction.PredictedTrajectory):
+        def __init__(self, initialPosition, initialSpeed, control, maxSpeed = None):
+            self.control = control
+            self.maxSpeed = maxSpeed
+            self.probability = None
+            self.predictedPositions = {0: moving.Point(initialPosition)}
+            self.predictedSpeedOrientations = {0: moving.NormAngle(initialSpeed, 0)}
+            
+        def setAcceleration(self, acceleration):
+            self.control = moving.NormAngle(acceleration, 0)
+            
+        def getControl(self):
+            return self.control
+
+
+    def __init__(self, initialPosition = 0, initialSpeed = 0, acceleration = 0, prt = 2.5, leader = None):
+        self.positions = PredictedTrajectory1D(initialPosition, initialSpeed)
+
         self.prt = prt
         self.leader = leader
-        self.log = log
-        if log:
-            self.positions = [position]
-            self.speeds = [speed]
-            self.accelerations = [acceleration]
-        # todo add microModel
+        # todo add microModel (Treiber)
 
-    def updatePosition(self, dt):
+    def setAcceleration(self, acceleration):
+        self.positions.setAcceleration(acceleration)
+
+    def updatePosition(self, dt): # knowledge of time outside of vehicle ??
         speed = self.speed
         self.speed += self.acceleration*dt
         self.position += speed*dt
@@ -146,6 +161,7 @@
             self.equivalents = equivalents
             self.nLanes = nLanes # unused
         else:
+            print('Proportions do not sum to 1')
             pass
 
     def getPCUVolume(self):
--- a/python/ubc_utils.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/ubc_utils.py	Thu Apr 11 22:46:33 2013 -0400
@@ -170,7 +170,7 @@
 
 def loadInteractions(filename, nInteractions = -1):
     'Loads interactions from the old UBC traffic event format'
-    from event import Interaction 
+    from events import Interaction 
     from indicators import SeverityIndicator
     file = utils.openCheck(filename)
     if (not file):
@@ -184,12 +184,12 @@
         inter = Interaction(interactionNum, TimeInterval(parsedLine[1],parsedLine[2]), parsedLine[3], parsedLine[4], categoryNum = parsedLine[5])
         
         indicatorFrameNums = [int(n) for n in lines[1].split(' ')]
-        inter.indicators = []
         for indicatorNum,line in enumerate(lines[2:]):
             values = {}
             for i,v in enumerate([float(n) for n in line.split(' ')]):
-                values[indicatorFrameNums[i]] = v
-            inter.indicators.append(SeverityIndicator(severityIndicatorNames[indicatorNum], values, None, mostSevereIsMax[indicatorNum], ignoredValue[indicatorNum]))
+                if not ignoredValue[indicatorNum] or v != ignoredValue[indicatorNum]:
+                    values[indicatorFrameNums[i]] = v
+            inter.addIndicator(SeverityIndicator(severityIndicatorNames[indicatorNum], values, None, mostSevereIsMax[indicatorNum]))
 
         interactions.append(inter)
         interactionNum+=1
--- a/python/utils.py	Tue Dec 25 02:24:21 2012 -0500
+++ b/python/utils.py	Thu Apr 11 22:46:33 2013 -0400
@@ -58,6 +58,15 @@
 # simple statistics
 #########################
 
+def confidenceInterval(mean, stdev, nSamples, percentConfidence, printLatex = False):
+    from math import sqrt
+    from scipy.stats.distributions import norm
+    k = round(norm.ppf(0.5+percentConfidence/200., 0, 1)*100)/100. # 1.-(100-percentConfidence)/200.
+    e = k*stdev/sqrt(nSamples)
+    if printLatex:
+        print('${0} \pm {1}\\frac{{{2}}}{{\sqrt{{{3}}}}}$'.format(mean, k, stdev, nSamples))
+    return mean-e, mean+e
+
 def computeChi2(expected, observed):
     '''Returns the Chi2 statistics'''
     result = 0.
@@ -165,22 +174,20 @@
 # maths section
 #########################
 
-def LCSS(l1, l2, threshold, delta, distance):
+def LCSS(l1, l2, threshold, distance, delta = float('inf')):
     '''returns the longest common subsequence similarity
-    based on the threshold on distance between two elements of lists l1, l2.
-	looks for points that are sampled within a delta time window, can put 'inf' value to cancl this condition'''
+    based on the threshold on distance between two elements of lists l1, l2
+    '''
     from numpy import zeros, int as npint
     m = len(l1)
     n = len(l2)
     similarity = zeros((m+1,n+1), dtype = npint)
     for i in xrange(1,m+1):
-        for j in xrange(1,n+1):
-			from math import fabs
-			while fabs(i-j)<= delta:
-                if distance(l1[i-1], l2[j-1])<threshold:
-                    similarity[i][j] = similarity[i-1][j-1]+1
-                else:
-                    similarity[i][j] = max(similarity[i-1][j], similarity[i][j-1])
+        for j in xrange(max(1,i-delta),min(n+1,i+delta)):
+            if distance(l1[i-1], l2[j-1])<=threshold:
+                similarity[i][j] = similarity[i-1][j-1]+1
+            else:
+                similarity[i][j] = max(similarity[i-1][j], similarity[i][j-1])
     return similarity[-1][-1]
 
 def framesToTime(nFrames, frameRate, initialTime = (0.,0.,0.)):
@@ -247,6 +254,20 @@
 # plotting section
 #########################
 
+def stepPlot(X, firstX, lastX, initialCount = 0):
+    '''for each value in x, increment by one the initial count
+    returns the lists that can be plotted 
+    to obtain a step plot increasing by one for each value in x, from first to last value'''
+    
+    sortedX = []
+    counts = [initialCount]
+    for x in sorted(X):
+        sortedX += [x,x]
+        counts.append(counts[-1])
+        counts.append(counts[-1]+1)
+    counts.append(counts[-1])
+    return [firstX]+sortedX+[lastX], counts
+
 class PlottingPropertyValues:
     def __init__(self, values):
         self.values = values
@@ -309,6 +330,22 @@
         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)