Mercurial Hosting > traffic-intelligence
changeset 1035:933588568bec
major update to learn motion pattern, see program description
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Wed, 20 Jun 2018 16:48:20 -0400 |
parents | 4069d8545922 |
children | 0d7e5e290ea3 |
files | scripts/learn-motion-patterns.py trafficintelligence/moving.py trafficintelligence/storage.py |
diffstat | 3 files changed, 56 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/learn-motion-patterns.py Wed Jun 20 12:04:22 2018 -0400 +++ b/scripts/learn-motion-patterns.py Wed Jun 20 16:48:20 2018 -0400 @@ -3,15 +3,16 @@ import sys, argparse import numpy as np +import matplotlib.pyplot as plt from trafficintelligence import ml, utils, storage, moving -parser = argparse.ArgumentParser(description='The program learns prototypes for the motion patterns') #, epilog = '' +parser = argparse.ArgumentParser(description='''The program clusters trajectories, each cluster being represented by a trajectory. It can either work on the same dataset (database) or different ones, but only does learning or assignment at a time to avoid issues (the minimum cluster size argument is not used for now as it may change prototypes when assigning other trajectories)''') #, epilog = '' #parser.add_argument('--cfg', dest = 'configFilename', help = 'name of the configuration file') parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the Sqlite database file', required = True) parser.add_argument('-o', dest = 'outputPrototypeDatabaseFilename', help = 'name of the Sqlite database file to save prototypes') parser.add_argument('-i', dest = 'inputPrototypeDatabaseFilename', help = 'name of the Sqlite database file for prototypes to start the algorithm with') -parser.add_argument('-t', dest = 'trajectoryType', help = 'type of trajectories to learn from', choices = ['objectfeatures', 'feature', 'object'], default = 'objectfeatures') +parser.add_argument('-t', dest = 'trajectoryType', help = 'type of trajectories to learn from', choices = ['objectfeature', 'feature', 'object'], default = 'objectfeatures') parser.add_argument('--max-nobjectfeatures', dest = 'maxNObjectFeatures', help = 'maximum number of features per object to load', type = int, default = 1) parser.add_argument('-n', dest = 'nTrajectories', help = 'number of the object or feature trajectories to load', type = int, default = None) parser.add_argument('-e', dest = 'epsilon', help = 'distance for the similarity of trajectory points', type = float, required = True) @@ -24,25 +25,22 @@ parser.add_argument('--subsample', dest = 'positionSubsamplingRate', help = 'rate of position subsampling (1 every n positions)', type = int) parser.add_argument('--display', dest = 'display', help = 'display trajectories', action = 'store_true') parser.add_argument('--save-similarities', dest = 'saveSimilarities', help = 'save computed similarities (in addition to prototypes)', action = 'store_true') -parser.add_argument('--save-matches', dest = 'saveMatches', help = 'saves the assignments of the objects (not for features) to the prototypes', action = 'store_true') +parser.add_argument('--save-assignments', dest = 'saveAssignments', help = 'saves the assignments of the objects to the prototypes', action = 'store_true') parser.add_argument('--assign', dest = 'assign', help = 'assigns the objects to the prototypes and saves the assignments', action = 'store_true') args = parser.parse_args() # use cases # 1. learn proto from one file, save in same or another -# 2. load proto, load objects, update proto, save proto -# 3. assign objects from one db to proto -# 4. load objects from several files, save in another -> see metadata: site with view and times -# 5. keep prototypes, with positions/velocities, in separate db (keep link to original data through filename, type and index) +# 2. load proto, load objects (from same or other db), update proto matchings, save proto +# TODO 3. on same dataset, learn and assign trajectories (could be done with min cluster size) +# TODO? 4. when assigning, allow min cluster size only to avoid assigning to small clusters (but prototypes are not removed even if in small clusters, can be done after assignment with nmatchings) # TODO add possibility to cluster with velocities -# TODO add possibilite to load all trajectories and use minclustersize -# save the objects that match the prototypes -# write an assignment function for objects +# TODO add possibility to load all trajectories and use minclustersize # load trajectories to cluster or assign -if args.trajectoryType == 'objectfeatures': +if args.trajectoryType == 'objectfeature': trajectoryType = 'feature' objectFeatureNumbers = storage.loadObjectFeatureFrameNumbers(args.databaseFilename, objectNumbers = args.nTrajectories) featureNumbers = [] @@ -88,9 +86,7 @@ # print('Not assigning with non-zero minimum cluster size and initial prototypes (would remove initial prototypes based on other trajectories') # else: # prototypeIndices, labels = ml.assignToPrototypeClusters(trajectories, prototypeIndices, similarities, args.minSimilarity, similarityFunc) - prototypeIndices, labels = ml.assignToPrototypeClusters(trajectories, prototypeIndices, similarities, args.minSimilarity, similarityFunc) - clusterSizes = ml.computeClusterSizes(labels, prototypeIndices, -1) - print(clusterSizes) + assignedPrototypeIndices, labels = ml.assignToPrototypeClusters(trajectories, prototypeIndices, similarities, args.minSimilarity, similarityFunc) if args.learn and not args.assign: prototypes = [] @@ -107,39 +103,52 @@ if args.inputPrototypeDatabaseFilename == args.outputPrototypeDatabaseFilename: storage.deleteFromSqlite(args.outputPrototypeDatabaseFilename, 'prototype') storage.savePrototypesToSqlite(outputPrototypeDatabaseFilename, prototypes) + if args.display: + plt.figure() + for p in prototypes: + p.getMovingObject().plot() + plt.axis('equal') + plt.show() -if not args.learn and args.assign: # no new prototypes # not save assignments of past prototypes if removes with minClusterSize - prototypes = [] +if not args.learn and args.assign: # no modification to prototypes, can work with initialPrototypes + clusterSizes = ml.computeClusterSizes(labels, prototypeIndices, -1) for i in prototypeIndices: nMatchings = clusterSizes[i]-1 if initialPrototypes[i].nMatchings is None: initialPrototypes[i].nMatchings = nMatchings else: initialPrototypes[i].nMatchings += nMatchings - prototypes.append(initialPrototypes[i]) if args.outputPrototypeDatabaseFilename is None: outputPrototypeDatabaseFilename = args.databaseFilename else: outputPrototypeDatabaseFilename = args.outputPrototypeDatabaseFilename - storage.setPrototypeMatchingsInSqlite(outputPrototypeDatabaseFilename, prototypes) - - labelsToProtoIndices = {protoId: i for i, protoId in enumerate(prototypeIndices)} - if args.saveMatches: - storage.savePrototypeAssignmentsToSqlite(args.databaseFilename, objects, trajectoryType, [labelsToProtoIndices[l] for l in labels], prototypes) + storage.setPrototypeMatchingsInSqlite(outputPrototypeDatabaseFilename, initialPrototypes) + if args.saveAssignments: + if args.trajectoryType == 'objectfeature': # consider that the object is assigned through its longest features + objectNumbers = [] + objectLabels = [] + for objNum, objFeatureNumbers in objectFeatureNumbers.items(): + objLabels = [] + for i, o in enumerate(objects): + if o.getNum() in objFeatureNumbers: + objLabels.append(labels[i+len(initialPrototypes)]) + objectLabels.append(utils.mostCommon(objLabels)) + objectNumbers.append(objNum) + storage.savePrototypeAssignmentsToSqlite(args.databaseFilename, objectNumbers, 'object', objectLabels, initialPrototypes) + else: + storage.savePrototypeAssignmentsToSqlite(args.databaseFilename, [obj.getNum() for obj in objects], trajectoryType, labels[len(initialPrototypes):], initialPrototypes) + if args.display: + plt.figure() + for i,o in enumerate(objects): + if labels[i+len(initialPrototypes)] < 0: + o.plot('kx-') + else: + o.plot(utils.colors[labels[i+len(initialPrototypes)]]) + for i,p in enumerate(initialPrototypes): + p.getMovingObject().plot(utils.colors[i]+'o') + plt.axis('equal') + plt.show() if (args.learn or args.assign) and args.saveSimilarities: np.savetxt(utils.removeExtension(args.databaseFilename)+'-prototype-similarities.txt.gz', similarities, '%.4f') -if args.display and args.assign: - from matplotlib.pyplot import figure, show, axis - figure() - for i,o in enumerate(objects): - if i not in prototypeIndices: - if labels[i] < 0: - o.plot('kx') - else: - o.plot(utils.colors[labels[i]]) - for i in prototypeIndices: - objects[i].plot(utils.colors[i]+'o') - axis('equal') - show()
--- a/trafficintelligence/moving.py Wed Jun 20 12:04:22 2018 -0400 +++ b/trafficintelligence/moving.py Wed Jun 20 16:48:20 2018 -0400 @@ -1782,7 +1782,8 @@ return self.movingObject def setMovingObject(self, o): self.movingObject = o - + def __str__(self): + return '{} {} {}'.format(self.filename, self.num, self.trajectoryType) ################## # Annotations
--- a/trafficintelligence/storage.py Wed Jun 20 12:04:22 2018 -0400 +++ b/trafficintelligence/storage.py Wed Jun 20 16:48:20 2018 -0400 @@ -22,6 +22,10 @@ 'object': 'objects', 'objectfeatures': 'positions'} +assignmentTableNames = {'feature':'positions', + 'object': 'objects', + 'objectfeatures': 'positions'} + ######################### # Sqlite ######################### @@ -52,7 +56,7 @@ elif dataType == 'pois': dropTables(connection, ['gaussians2d', 'objects_pois']) elif dataType == 'prototype': - dropTables(connection, ['prototypes', 'objects_prototypes']) + dropTables(connection, ['prototypes', 'objects_prototypes', 'features_prototypes']) else: print('Unknown data type {} to delete from database'.format(dataType)) else: @@ -589,7 +593,7 @@ printDBError(error) connection.commit() -def savePrototypeAssignmentsToSqlite(filename, objects, objectType, labels, prototypes): +def savePrototypeAssignmentsToSqlite(filename, objectNumbers, objectType, labels, prototypes): with sqlite3.connect(filename) as connection: cursor = connection.cursor() try: @@ -600,9 +604,10 @@ tableName = 'objects_prototypes' objectIdColumnName = 'object_id' cursor.execute('CREATE TABLE IF NOT EXISTS '+tableName+' ('+objectIdColumnName+' INTEGER, prototype_filename VARCHAR, prototype_id INTEGER, trajectory_type VARCHAR CHECK (trajectory_type IN (\"feature\", \"object\")), PRIMARY KEY('+objectIdColumnName+', prototype_filename, prototype_id, trajectory_type))') - for obj, label in zip(objects, labels): - proto = prototypes[label] - cursor.execute('INSERT INTO objects_prototypes VALUES(?,?,?,?)', (obj.getNum(), proto.getFilename(), proto.getNum(), proto.getTrajectoryType())) + for objNum, label in zip(objectNumbers, labels): + if label >=0: + proto = prototypes[label] + cursor.execute('INSERT INTO '+tableName+' VALUES(?,?,?,?)', (objNum, proto.getFilename(), proto.getNum(), proto.getTrajectoryType())) except sqlite3.OperationalError as error: printDBError(error) connection.commit()