changeset 805:180b6b0231c0

added saving/loading points of interests
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 09 Jun 2016 15:36:21 -0400
parents c5f98916297e
children c6f497291fd8 4957e32bb659 bb0fad90cc31
files python/metadata.py python/ml.py python/storage.py python/tests/storage.txt scripts/delete-tables.py scripts/learn-poi.py
diffstat 6 files changed, 129 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/python/metadata.py	Tue May 31 17:07:23 2016 -0400
+++ b/python/metadata.py	Thu Jun 09 15:36:21 2016 -0400
@@ -18,12 +18,16 @@
     description = Column(String) # longer names, eg intersection of road1 and road2
     xcoordinate = Column(Float)  # ideally moving.Point, but needs to be 
     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
     
-    def __init__(self, name, description = "", xcoordinate = None, ycoordinate = None):
+    def __init__(self, name, description = "", xcoordinate = None, ycoordinate = None, mapImageFilename = None, nUnitsPerPixel = 1.):
         self.name = name
         self.description = description
         self.xcoordinate = xcoordinate
         self.ycoordinate = ycoordinate
+        self.mapImageFilename = mapImageFilename
+        self.nUnitsPerPixel = nUnitsPerPixel
 
     def getFilename(self):
         return self.name
--- a/python/ml.py	Tue May 31 17:07:23 2016 -0400
+++ b/python/ml.py	Thu Jun 09 15:36:21 2016 -0400
@@ -209,16 +209,16 @@
     return clusterSizes
 
 # Gaussian Mixture Models
-def plotGMMClusters(model, dataset = None, fig = None, colors = utils.colors, nPixelsPerUnit = 1., alpha = 0.3):
+def plotGMMClusters(model, dataset = None, fig = None, colors = utils.colors, nUnitsPerPixel = 1., alpha = 0.3):
     '''plot the ellipse corresponding to the Gaussians
     and the predicted classes of the instances in the dataset'''
     if fig is None:
         fig = plt.figure()
     labels = model.predict(dataset)
-    tmpDataset = nPixelsPerUnit*dataset
+    tmpDataset = dataset/nUnitsPerPixel
     for i in xrange(model.n_components):
-        mean = nPixelsPerUnit*model.means_[i]
-        covariance = nPixelsPerUnit*model.covars_[i]
+        mean = model.means_[i]/nUnitsPerPixel
+        covariance = model.covars_[i]/nUnitsPerPixel
         if dataset is not None:
             plt.scatter(tmpDataset[labels == i, 0], tmpDataset[labels == i, 1], .8, color=colors[i])
         plt.annotate(str(i), xy=(mean[0]+1, mean[1]+1))
@@ -232,3 +232,4 @@
         ell.set_clip_box(fig.bbox)
         ell.set_alpha(alpha)
         fig.axes[0].add_artist(ell)
+    return labels
--- a/python/storage.py	Tue May 31 17:07:23 2016 -0400
+++ b/python/storage.py	Thu Jun 09 15:36:21 2016 -0400
@@ -384,6 +384,8 @@
             dropTables(connection, ['interactions', 'indicators'])
         elif dataType == 'bb':
             dropTables(connection, ['bounding_boxes'])
+        elif dataType == 'pois':
+            dropTables(connection, ['gaussians2d'])
         else:
             print('Unknown data type {} to delete from database'.format(dataType))
         connection.close()
@@ -506,6 +508,71 @@
     return boundingBoxes
 
 #########################
+# saving and loading for scene interpretation
+#########################
+
+def savePOIs(filename, gmm, gmmType, gmmId):
+    '''Saves a Gaussian mixture model (of class sklearn.mixture.GMM)
+    gmmType is a type of GMM, learnt either from beginnings or ends of trajectories'''
+    connection = sqlite3.connect(filename)
+    cursor = connection.cursor()
+    if gmmType not in ['beginning', 'end']:
+        print('Unknown POI type {}. Exiting'.format(gmmType))
+        import sys
+        sys.exit()
+    try:
+        cursor.execute('CREATE TABLE IF NOT EXISTS gaussians2d (id INTEGER, type VARCHAR, x_center REAL, y_center REAL, covar00 REAL, covar01 REAL, covar10 REAL, covar11 REAL, covariance_type VARCHAR, weight, mixture_id INTEGER, PRIMARY KEY(id, mixture_id))')
+        for i in xrange(gmm.n_components):
+            cursor.execute('INSERT INTO gaussians2d VALUES({}, \'{}\', {}, {}, {}, {}, {}, {}, \'{}\', {}, {})'.format(i, gmmType, gmm.means_[i][0], gmm.means_[i][1], gmm.covars_[i][0,0], gmm.covars_[i][0,1], gmm.covars_[i][1,0], gmm.covars_[i][1,1], gmm.covariance_type, gmm.weights_[i], gmmId))
+        connection.commit()
+    except sqlite3.OperationalError as error:
+        printDBError(error)
+    connection.close()
+
+def loadPOIs(filename):
+    'Loads all 2D Gaussians in the database'
+    from sklearn import mixture # todo if not avalaible, load data in duck-typed class with same fields
+    connection = sqlite3.connect(filename)
+    cursor = connection.cursor()
+    pois = []
+    try:
+        cursor.execute('SELECT * from gaussians2d')
+        gmmId = None
+        gmm = []
+        for row in cursor:
+            if gmmId is None or row[10] != gmmId:
+                if len(gmm) > 0:
+                    tmp = mixture.GMM(len(gmm), covarianceType)
+                    tmp.means_ = array([gaussian['mean'] for gaussian in gmm])
+                    tmp.covars_ = array([gaussian['covar'] for gaussian in gmm])
+                    tmp.weights_ = array([gaussian['weight'] for gaussian in gmm])
+                    tmp.gmmTypes = [gaussian['type'] for gaussian in gmm]
+                    pois.append(tmp)
+                gaussian = {'type': row[1],
+                            'mean': row[2:4],
+                            'covar': array(row[4:8]).reshape(2,2),
+                            'weight': row[9]}
+                gmm = [gaussian]
+                covarianceType = row[8]
+                gmmId = row[10]
+            else:
+                gmm.append({'type': row[1],
+                            'mean': row[2:4],
+                            'covar': array(row[4:8]).reshape(2,2),
+                            'weight': row[9]})
+        if len(gmm) > 0:
+            tmp = mixture.GMM(len(gmm), covarianceType)
+            tmp.means_ = array([gaussian['mean'] for gaussian in gmm])
+            tmp.covars_ = array([gaussian['covar'] for gaussian in gmm])
+            tmp.weights_ = array([gaussian['weight'] for gaussian in gmm])
+            tmp.gmmTypes = [gaussian['type'] for gaussian in gmm]
+            pois.append(tmp)
+    except sqlite3.OperationalError as error:
+        printDBError(error)
+    connection.close()
+    return pois
+    
+#########################
 # saving and loading for scene interpretation (Mohamed Gomaa Mohamed's PhD)
 #########################
 
--- a/python/tests/storage.txt	Tue May 31 17:07:23 2016 -0400
+++ b/python/tests/storage.txt	Thu Jun 09 15:36:21 2016 -0400
@@ -75,3 +75,18 @@
 '# asdlfjasdlkj0'
 >>> readline(strio, '%#')
 'sadlkfjsdlakjf'
+
+>>> from sklearn.mixture import GMM
+>>> from numpy.random import random_sample
+>>> nPoints = 50
+>>> points = random_sample(nPoints*2).reshape(nPoints,2)
+>>> gmm = GMM(4, covariance_type = 'full')
+>>> tmp = gmm.fit(points)
+>>> id = 0
+>>> savePOIs('pois-tmp.sqlite', gmm, 'end', id)
+>>> reloadedGmm = loadPOIs('pois-tmp.sqlite')
+>>> sum(gmm.predict(points) == reloadedGmm[id].predict(points)) == nPoints
+True
+>>> reloadedGmm[id].gmmTypes[0] == 'end'
+True
+>>> remove('pois-tmp.sqlite')
--- a/scripts/delete-tables.py	Tue May 31 17:07:23 2016 -0400
+++ b/scripts/delete-tables.py	Thu Jun 09 15:36:21 2016 -0400
@@ -8,7 +8,7 @@
 parser = argparse.ArgumentParser(description='The program deletes (drops) the tables in the database before saving new results (for objects, tables object_features and objects are dropped; for interactions, the tables interactions and indicators are dropped')
 #parser.add_argument('configFilename', help = 'name of the configuration file')
 parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the Sqlite database', required = True)
-parser.add_argument('-t', dest = 'dataType', help = 'type of the data to remove', required = True, choices = ['object','interaction', 'bb'])
+parser.add_argument('-t', dest = 'dataType', help = 'type of the data to remove', required = True, choices = ['object','interaction', 'bb', 'pois'])
 args = parser.parse_args()
 
 storage.deleteFromSqlite(args.databaseFilename, args.dataType)
--- a/scripts/learn-poi.py	Tue May 31 17:07:23 2016 -0400
+++ b/scripts/learn-poi.py	Thu Jun 09 15:36:21 2016 -0400
@@ -11,10 +11,11 @@
 parser = argparse.ArgumentParser(description='The program learns and displays Gaussians fit to beginnings and ends of object trajectories (based on Mohamed Gomaa Mohamed 2015 PhD). TODO: save the data')
 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 = ['feature', 'object'], default = 'object')
-parser.add_argument('-n', dest = 'nClusters', help = 'number of point clusters', required = True, type = int)
+parser.add_argument('-norigins', dest = 'nOriginClusters', help = 'number of clusters for trajectory origins', required = True, type = int)
+parser.add_argument('-ndestinations', dest = 'nDestinationClusters', help = 'number of clusters for trajectory destinations (=norigins if not provided)', type = int)
 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 = 'pixelsPerUnit', help = 'number pixels per unit of distance', type = float, default = 1.)
+parser.add_argument('-u', dest = 'unitsPerPixel', help = 'number of units of distance per pixel', type = float, default = 1.)
 
 args = parser.parse_args()
 
@@ -29,25 +30,37 @@
 beginnings = np.array(beginnings)
 ends = np.array(ends)
 
-gmm = mixture.GMM(n_components=args.nClusters, covariance_type = args.covarianceType)
-beginningModel=gmm.fit(beginnings)
-gmm = mixture.GMM(n_components=args.nClusters, covariance_type = args.covarianceType)
-endModel=gmm.fit(ends)
+nDestinationClusters = args.nDestinationClusters
+if args.nDestinationClusters is None:
+    nDestinationClusters = args.nOriginClusters
 
-fig = plt.figure()
-if args.worldImageFilename is not None and args.pixelsPerUnit is not None:
-    img = plt.imread(args.worldImageFilename)
-    plt.imshow(img)
-ml.plotGMMClusters(beginningModel, beginnings, fig, nPixelsPerUnit = args.pixelsPerUnit)
-plt.axis('equal')
-plt.title('Origins')
-print('Origin Clusters:\n{}'.format(ml.computeClusterSizes(beginningModel.predict(beginnings), range(args.nClusters))))
-
-fig = plt.figure()
-if args.worldImageFilename is not None and args.pixelsPerUnit is not None:
-    img = plt.imread(args.worldImageFilename)
-    plt.imshow(img)
-ml.plotGMMClusters(endModel, ends, fig, nPixelsPerUnit = args.pixelsPerUnit)
-plt.axis('equal')
-plt.title('Destinations')
-print('Destination Clusters:\n{}'.format(ml.computeClusterSizes(endModel.predict(ends), range(args.nClusters))))
+gmmId=0
+for nClusters, points, gmmType in zip([args.nOriginClusters, nDestinationClusters],
+                                   [beginnings, ends],
+                                   ['beginning', 'end']):
+    # estimation
+    gmm = mixture.GMM(n_components=nClusters, covariance_type = args.covarianceType)
+    model=gmm.fit(beginnings)
+    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))))
+    # save
+    storage.savePOIs(args.databaseFilename, model, gmmType, gmmId)
+    gmmId += 1
+                     
+# fig = plt.figure()
+# if args.worldImageFilename is not None and args.pixelsPerUnit is not None:
+#     img = plt.imread(args.worldImageFilename)
+#     plt.imshow(img)
+# ml.plotGMMClusters(, , fig, nPixelsPerUnit = args.pixelsPerUnit)
+# plt.axis('equal')
+# plt.title()
+# print('Destination Clusters:\n{}'.format(ml.computeClusterSizes(endModel.predict(ends), range(args.nClusters))))