Mercurial Hosting > traffic-intelligence
changeset 1161:b968c33f8c2f
work on producing figures and collision maps for large datasets with multiple sites
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Thu, 04 Mar 2021 23:12:34 -0500 |
parents | 3a6b00f13e95 |
children | efd52c55a72b |
files | scripts/process.py trafficintelligence/events.py |
diffstat | 2 files changed, 74 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/process.py Mon Feb 22 22:12:19 2021 -0500 +++ b/scripts/process.py Thu Mar 04 23:12:34 2021 -0500 @@ -24,7 +24,7 @@ parser.add_argument('--process', dest = 'process', help = 'data to process', choices = ['feature', 'object', 'classification', 'prototype', 'interaction']) parser.add_argument('--display', dest = 'display', help = 'data to display (replay over video)', choices = ['feature', 'object', 'classification', 'interaction']) parser.add_argument('--progress', dest = 'progress', help = 'information about the progress of processing', action = 'store_true') -parser.add_argument('--analyze', dest = 'analyze', help = 'data to analyze (results)', choices = ['feature', 'object', 'classification', 'interaction', 'event-speed', 'event-interaction']) +parser.add_argument('--analyze', dest = 'analyze', help = 'data to analyze (results)', choices = ['feature', 'object', 'classification', 'interaction', 'collision-map', 'event-speed', 'event-interaction']) # common options parser.add_argument('--cfg', dest = 'configFilename', help = 'name of the configuration file') @@ -61,6 +61,8 @@ # analysis options parser.add_argument('--output', dest = 'output', help = 'kind of output to produce (interval means)', choices = ['figure', 'interval', 'event']) parser.add_argument('--min-duration', dest = 'minDuration', help = 'mininum duration we have to see the user or interaction to take into account in the analysis (s)', type = float) +parser.add_argument('--max-time-indicator-value', dest = 'maxTimeIndicatorValue', help = 'maximum indicator value for time indicators like PET and TTC (s)', type = float) +parser.add_argument('--max-speed-indicator-value', dest = 'maxSpeedIndicatorValue', help = 'maximum indicator value for speed indicators like individual speed statistics and speed differential (km/h)', type = float) parser.add_argument('--interval-duration', dest = 'intervalDuration', help = 'length of time interval to aggregate data (min)', type = int, default = 15) parser.add_argument('--aggregation', dest = 'aggMethods', help = 'aggregation method per user/interaction and per interval', choices = ['mean', 'median', 'centile'], nargs = '*', default = ['median']) parser.add_argument('--aggregation-centiles', dest = 'aggCentiles', help = 'centile(s) to compute from the observations', nargs = '*', type = int) @@ -138,7 +140,8 @@ print('{} video sequences without a camera view:'.format(len(videoSequences))) print([vs.idx for vs in videoSequences]) print('-'*80) - print(data) + with pd.option_context('display.max_rows', None, 'display.max_columns', None): + print(data) ################################# # Delete @@ -284,26 +287,27 @@ if args.analyze == 'interaction': # redo as for object, export in dataframe all interaction data indicatorIds = [2,5,7,10] - conversionFactors = {2: 1., 5: 30.*3.6, 7:1./30, 10:1./30} #maxIndicatorValue = {2: float('inf'), 5: float('inf'), 7:10., 10:10.} data = [] # list of observation per site-user with time headers = ['site', 'date', 'time', events.Interaction.indicatorNames[10].replace(' ','-')] # user types? aggFunctions, tmpheaders = utils.aggregationMethods(args.aggMethods, args.aggCentiles) + nAggFunctions = len(tmpheaders) + indicatorUnits = [events.Interaction.indicatorUnits[10]] # for PET above for i in indicatorIds[:3]: for h in tmpheaders: headers.append(events.Interaction.indicatorNames[i].replace(' ','-')+'-'+h) - indicators = {} - interactions = {} + indicatorUnits.append(events.Interaction.indicatorUnits[i]) for vs in videoSequences: print('Extracting SMoS from '+vs.getDatabaseFilename()) interactions = storage.loadInteractionsFromSqlite(str(parentPath/vs.getDatabaseFilename())) minDuration = vs.cameraView.cameraType.frameRate*args.minDuration + conversionFactors = {2: 1., 5: 3.6*vs.cameraView.cameraType.frameRate, 7:1./vs.cameraView.cameraType.frameRate, 10:1./vs.cameraView.cameraType.frameRate} for inter in interactions: if inter.length() > minDuration: d = vs.startTime.date() t = vs.startTime.time() row = [vs.cameraView.site.name, d, utils.framesToTime(inter.getFirstInstant(), vs.cameraView.cameraType.frameRate, t)] - pet = inter.getIndicator('Post Encroachment Time') + pet = inter.getIndicator(events.Interaction.indicatorNames[10]) if pet is None: row.append(None) else: @@ -320,21 +324,74 @@ else: row.append(agg) else: - row.extend([None]*len(aggFunctions)) + row.extend([None]*nAggFunctions) data.append(row) data = pd.DataFrame(data, columns = headers) if args.output == 'figure': - for i in indicatorIds: - pass # tmp = [indicators[siteId][i] for siteId in indicators] - # plt.ioff() - # plt.figure() + plt.ioff() + for i, indic in enumerate(headers[3:]): + if 'Time' in indic and args.maxTimeIndicatorValue is not None: + tmp = data.loc[data[indic] < args.maxTimeIndicatorValue, ['site', indic]] + elif 'Speed' in indic and args.maxSpeedIndicatorValue is not None: + tmp = data.loc[data[indic] < args.maxSpeedIndicatorValue, ['site', indic]] + else: + tmp = data[['site', indic]] + plt.figure() + tmp.boxplot(indic, 'site') # plt.boxplot(tmp, labels = [session.query(Site).get(siteId).name for siteId in indicators]) - # plt.ylabel(events.Interaction.indicatorNames[i]+' ('+events.Interaction.indicatorUnits[i]+')') - # plt.savefig(events.Interaction.indicatorNames[i]+'.png', dpi=150) - # plt.close() + plt.ylabel(indic+' ('+indicatorUnits[i]+')') + plt.savefig('boxplot-sites-'+indic+'.pdf')#, dpi=150) + plt.close() + plt.figure() + for site in sorted(tmp.site.unique()): + x = sorted(tmp.loc[tmp.site == site, indic]) + plt.plot(x, np.arange(1,len(x)+1)/len(x), label=site) + plt.legend() + plt.title('Cumulative Distribution Function by Site') + plt.xlabel(indic+' ('+indicatorUnits[i]+')') + plt.savefig('cdf-sites-'+indic+'.pdf') + plt.close() elif args.output == 'event': data.to_csv(args.eventFilename, index = False) +if args.analyze == 'collision-map': + predictionParameters = prediction.CVExactPredictionParameters() + data = [] + for vs in videoSequences: + print('Extracting potential collision points from '+vs.getDatabaseFilename()) + interactions = storage.loadInteractionsFromSqlite(str(parentPath/vs.getDatabaseFilename())) + objects = storage.loadTrajectoriesFromSqlite(str(parentPath/vs.getDatabaseFilename()), 'object') + params = storage.ProcessParameters(str(parentPath/vs.cameraView.getTrackingConfigurationFilename())) + minDuration = vs.cameraView.cameraType.frameRate*args.minDuration + maxTimeIndicatorValue = vs.cameraView.cameraType.frameRate*args.maxTimeIndicatorValue + for inter in interactions: + if inter.length() > minDuration: + ttc = inter.getIndicator(events.Interaction.indicatorNames[7]) + if ttc is not None: + t = min(ttc.values, key = ttc.values.get) + if args.maxTimeIndicatorValue is None or ttc.values[t] < maxTimeIndicatorValue: + inter.setRoadUsers(objects) + cps, _ = predictionParameters.computeCrossingsCollisionsAtInstant(t, inter.roadUser1, inter.roadUser2, params.collisionDistance, params.predictionTimeHorizon) + data.append([vs.cameraView.site.name, cps[0].x, cps[0].y, cps[0].indicator]) + data = pd.DataFrame(data, columns = ['site', 'x', 'y', 'ttc']) + margin = 0.1 + for site in data.site.unique(): + s = session.query(Site).filter(Site.name.like('%'+site+'%')).first() + img = plt.imread(str(parentPath/s.getMapImageFilename())) + tmp = data[data.site == site].copy() + tmp.x = tmp.x/s.nUnitsPerPixel + tmp.y = tmp.y/s.nUnitsPerPixel + h, w, _ = img.shape + tmp = tmp[(tmp.x>-margin*w) & (tmp.x < (1+margin)*w) & (tmp.y > -margin*h) & (tmp.y < (1+margin)*h)] + plt.figure() + plt.imshow(img) + plt.hexbin(tmp.x, tmp.y, alpha = 0.5, edgecolors = 'face', mincnt=1, gridsize=50) + plt.title('Density of Potential Collision Points at Site '+site) + plt.colorbar() + plt.axis('equal') + plt.savefig('collision-map-'+site+'.pdf') + #plt.close() + if args.analyze == 'event-speed': # aggregate event data by 15 min interval (args.intervalDuration), count events with thresholds data = pd.read_csv(args.eventFilename, parse_dates = [2]) #data = pd.read_csv('./speeds.csv', converters = {'time': lambda s: datetime.datetime.strptime(s, "%H:%M:%S").time()}, nrows = 5000) @@ -377,6 +434,7 @@ data = pd.read_csv(args.eventFilename, parse_dates = [2]) headers = ['site', 'date', 'intervalend15', 'duration', 'count'] aggFunctions, tmpheaders = utils.aggregationMethods(args.aggMethods, args.aggCentiles) + nAggFunctions = len(tmpheaders) dataColumns = list(data.columns[3:]) for h in dataColumns: if not 'speed' in h.lower(): # proximity indicators are reversed, taking 85th centile of this column will yield the 15th centile (which we have to take the opposite again) @@ -405,7 +463,7 @@ else: row.append(np.abs(aggregated)) else: - row.extend([None]*len(aggFunctions)) + row.extend([None]*nAggFunctions) for h,t in zip(dataColumns, args.eventThresholds): # each threshold in this case applies to one indicator if 'speed' in h.lower(): row.append((group[h] > t).sum())