Mercurial Hosting > traffic-intelligence
changeset 708:a37c565f4b68
merged dev
author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
---|---|
date | Wed, 22 Jul 2015 14:17:44 -0400 |
parents | 7efa36b9bcfd (current diff) e395bffe1412 (diff) |
children | 29daabe094fe 70a3cdf0dbb3 |
files | scripts/classify-objects.py |
diffstat | 17 files changed, 482 insertions(+), 392 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Wed Jul 22 14:17:19 2015 -0400 +++ b/Makefile Wed Jul 22 14:17:44 2015 -0400 @@ -1,3 +1,4 @@ +INSTALL_DIR = /usr/local/bin cexe: @cd c && make feature-based-tracking @@ -17,9 +18,9 @@ @cp bin/feature-based-tracking /usr/local/bin @echo "=========================================" @echo "Copying Python scripts" - @cp scripts/* /usr/local/bin + @cp scripts/* $(INSTALL_DIR) uninstall: @echo "Uninstalling for Linux" - rm /usr/local/bin/feature-based-tracking - @cd scripts && ./uninstall-scripts.sh \ No newline at end of file + rm $(INSTALL_DIR)/feature-based-tracking + @cd scripts && ./uninstall-scripts.sh $(INSTALL_DIR)
--- a/c/utils.cpp Wed Jul 22 14:17:19 2015 -0400 +++ b/c/utils.cpp Wed Jul 22 14:17:44 2015 -0400 @@ -4,7 +4,6 @@ #include <iostream> #include <fstream> -#include <sstream> using namespace std;
--- a/include/utils.hpp Wed Jul 22 14:17:19 2015 -0400 +++ b/include/utils.hpp Wed Jul 22 14:17:44 2015 -0400 @@ -1,6 +1,7 @@ #ifndef UTILS_HPP #define UTILS_HPP +#include <sstream> #include <iosfwd> #include <string> #include <vector> @@ -73,7 +74,8 @@ template<typename T> bool fromString(T & result, const std::string & s) { std::istringstream iss(s); - return iss >> result != 0; + iss >> result; + return iss.good() || iss.eof(); } #endif
--- a/python/cvutils.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/cvutils.py Wed Jul 22 14:17:44 2015 -0400 @@ -17,7 +17,7 @@ skimageAvailable = False from sys import stdout -from numpy import dot, array, append +from numpy import dot, array, append, float32 #import aggdraw # agg on top of PIL (antialiased drawing) @@ -126,7 +126,8 @@ def playVideo(filename, firstFrameNum = 0, frameRate = -1, interactive = False, printFrames = True, text = None, rescale = 1., step = 1): '''Plays the video''' windowName = 'frame' - cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) + if rescale == 1.: + cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) wait = 5 if frameRate > 0: wait = int(round(1000./frameRate)) @@ -200,7 +201,10 @@ images = [] capture = cv2.VideoCapture(videoFilename) if capture.isOpened(): - nDigits = int(floor(log10(capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))))+1 + rawCount = capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT) + if rawCount < 0: + rawCount = firstFrameNum+nFrames+1 + nDigits = int(floor(log10(rawCount)))+1 ret = False capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, firstFrameNum) imgNum = 0 @@ -232,7 +236,7 @@ print('Video capture for {} failed'.format(videoFilename)) return None - def imageBox(img, obj, frameNum, homography, width, height, px = 0.2, py = 0.2, pixelThreshold = 800): + def imageBox(img, obj, frameNum, homography, width, height, px = 0.2, py = 0.2, minNPixels = 800): 'Computes the bounding box of object at frameNum' x = [] y = [] @@ -253,10 +257,10 @@ yCropMax = int(min(height - 1, .5 * (ymin + ymax + a))) xCropMin = int(max(0, .5 * (xmin + xmax - a))) xCropMax = int(min(width - 1, .5 * (xmin + xmax + a))) - if yCropMax != yCropMin and xCropMax != xCropMin and (yCropMax - yCropMin) * (xCropMax - xCropMin) > pixelThreshold: + if yCropMax != yCropMin and xCropMax != xCropMin and (yCropMax - yCropMin) * (xCropMax - xCropMin) > minNPixels: croppedImg = img[yCropMin : yCropMax, xCropMin : xCropMax] else: - croppedImg = [] + croppedImg = None return croppedImg, yCropMin, yCropMax, xCropMin, xCropMax @@ -270,7 +274,8 @@ height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)) windowName = 'frame' - #cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) + if rescale == 1.: + cv2.namedWindow(windowName, cv2.WINDOW_NORMAL) if undistort: # setup undistortion [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) @@ -538,10 +543,10 @@ return None if skimageAvailable: + from skimage.feature import hog + from skimage import color, transform + def HOG(image, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): - from skimage.feature import hog - from skimage import color, transform - bwImg = color.rgb2gray(image) inputImg = transform.resize(bwImg, rescaleSize) features = hog(inputImg, orientations, pixelsPerCell, cellsPerBlock, visualize, normalize) @@ -551,14 +556,13 @@ features = features[0] figure() subplot(1,2,1) - imshow(img) + imshow(inputImg) subplot(1,2,2) imshow(hogViz) - return features + return float32(features) def createHOGTrainingSet(imageDirectory, classLabel, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False): from os import listdir - from numpy import float32 from matplotlib.pyplot import imread inputData = []
--- a/python/events.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/events.py Wed Jul 22 14:17:44 2015 -0400 @@ -6,7 +6,6 @@ from base import VideoFilenameAddable import numpy as np -from numpy import arccos import multiprocessing import itertools @@ -90,6 +89,8 @@ '', ''] + timeIndicators = ['Time to Collision', 'predicted Post Encroachment Time'] + def __init__(self, num = None, timeInterval = None, roaduserNum1 = None, roaduserNum2 = None, roadUser1 = None, roadUser2 = None, categoryNum = None): moving.STObject.__init__(self, num, timeInterval) if timeInterval is None and roadUser1 is not None and roadUser2 is not None: @@ -113,20 +114,23 @@ return self.roadUserNumbers def setRoadUsers(self, objects): - nums = list(self.getRoadUserNumbers()) - if objects[nums[0]].getNum() == nums[0]: + nums = sorted(list(self.getRoadUserNumbers())) + if nums[0]<len(objects) and objects[nums[0]].getNum() == nums[0]: self.roadUser1 = objects[nums[0]] - if objects[nums[1]].getNum() == nums[1]: + if nums[1]<len(objects) and objects[nums[1]].getNum() == nums[1]: self.roadUser2 = objects[nums[1]] - i = 0 - while i < len(objects) and self.roadUser2 is None: - if objects[i].getNum() in nums: - if self.roadUser1 is None: - self.roadUser1 = objects[i] - else: - self.roadUser2 = objects[i] - i += 1 + if self.roadUser1 is None or self.roadUser2 is None: + self.roadUser1 = None + self.roadUser2 = None + i = 0 + while i < len(objects) and self.roadUser2 is None: + if objects[i].getNum() in nums: + if self.roadUser1 is None: + self.roadUser1 = objects[i] + else: + self.roadUser2 = objects[i] + i += 1 def getIndicator(self, indicatorName): return self.indicators.get(indicatorName, None) @@ -177,14 +181,14 @@ v1 = self.roadUser1.getVelocityAtInstant(instant) v2 = self.roadUser2.getVelocityAtInstant(instant) deltav = v2-v1 - velocityAngles[instant] = arccos(moving.Point.dot(v1, v2)/(v1.norm2()*v2.norm2())) + velocityAngles[instant] = np.arccos(moving.Point.dot(v1, v2)/(v1.norm2()*v2.norm2())) collisionCourseDotProducts[instant] = moving.Point.dot(deltap, deltav) distances[instant] = deltap.norm2() speedDifferentials[instant] = deltav.norm2() if collisionCourseDotProducts[instant] > 0: interactionInstants.append(instant) if distances[instant] != 0 and speedDifferentials[instant] != 0: - collisionCourseAngles[instant] = arccos(collisionCourseDotProducts[instant]/(distances[instant]*speedDifferentials[instant])) + collisionCourseAngles[instant] = np.arccos(collisionCourseDotProducts[instant]/(distances[instant]*speedDifferentials[instant])) if len(interactionInstants) >= 2: self.interactionInterval = moving.TimeInterval(interactionInstants[0], interactionInstants[-1]) @@ -192,16 +196,16 @@ self.interactionInterval = moving.TimeInterval() self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[0], collisionCourseDotProducts)) self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[1], collisionCourseAngles)) - self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[2], distances)) + self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[2], distances, mostSevereIsMax = False)) self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[4], velocityAngles)) self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[5], speedDifferentials)) # if we have features, compute other indicators if self.roadUser1.hasFeatures() and self.roadUser2.hasFeatures(): - minDistance={} + minDistances={} for instant in self.timeInterval: - minDistance[instant] = moving.MovingObject.minDistance(self.roadUser1, self.roadUser2, instant) - self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[3], minDistance)) + minDistances[instant] = moving.MovingObject.minDistance(self.roadUser1, self.roadUser2, instant) + self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[3], minDistances, mostSevereIsMax = False)) def computeCrossingsCollisions(self, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False, timeInterval = None, nProcesses = 1, usePrototypes=False, route1= (-1,-1), route2=(-1,-1), prototypes={}, secondStepPrototypes={}, nMatching={}, objects=[], noiseEntryNums=[], noiseExitNums=[], minSimilarity=0.1, mostMatched=None, useDestination=True, useSpeedPrototype=True, acceptPartialLength=30, step=1): '''Computes all crossing and collision points at each common instant for two road users. ''' @@ -217,11 +221,12 @@ self.collisionPoints, crossingZones = predictionParameters.computeCrossingsCollisions(self.roadUser1, self.roadUser2, collisionDistanceThreshold, timeHorizon, computeCZ, debug, commonTimeInterval, nProcesses,usePrototypes,route1,route2,prototypes,secondStepPrototypes,nMatching,objects,noiseEntryNums,noiseExitNums,minSimilarity,mostMatched,useDestination,useSpeedPrototype,acceptPartialLength, step) for i, cp in self.collisionPoints.iteritems(): TTCs[i] = prediction.SafetyPoint.computeExpectedIndicator(cp) - self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[7], TTCs, mostSevereIsMax=False)) + if len(TTCs) > 0: + self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[7], TTCs, mostSevereIsMax=False)) # crossing zones and pPET if computeCZ: - self.crossingZones[predictionParameters.name] = crossingZones + self.crossingZones = crossingZones pPETs = {} for i, cz in self.crossingZones.iteritems(): pPETs[i] = prediction.SafetyPoint.computeExpectedIndicator(cz) @@ -242,18 +247,11 @@ else: return None - def getCrossingZones(self, predictionMethodName): - if self.crossingZones is not None: - return self.crossingZones[predictionMethodName] - else: - return None + def getCollisionPoints(self): + return self.collisionPoints - def getCollisionPoints(self, predictionMethodName): - if self.collisionPoints is not None: - return self.collisionPoints[predictionMethodName] - else: - return None - + def getCrossingZones(self): + return self.crossingZones def createInteractions(objects, _others = None): '''Create all interactions of two co-existing road users''' @@ -282,22 +280,19 @@ else: return None -def aggregateSafetyPoints(interactions, predictionMethodName = None, pointType = 'collision'): +def aggregateSafetyPoints(interactions, pointType = 'collision'): '''Put all collision points or crossing zones in a list for display''' - if predictionMethodName is None and len(interactions)>0: - predictionMethodName = interactions[0].collisionPoints.keys()[0] - allPoints = [] if pointType == 'collision': for i in interactions: - for points in i.collisionPoints[predictionMethodName].values(): + for points in i.collisionPoints.values(): allPoints += points elif pointType == 'crossing': for i in interactions: - for points in i.crossingZones[predictionMethodName].values(): + for points in i.crossingZones.values(): allPoints += points else: - print('unknown type of point '+pointType) + print('unknown type of point: '+pointType) return allPoints def prototypeCluster(interactions, similarityMatrix, alignmentMatrix, indicatorName, minSimilarity): @@ -343,130 +338,6 @@ Non-prototype interactions will be assigned to an existing prototype if all indicators are similar enough''' pass -# 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.roadUser1, pairs.roadUser2, 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].roadUser1, self.pairs[j].roadUser2, 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=float('Inf')): - 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=float('Inf')): - 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
--- a/python/indicators.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/indicators.py Wed Jul 22 14:17:44 2015 -0400 @@ -2,6 +2,10 @@ '''Class for indicators, temporal indicators, and safety indicators''' import moving +#import matplotlib.nxutils as nx +from matplotlib.pyplot import plot, ylim +from matplotlib.pylab import find +from numpy import array, arange, mean, floor, mean # need for a class representing the indicators, their units, how to print them in graphs... @@ -15,21 +19,21 @@ it should have more information like name, unit''' - def __init__(self, name, values, timeInterval=None, maxValue = None): + def __init__(self, name, values, timeInterval = None, maxValue = None): self.name = name - if timeInterval: + if timeInterval is None: + self.values = values + instants = sorted(self.values.keys()) + if len(instants) > 0: + self.timeInterval = moving.TimeInterval(instants[0], instants[-1]) + else: + self.timeInterval = moving.TimeInterval() + else: assert len(values) == timeInterval.length() self.timeInterval = timeInterval self.values = {} for i in xrange(int(round(self.timeInterval.length()))): self.values[self.timeInterval[i]] = values[i] - else: - self.values = values - instants = sorted(self.values.keys()) - if instants: - self.timeInterval = moving.TimeInterval(instants[0], instants[-1]) - else: - self.timeInterval = moving.TimeInterval() self.maxValue = maxValue def __len__(self): @@ -74,7 +78,6 @@ return [self.__getitem__(t) for t in self.timeInterval] def plot(self, options = '', xfactor = 1., yfactor = 1., timeShift = 0, **kwargs): - from matplotlib.pylab import plot,ylim if self.getTimeInterval().length() == 1: marker = 'o' else: @@ -141,9 +144,6 @@ self.mostSevereIsMax = mostSevereIsMax def getMostSevereValue(self, minNInstants=1): # TODO use np.percentile - from matplotlib.mlab import find - from numpy.core.multiarray import array - from numpy.core.fromnumeric import mean values = array(self.values.values()) indices = range(len(values)) if len(indices) >= minNInstants: @@ -152,6 +152,13 @@ else: return None + def getInstantOfMostSevereValue(self): + '''Returns the instant at which the indicator reaches its most severe value''' + if self.mostSevereIsMax: + return max(self.values, key=self.values.get) + else: + return min(self.values, key=self.values.get) + # functions to aggregate discretized maps of indicators # TODO add values in the cells between the positions (similar to discretizing vector graphics to bitmap) @@ -163,7 +170,6 @@ ex: speeds and trajectory''' - from numpy import floor, mean assert len(indicatorValues) == trajectory.length() indicatorMap = {} for k in xrange(trajectory.length()): @@ -178,28 +184,22 @@ indicatorMap[k] = mean(indicatorMap[k]) return indicatorMap -def indicatorMapFromPolygon(value, polygon, squareSize): - '''Fills an indicator map with the value within the polygon - (array of Nx2 coordinates of the polygon vertices)''' - import matplotlib.nxutils as nx - from numpy.core.multiarray import array, arange - from numpy import floor - - points = [] - for x in arange(min(polygon[:,0])+squareSize/2, max(polygon[:,0]), squareSize): - for y in arange(min(polygon[:,1])+squareSize/2, max(polygon[:,1]), squareSize): - points.append([x,y]) - inside = nx.points_inside_poly(array(points), polygon) - indicatorMap = {} - for i in xrange(len(inside)): - if inside[i]: - indicatorMap[(floor(points[i][0]/squareSize), floor(points[i][1]/squareSize))] = 0 - return indicatorMap +# def indicatorMapFromPolygon(value, polygon, squareSize): +# '''Fills an indicator map with the value within the polygon +# (array of Nx2 coordinates of the polygon vertices)''' +# points = [] +# for x in arange(min(polygon[:,0])+squareSize/2, max(polygon[:,0]), squareSize): +# for y in arange(min(polygon[:,1])+squareSize/2, max(polygon[:,1]), squareSize): +# points.append([x,y]) +# inside = nx.points_inside_poly(array(points), polygon) +# indicatorMap = {} +# for i in xrange(len(inside)): +# if inside[i]: +# indicatorMap[(floor(points[i][0]/squareSize), floor(points[i][1]/squareSize))] = 0 +# return indicatorMap def indicatorMapFromAxis(value, limits, squareSize): '''axis = [xmin, xmax, ymin, ymax] ''' - from numpy.core.multiarray import arange - from numpy import floor indicatorMap = {} for x in arange(limits[0], limits[1], squareSize): for y in arange(limits[2], limits[3], squareSize): @@ -210,7 +210,6 @@ '''Puts many indicator maps together (averaging the values in each cell if more than one maps has a value)''' - #from numpy import mean indicatorMap = {} for m in maps: for k,v in m.iteritems():
--- a/python/ml.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/ml.py Wed Jul 22 14:17:44 2015 -0400 @@ -6,25 +6,29 @@ class Model(object): '''Abstract class for loading/saving model''' - def load(self, fn): - self.model.load(fn) + def load(self, filename): + from os import path + if path.exists(filename): + self.model.load(filename) + else: + print('Provided filename {} does not exist: model not loaded!'.format(filename)) - def save(self, fn): - self.model.save(fn) + def save(self, filename): + self.model.save(filename) class SVM(Model): '''wrapper for OpenCV SimpleVectorMachine algorithm''' - def __init__(self, svm_type, kernel_type, degree = 0, gamma = 1, coef0 = 0, Cvalue = 1, nu = 0, p = 0): + def __init__(self): import cv2 self.model = cv2.SVM() + + def train(self, samples, responses, svm_type, kernel_type, degree = 0, gamma = 1, coef0 = 0, Cvalue = 1, nu = 0, p = 0): self.params = dict(svm_type = svm_type, kernel_type = kernel_type, degree = degree, gamma = gamma, coef0 = coef0, Cvalue = Cvalue, nu = nu, p = p) - - def train(self, samples, responses): self.model.train(samples, responses, params = self.params) - def predict(self, samples): - return np.float32([self.model.predict(s) for s in samples]) + def predict(self, hog): + return self.model.predict(hog) class Centroid(object):
--- a/python/moving.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/moving.py Wed Jul 22 14:17:44 2015 -0400 @@ -5,7 +5,7 @@ from base import VideoFilenameAddable from math import sqrt, atan2, cos, sin -from numpy import median, array, zeros, hypot, NaN, std +from numpy import median, array, zeros, hypot, NaN, std, floor, float32 from matplotlib.pyplot import plot from scipy.stats import scoreatpercentile from scipy.spatial.distance import cdist @@ -78,7 +78,6 @@ else: return None - def unionIntervals(intervals): 'returns the smallest interval containing all intervals' inter = intervals[0] @@ -123,6 +122,9 @@ '''Returns the length of the interval''' return float(max(0,self.last-self.first+1)) + def __len__(self): + return self.length() + # class BoundingPolygon: # '''Class for a polygon bounding a set of points # with methods to create intersection, unions... @@ -142,11 +144,17 @@ self.boundingPolygon = boundingPolygon def empty(self): - return self.timeInterval.empty() or not self.boudingPolygon + return self.timeInterval.empty()# or not self.boudingPolygon def getNum(self): return self.num + def __len__(self): + return self.timeInterval.length() + + def length(self): + return self.timeInterval.length() + def getFirstInstant(self): return self.timeInterval.first @@ -190,8 +198,12 @@ else: raise IndexError() - def orthogonal(self): - return Point(self.y, -self.x) + def orthogonal(self, clockwise = True): + 'Returns the orthogonal vector' + if clockwise: + return Point(self.y, -self.x) + else: + return Point(-self.y, self.x) def multiply(self, alpha): 'Warning, returns a new Point' @@ -1055,9 +1067,6 @@ print 'The object does not exist at '+str(inter) return None - def length(self): - return self.timeInterval.length() - def getPositions(self): return self.positions @@ -1129,8 +1138,13 @@ print('Object {} has no features loaded.'.format(self.getNum())) return None - def getSpeeds(self): - return self.getVelocities().norm() + def getSpeeds(self, nInstantsIgnoredAtEnds = 0): + speeds = self.getVelocities().norm() + if nInstantsIgnoredAtEnds > 0: + n = min(nInstantsIgnoredAtEnds, int(floor(self.length()/2.))) + return speeds[n:-n] + else: + return speeds def getSpeedIndicator(self): from indicators import SeverityIndicator @@ -1346,23 +1360,20 @@ ### # User Type Classification ### - def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, ignoreNInstantsAtEnds = 0): + def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): '''Classifies slow and fast road users slow: non-motorized -> pedestrians fast: motorized -> cars aggregationFunc can be any function that can be applied to a vector of speeds, including percentile: aggregationFunc = lambda x: percentile(x, percentileFactor) # where percentileFactor is 85 for 85th percentile''' - if ignoreNInstantsAtEnds > 0: - speeds = self.getSpeeds()[ignoreNInstantsAtEnds:-ignoreNInstantsAtEnds] - else: - speeds = self.getSpeeds() + speeds = self.getSpeeds(nInstantsIgnoredAtEnds) if aggregationFunc(speeds) >= threshold: self.setUserType(userType2Num['car']) else: self.setUserType(userType2Num['pedestrian']) - def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median): + def classifyUserTypeSpeed(self, speedProbabilities, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): '''Classifies road user per road user type speedProbabilities are functions return P(speed|class) in a dictionary indexed by user type names @@ -1375,62 +1386,67 @@ else: return x''' if not hasattr(self, 'aggregatedSpeed'): - self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) + self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds)) userTypeProbabilities = {} for userTypename in speedProbabilities: userTypeProbabilities[userType2Num[userTypename]] = speedProbabilities[userTypename](self.aggregatedSpeed) self.setUserType(utils.argmaxDict(userTypeProbabilities)) return userTypeProbabilities - def initClassifyUserTypeHoGSVM(self, aggregationFunc = median): + def initClassifyUserTypeHoGSVM(self, aggregationFunc, pedBikeCarSVM, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), nInstantsIgnoredAtEnds = 0): '''Initializes the data structures for classification - TODO? compute speed for longest feature? - Skip beginning and end of feature for speed? Offer options instead of median''' - self.aggregatedSpeed = aggregationFunc(self.getSpeeds()) + TODO? compute speed for longest feature?''' + self.aggregatedSpeed = aggregationFunc(self.getSpeeds(nInstantsIgnoredAtEnds)) + if self.aggregatedSpeed < pedBikeSpeedTreshold or bikeCarSVM is None: + self.appearanceClassifier = pedBikeCarSVM + elif self.aggregatedSpeed < bikeCarSpeedThreshold: + self.appearanceClassifier = bikeCarSVM + else: + class CarClassifier: + def predict(self, hog): + return userType2Num['car'] + self.appearanceClassifier = CarClassifier() + self.userTypes = {} - def classifyUserTypeHoGSVMAtInstant(self, img, pedBikeCarSVM, instant, homography, width, height, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), px = 0.2, py = 0.2, pixelThreshold = 800): + def classifyUserTypeHoGSVMAtInstant(self, img, instant, homography, width, height, px = 0.2, py = 0.2, minNPixels = 800): '''Extract the image box around the object and applies the SVM model on it''' - croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = imageBox(img, self, instant, homography, width, height, px, py, pixelThreshold) - if len(croppedImg) > 0: # != [] - hog = array([cvutils.HOG(croppedImg)], dtype = np.float32) - if self.aggregatedSpeed < pedBikeSpeedTreshold or bikeCarSVM is None: - self.userTypes[instant] = int(pedBikeCarSVM.predict(hog)) - elif self.aggregatedSpeed < bikeCarSpeedTreshold: - self.userTypes[instant] = int(bikeCarSVM.predict(hog)) - else: - self.userTypes[instant] = userType2Num['car'] + croppedImg, yCropMin, yCropMax, xCropMin, xCropMax = cvutils.imageBox(img, self, instant, homography, width, height, px, py, minNPixels) + if croppedImg is not None and len(croppedImg) > 0: + hog = cvutils.HOG(croppedImg)#HOG(image, rescaleSize = (64, 64), orientations=9, pixelsPerCell=(8, 8), cellsPerBlock=(2, 2), visualize=False, normalize=False) + self.userTypes[instant] = int(self.appearanceClassifier.predict(hog)) else: self.userTypes[instant] = userType2Num['unknown'] - def classifyUserTypeHoGSVM(self, images, pedBikeCarSVM, homography, width, height, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), speedProbabilities = None, aggregationFunc = median, px = 0.2, py = 0.2, pixelThreshold = 800): + def classifyUserTypeHoGSVM(self, pedBikeCarSVM = None, width = 0, height = 0, homography = None, images = None, bikeCarSVM = None, pedBikeSpeedTreshold = float('Inf'), bikeCarSpeedThreshold = float('Inf'), minSpeedEquiprobable = -1, speedProbabilities = None, aggregationFunc = median, nInstantsIgnoredAtEnds = 0, px = 0.2, py = 0.2, minNPixels = 800): '''Agregates SVM detections in each image and returns probability (proportion of instants with classification in each category) - iamges is a dictionary of images indexed by instant + images is a dictionary of images indexed by instant With default parameters, the general (ped-bike-car) classifier will be used - TODO? consider all categories?''' - if not hasattr(self, aggregatedSpeed) or not hasattr(self, userTypes): + + Considered categories are the keys of speedProbabilities''' + if not hasattr(self, 'aggregatedSpeed') or not hasattr(self, 'userTypes'): print('Initilize the data structures for classification by HoG-SVM') - self.initClassifyUserTypeHoGSVM(aggregationFunc) + self.initClassifyUserTypeHoGSVM(aggregationFunc, pedBikeCarSVM, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, nInstantsIgnoredAtEnds) - if len(self.userTypes) != self.length(): # if classification has not been done previously + if len(self.userTypes) != self.length() and images is not None: # if classification has not been done previously for t in self.getTimeInterval(): if t not in self.userTypes: - self.classifyUserTypeHoGSVMAtInstant(images[t], pedBikeCarSVM, t, homography, width, height, bikeCarSVM, pedBikeSpeedTreshold, bikeCarSpeedThreshold, px, py, pixelThreshold) + self.classifyUserTypeHoGSVMAtInstant(images[t], t, homography, width, height, px, py, minNPixels) # compute P(Speed|Class) - if speedProbabilities is None: # equiprobable information from speed + if speedProbabilities is None or self.aggregatedSpeed < minSpeedEquiprobable: # equiprobable information from speed userTypeProbabilities = {userType2Num['car']: 1., userType2Num['pedestrian']: 1., userType2Num['bicycle']: 1.} else: userTypeProbabilities = {userType2Num[userTypename]: speedProbabilities[userTypename](self.aggregatedSpeed) for userTypename in speedProbabilities} # result is P(Class|Appearance) x P(Speed|Class) - nInstantsUserType = {userType2Num[userTypename]: 0 for userTypename in userTypeProbabilities}# number of instants the object is classified as userTypename + nInstantsUserType = {userTypeNum: 0 for userTypeNum in userTypeProbabilities}# number of instants the object is classified as userTypename for t in self.userTypes: - nInstantsUserType[self.userTypes[t]] += 1 - for userTypename in userTypeProbabilities: - userTypeProbabilities[userTypename] *= nInstantsUserType[userTypename] + nInstantsUserType[self.userTypes[t]] = nInstantsUserType.get(self.userTypes[t], 0) + 1 + for userTypeNum in userTypeProbabilities: + userTypeProbabilities[userTypeNum] *= nInstantsUserType[userTypeNum] # class is the user type that maximizes usertype probabilities self.setUserType(utils.argmaxDict(userTypeProbabilities))
--- a/python/prediction.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/prediction.py Wed Jul 22 14:17:44 2015 -0400 @@ -6,6 +6,7 @@ import math, random import numpy as np +from multiprocessing import Pool class PredictedTrajectory(object): @@ -137,8 +138,7 @@ @staticmethod def computeExpectedIndicator(points): - from numpy import sum - return sum([p.indicator*p.probability for p in points])/sum([p.probability for p in points]) + return np.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 @@ -161,11 +161,11 @@ from matplotlib.pyplot import figure, axis, title, close, savefig figure() for et in predictedTrajectories1: - et.predictPosition(timeHorizon) + et.predictPosition(int(np.round(timeHorizon))) et.plot('rx') for et in predictedTrajectories2: - et.predictPosition(timeHorizon) + et.predictPosition(int(np.round(timeHorizon))) et.plot('bx') obj1.plot('r') obj2.plot('b') @@ -321,8 +321,8 @@ if nProcesses == 1: if usePrototypes: firstInstant= next( (x for x in xrange(commonTimeInterval.first,commonTimeInterval.last) if x-obj1.getFirstInstant() >= acceptPartialLength and x-obj2.getFirstInstant() >= acceptPartialLength), commonTimeInterval.last) - commonTimeIntervalList1= list(xrange(firstInstant,commonTimeInterval.last-1)) # do not look at the 1 last position/velocities, often with errors - commonTimeIntervalList2= list(xrange(firstInstant,commonTimeInterval.last-1,step)) # do not look at the 1 last position/velocities, often with errors + commonTimeIntervalList1= range(firstInstant,commonTimeInterval.last-1) # do not look at the 1 last position/velocities, often with errors + commonTimeIntervalList2= range(firstInstant,commonTimeInterval.last-1,step) # do not look at the 1 last position/velocities, often with errors for i in commonTimeIntervalList2: i, cp, cz = self.computeCrossingsCollisionsAtInstant(i, obj1, obj2, collisionDistanceThreshold, timeHorizon, computeCZ, debug,usePrototypes,route1,route2,prototypes,secondStepPrototypes,nMatching,objects,noiseEntryNums,noiseExitNums,minSimilarity,mostMatched,useDestination,useSpeedPrototype) if len(cp) != 0: @@ -345,7 +345,6 @@ if len(cz) != 0: crossingZones[i] = cz else: - from multiprocessing import Pool pool = Pool(processes = nProcesses) jobs = [pool.apply_async(computeCrossingsCollisionsAtInstant, args = (self, i, obj1, obj2, collisionDistanceThreshold, timeHorizon, computeCZ, debug,usePrototypes,route1,route2,prototypes,secondStepPrototypes,nMatching,objects,noiseEntryNums,noiseExitNums,minSimilarity,mostMatched,useDestination,useSpeedPrototype)) for i in list(commonTimeInterval)[:-1]] #results = [j.get() for j in jobs] @@ -493,7 +492,8 @@ class CVDirectPredictionParameters(PredictionParameters): '''Prediction parameters of prediction at constant velocity - using direct computation of the intersecting point''' + using direct computation of the intersecting point + Warning: the computed time to collision may be higher than timeHorizon (not used)''' def __init__(self): PredictionParameters.__init__(self, 'constant velocity (direct computation)', None) @@ -533,19 +533,6 @@ crossingZones = [SafetyPoint(intersection, 1., timeInterval1.distance(timeInterval2))] else: collisionPoints = [SafetyPoint(intersection, 1., collisionTimeInterval.center())] - # elif computeCZ and (dot1 > 0 or dot2 > 0): - # if dot1 > 0: - # firstUser = obj2 # first through crossingzone - # secondUser = obj1 # second through crossingzone - # elif dot2 > 0: - # firstUser = obj1 - # secondUser = obj2 - # p2 = secondUser.getPositionAtInstant(currentInstant) - # v2 = secondUser.getVelocityAtInstant(currentInstant) - # indices, intersections = firstUser.getPositions().getLineIntersections(p2, p2+v2) - # if indices is not None: - # pass - # else: # one has to predict !!! if debug and intersection is not None: from matplotlib.pyplot import plot, figure, axis, title @@ -562,12 +549,13 @@ class CVExactPredictionParameters(PredictionParameters): '''Prediction parameters of prediction at constant velocity - using direct computation of the intersecting point (solving for the equation''' + using direct computation of the intersecting point (solving the equation) + Warning: the computed time to collision may be higher than timeHorizon (not used)''' def __init__(self): PredictionParameters.__init__(self, 'constant velocity (direct exact computation)', None) - def computeCrossingsCollisionsAtInstant(self, currentInstant, obj1, obj2, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False): + def computeCrossingsCollisionsAtInstant(self, currentInstant, obj1, obj2, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False, *kwargs): 'TODO add collision point coordinates, compute pPET' #collisionPoints = [] #crossingZones = [] @@ -581,9 +569,9 @@ if intersection is not None: ttc = moving.Point.timeToCollision(p1, p2, v1, v2, collisionDistanceThreshold) if ttc: - return [SafetyPoint(intersection, 1., ttc)], [] # (p1+v1.multiply(ttc)+p2+v2.multiply(ttc)).multiply(0.5) + return currentInstant, [SafetyPoint(intersection, 1., ttc)], [] # (p1+v1.multiply(ttc)+p2+v2.multiply(ttc)).multiply(0.5) else: - return [],[] + return currentInstant, [],[] #### # Other Methods
--- a/python/storage.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/storage.py Wed Jul 22 14:17:44 2015 -0400 @@ -6,6 +6,7 @@ from base import VideoFilenameAddable import sqlite3, logging +from numpy import log, min as npmin, max as npmax, round as npround, array, sum as npsum, loadtxt commentChar = '#' @@ -289,22 +290,16 @@ connection.close() return matched_indexes -def getTrajectoryIdQuery(objectNumbers, trajectoryType): - if trajectoryType == 'feature': - statementBeginning = 'where trajectory_id ' - elif trajectoryType == 'object': - statementBeginning = 'and OF.object_id ' - elif trajectoryType == 'bbtop' or 'bbbottom': - statementBeginning = 'where object_id ' - else: - print('no trajectory type was chosen') - +def getObjectCriteria(objectNumbers): if objectNumbers is None: query = '' elif type(objectNumbers) == int: - query = statementBeginning+'between 0 and {0} '.format(objectNumbers) + query = 'between 0 and {0}'.format(objectNumbers-1) elif type(objectNumbers) == list: - query = statementBeginning+'in ('+', '.join([str(n) for n in objectNumbers])+') ' + query = 'in ('+', '.join([str(n) for n in objectNumbers])+')' + else: + print('objectNumbers {} are not a known type ({})'.format(objectNumbers, type(objectNumbers))) + query = '' return query def loadTrajectoriesFromTable(connection, tableName, trajectoryType, objectNumbers = None): @@ -315,13 +310,19 @@ cursor = connection.cursor() try: - idQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType) + objectCriteria = getObjectCriteria(objectNumbers) if trajectoryType == 'feature': - queryStatement = 'SELECT * from '+tableName+' '+idQuery+'ORDER BY trajectory_id, frame_number' + queryStatement = 'SELECT * from '+tableName + if objectNumbers is not None: + queryStatement += ' where trajectory_id '+objectCriteria + queryStatement += ' 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 '+idQuery+'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' + if objectNumbers is not None: + queryStatement += ' and OF.object_id '+objectCriteria + queryStatement += ' group by OF.object_id, P.frame_number ORDER BY OF.object_id, P.frame_number' cursor.execute(queryStatement) logging.debug(queryStatement) elif trajectoryType in ['bbtop', 'bbbottom']: @@ -329,7 +330,10 @@ corner = 'top_left' elif trajectoryType == 'bbbottom': corner = 'bottom_right' - queryStatement = 'SELECT object_id, frame_number, x_'+corner+', y_'+corner+' FROM '+tableName+' '+idQuery+'ORDER BY object_id, frame_number' + queryStatement = 'SELECT object_id, frame_number, x_'+corner+', y_'+corner+' FROM '+tableName + if objectNumbers is not None: + queryStatement += ' where object_id '+objectCriteria + queryStatement += ' ORDER BY object_id, frame_number' cursor.execute(queryStatement) logging.debug(queryStatement) else: @@ -361,17 +365,17 @@ 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:]) + objectCriteria = getObjectCriteria(objectNumbers) + queryStatement = 'SELECT object_id, road_user_type from objects' + if objectNumbers is not None: + queryStatement += ' where object_id '+objectCriteria + cursor.execute(queryStatement) userTypes = {} for row in cursor: userTypes[row[0]] = row[1] return userTypes -def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None): +def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None, withFeatures = False): '''Loads the first objectNumbers objects or the indices in objectNumbers from the database''' connection = sqlite3.connect(filename) @@ -390,8 +394,11 @@ cursor = connection.cursor() try: # attribute feature numbers to objects - objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType) - queryStatement = 'SELECT P.trajectory_id, OF.object_id from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id '+objectIdQuery+'group by P.trajectory_id order by OF.object_id' # order is important to group all features per object + objectCriteria = getObjectCriteria(objectNumbers) + queryStatement = 'SELECT P.trajectory_id, OF.object_id from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id' + if objectNumbers is not None: + queryStatement += ' and OF.object_id '+objectCriteria + queryStatement += ' group by P.trajectory_id order by OF.object_id' # order is important to group all features per object cursor.execute(queryStatement) logging.debug(queryStatement) @@ -410,6 +417,14 @@ userTypes = loadUserTypesFromTable(cursor, trajectoryType, objectNumbers) for obj in objects: obj.userType = userTypes[obj.getNum()] + + if withFeatures: + nFeatures = 0 + for obj in objects: + nFeatures = max(nFeatures, max(obj.featureNumbers)) + features = loadTrajectoriesFromSqlite(filename, 'feature', nFeatures+1) + for obj in objects: + obj.setFeatures(features) except sqlite3.OperationalError as error: printDBError(error) @@ -512,7 +527,7 @@ connection = sqlite3.connect(filename) cursor = connection.cursor() try: - cursor.execute('select INT.id, INT.object_id1, INT.object_id2, INT.first_frame_number, INT.last_frame_number, IND.indicator_type, IND.frame_number, IND.value from interactions INT, indicators IND where INT.id = IND.interaction_id ORDER BY INT.id, IND.indicator_type') + cursor.execute('select INT.id, INT.object_id1, INT.object_id2, INT.first_frame_number, INT.last_frame_number, IND.indicator_type, IND.frame_number, IND.value from interactions INT, indicators IND where INT.id = IND.interaction_id ORDER BY INT.id, IND.indicator_type, IND.frame_number') interactionNum = -1 indicatorTypeNum = -1 tmpIndicators = {} @@ -521,13 +536,14 @@ interactionNum = row[0] interactions.append(events.Interaction(interactionNum, moving.TimeInterval(row[3],row[4]), row[1], row[2])) interactions[-1].indicators = {} - if indicatorTypeNum != row[5]: + if indicatorTypeNum != row[5] or row[0] != interactionNum: + indicatorTypeNum = row[5] indicatorName = events.Interaction.indicatorNames[indicatorTypeNum] indicatorValues = {row[6]:row[7]} - interactions[-1].indicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues) - indicatorTypeNum = row[5] + interactions[-1].indicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues, mostSevereIsMax = not indicatorName in events.Interaction.timeIndicators) else: indicatorValues[row[6]] = row[7] + interactions[-1].indicators[indicatorName].timeInterval.last = row[6] except sqlite3.OperationalError as error: printDBError(error) return [] @@ -656,20 +672,21 @@ if usePandas: from pandas import read_csv - from numpy import min, max, round data = read_csv(filename, delimiter=';', comment='*', header=0, skiprows = 1) generatePDLaneColumn(data) data['TIME'] = data['$VEHICLE:SIMSEC']*simulationStepsPerTimeUnit if warmUpLastInstant is not None: data = data[data['TIME']>=warmUpLastInstant] grouped = data.loc[:,['NO','TIME']].groupby(['NO'], as_index = False) - instants = grouped['TIME'].agg({'first': min, 'last': max}) + instants = grouped['TIME'].agg({'first': npmin, 'last': npmax}) for row_index, row in instants.iterrows(): objNum = int(row['NO']) tmp = data[data['NO'] == objNum] objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(row['first'], row['last'])) # positions should be rounded to nDecimals decimals only - objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory(S = round(tmp['POS'].tolist(), nDecimals), Y = round(tmp['POSLAT'].tolist(), nDecimals), lanes = tmp['LANE'].tolist()) + objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory(S = npround(tmp['POS'].tolist(), nDecimals), Y = npround(tmp['POSLAT'].tolist(), nDecimals), lanes = tmp['LANE'].tolist()) + if nObjects > 0 and len(objects) >= nObjects: + break return objects.values() else: inputfile = openCheck(filename, quitting = True) @@ -718,7 +735,6 @@ If lanes is not None, only the data for the selected lanes will be provided (format as string x_y where x is link index and y is lane index)''' from pandas import read_csv - from numpy import array, sum as npsum columns = ['NO', '$VEHICLE:SIMSEC', 'POS'] if lanes is not None: columns += ['LANE\LINK\NO', 'LANE\INDEX'] @@ -727,7 +743,6 @@ data.sort(['$VEHICLE:SIMSEC'], inplace = True) nStationary = 0 - from matplotlib.pyplot import plot, figure nVehicles = 0 for name, group in data.groupby(['NO'], sort = False): nVehicles += 1 @@ -754,8 +769,9 @@ nCollisions = 0 for name, group in merged.groupby(['LANE\LINK\NO', 'LANE\INDEX', 'NO_x', 'NO_y']): - diff = group['POS_x']-group['POS_y'] - if len(diff) >= 2 and min(diff) < 0 and max(diff) > 0: + diff = group['POS_x'].convert_objects(convert_numeric=True)-group['POS_y'].convert_objects(convert_numeric=True) + # diff = group['POS_x']-group['POS_y'] # to check the impact of convert_objects and the possibility of using type conversion in read_csv or function to convert strings if any + if len(diff) >= 2 and npmin(diff) < 0 and npmax(diff) > 0: xidx = diff[diff < 0].argmax() yidx = diff[diff > 0].argmin() if abs(group.loc[xidx, '$VEHICLE:SIMSEC'] - group.loc[yidx, '$VEHICLE:SIMSEC']) <= collisionTimeDifference: @@ -874,7 +890,6 @@ def loadConfigFile(self, filename): from ConfigParser import ConfigParser - from numpy import loadtxt from os import path config = ConfigParser() @@ -901,7 +916,21 @@ self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps') # Classification parameters - + self.speedAggregationMethod = config.get(self.sectionHeader, 'speed-aggregation-method') + self.nFramesIgnoreAtEnds = config.getint(self.sectionHeader, 'nframes-ignore-at-ends') + self.speedAggregationQuantile = config.getint(self.sectionHeader, 'speed-aggregation-quantile') + self.minSpeedEquiprobable = config.getfloat(self.sectionHeader, 'min-speed-equiprobable') + self.minNPixels = config.getint(self.sectionHeader, 'min-npixels-crop') + self.pedBikeCarSVMFilename = config.get(self.sectionHeader, 'pbv-svm-filename') + self.bikeCarSVMFilename = config.get(self.sectionHeader, 'bv-svm-filename') + self.maxPedestrianSpeed = config.getfloat(self.sectionHeader, 'max-ped-speed') + self.maxCyclistSpeed = config.getfloat(self.sectionHeader, 'max-cyc-speed') + self.meanPedestrianSpeed = config.getfloat(self.sectionHeader, 'mean-ped-speed') + self.stdPedestrianSpeed = config.getfloat(self.sectionHeader, 'std-ped-speed') + self.locationCyclistSpeed = config.getfloat(self.sectionHeader, 'cyc-speed-loc') + self.scaleCyclistSpeed = config.getfloat(self.sectionHeader, 'cyc-speed-scale') + self.meanVehicleSpeed = config.getfloat(self.sectionHeader, 'mean-veh-speed') + self.stdVehicleSpeed = config.getfloat(self.sectionHeader, 'std-veh-speed') # Safety parameters self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate @@ -921,6 +950,26 @@ if filename is not None: self.loadConfigFile(filename) + def convertToFrames(self, speedRatio = 3.6): + '''Converts parameters with a relationship to time in 'native' frame time + speedRatio is the conversion from the speed unit in the config file + to the distance per second + + ie param(config file) = speedRatio x fps x param(used in program) + eg km/h = 3.6 (m/s to km/h) x frame/s x m/frame''' + denominator = self.videoFrameRate*speedRatio + denominator2 = denominator**2 + self.minSpeedEquiprobable = self.minSpeedEquiprobable/denominator + self.maxPedestrianSpeed = self.maxPedestrianSpeed/denominator + self.maxCyclistSpeed = self.maxCyclistSpeed/denominator + self.meanPedestrianSpeed = self.meanPedestrianSpeed/denominator + self.stdPedestrianSpeed = self.stdPedestrianSpeed/denominator + self.meanVehicleSpeed = self.meanVehicleSpeed/denominator + self.stdVehicleSpeed = self.stdVehicleSpeed/denominator + # special case for the lognormal distribution + self.locationCyclistSpeed = self.locationCyclistSpeed-log(denominator) + #self.scaleCyclistSpeed = self.scaleCyclistSpeed + class SceneParameters(object): def __init__(self, config, sectionName): from ConfigParser import NoOptionError
--- a/python/tests/moving.txt Wed Jul 22 14:17:19 2015 -0400 +++ b/python/tests/moving.txt Wed Jul 22 14:17:44 2015 -0400 @@ -167,13 +167,10 @@ >>> t.differentiate().empty() True ->>> o1 = MovingObject(positions = Trajectory([[0]*3,[2]*3]), velocities = Trajectory([[0]*3,[1]*3])) +>>> o1 = MovingObject.generate(Point(0., 2.), Point(0., 1.), TimeInterval(0,2)) >>> o1.classifyUserTypeSpeedMotorized(0.5, np.median) >>> userTypeNames[o1.getUserType()] 'car' ->>> o1.classifyUserTypeSpeedMotorized(0.5, np.mean) ->>> userTypeNames[o1.getUserType()] -'car' >>> o1.classifyUserTypeSpeedMotorized(1.5, np.median) >>> userTypeNames[o1.getUserType()] 'pedestrian'
--- a/python/tests/utils.txt Wed Jul 22 14:17:19 2015 -0400 +++ b/python/tests/utils.txt Wed Jul 22 14:17:44 2015 -0400 @@ -50,7 +50,7 @@ >>> mostCommon([range(2), range(4), range(2)]) [0, 1] ->>> lcss = LCSS(lambda x,y: abs(x-y) <= 0.1) +>>> lcss = LCSS(similarityFunc = lambda x,y: abs(x-y) <= 0.1) >>> lcss.compute(range(5), range(5)) 5 >>> lcss.compute(range(1,5), range(5)) @@ -59,8 +59,6 @@ 0 >>> lcss.compute(range(5), range(10)) 5 ->>> lcss.compute(range(5), range(10), 2) -5 >>> lcss.similarityFunc = lambda x,y: x == y >>> lcss.compute(['a','b','c'], ['a','b','c', 'd']) 3 @@ -117,3 +115,14 @@ 8 >>> lcss.subSequenceIndices [(2, 0), (4, 1), (6, 2), (7, 3), (8, 4), (9, 5), (11, 6), (13, 7)] + +>>> lcss = LCSS(metric = 'cityblock', epsilon = 0.1) +>>> lcss.compute([[i] for i in range(5)], [[i] for i in range(5)]) +5 +>>> lcss.compute([[i] for i in range(1,5)], [[i] for i in range(5)]) +4 +>>> lcss.compute([[i] for i in range(5,10)], [[i] for i in range(5)]) +0 +>>> lcss.compute([[i] for i in range(5)], [[i] for i in range(10)]) +5 +
--- a/python/utils.py Wed Jul 22 14:17:19 2015 -0400 +++ b/python/utils.py Wed Jul 22 14:17:44 2015 -0400 @@ -6,6 +6,7 @@ from datetime import time, datetime from math import sqrt, ceil, floor from scipy.stats import kruskal, shapiro +from scipy.spatial import distance from numpy import zeros, array, exp, sum as npsum, int as npint, arange, cumsum, median, isnan, ones, convolve, dtype, isnan, NaN, mean, ma @@ -26,6 +27,13 @@ # Simple statistics ######################### +def logNormalMeanVar(loc, scale): + '''location and scale are respectively the mean and standard deviation of the normal in the log-normal distribution + https://en.wikipedia.org/wiki/Log-normal_distribution''' + mean = exp(loc+(scale**2)/2) + var = (exp(loc**2)-1)*exp(2*loc+scale**2) + return mean, var + def sampleSize(stdev, tolerance, percentConfidence, printLatex = False): from scipy.stats.distributions import norm k = round(norm.ppf(0.5+percentConfidence/200., 0, 1)*100)/100. # 1.-(100-percentConfidence)/200. @@ -232,6 +240,7 @@ return ceil(v*tens)/tens def inBetween(bound1, bound2, x): + 'useful if one does not know the order of bound1/bound2' return bound1 <= x <= bound2 or bound2 <= x <= bound1 def pointDistanceL2(x1,y1,x2,y2): @@ -619,24 +628,55 @@ class LCSS(object): '''Class that keeps the LCSS parameters - and puts together the various computations''' - def __init__(self, similarityFunc, delta = float('inf'), aligned = False, lengthFunc = min): - self.similarityFunc = similarityFunc - self.aligned = aligned - self.delta = delta - self.lengthFunc = lengthFunc - self.subSequenceIndices = [(0,0)] + and puts together the various computations + + the methods with names starting with _ are not to be shadowed + in child classes, who will shadow the other methods, + ie compute and computeXX methods''' + def __init__(self, similarityFunc = None, metric = None, epsilon = None, delta = float('inf'), aligned = False, lengthFunc = min): + '''One should provide either a similarity function + that indicates (return bool) whether elements in the compares lists are similar + + eg distance(p1, p2) < epsilon + + or a type of metric usable in scipy.spatial.distance.cdist with an epsilon''' + if similarityFunc is None and metric is None: + print("No way to compute LCSS, similarityFunc and metric are None. Exiting") + import sys + sys.exit() + elif metric is not None and epsilon is None: + print("Please provide a value for epsilon if using a cdist metric. Exiting") + import sys + sys.exit() + else: + self.similarityFunc = similarityFunc + self.metric = metric + self.epsilon = epsilon + self.aligned = aligned + self.delta = delta + self.lengthFunc = lengthFunc + self.subSequenceIndices = [(0,0)] def similarities(self, l1, l2, jshift=0): n1 = len(l1) n2 = len(l2) self.similarityTable = zeros((n1+1,n2+1), dtype = npint) - for i in xrange(1,n1+1): - for j in xrange(max(1,i-jshift-self.delta),min(n2,i-jshift+self.delta)+1): - if self.similarityFunc(l1[i-1], l2[j-1]): - self.similarityTable[i,j] = self.similarityTable[i-1,j-1]+1 - else: - self.similarityTable[i,j] = max(self.similarityTable[i-1,j], self.similarityTable[i,j-1]) + if self.similarityFunc is not None: + for i in xrange(1,n1+1): + for j in xrange(max(1,i-jshift-self.delta),min(n2,i-jshift+self.delta)+1): + if self.similarityFunc(l1[i-1], l2[j-1]): + self.similarityTable[i,j] = self.similarityTable[i-1,j-1]+1 + else: + self.similarityTable[i,j] = max(self.similarityTable[i-1,j], self.similarityTable[i,j-1]) + elif self.metric is not None: + similarElements = distance.cdist(l1, l2, self.metric) <= self.epsilon + for i in xrange(1,n1+1): + for j in xrange(max(1,i-jshift-self.delta),min(n2,i-jshift+self.delta)+1): + if similarElements[i-1, j-1]: + self.similarityTable[i,j] = self.similarityTable[i-1,j-1]+1 + else: + self.similarityTable[i,j] = max(self.similarityTable[i-1,j], self.similarityTable[i,j-1]) + def subSequence(self, i, j): '''Returns the subsequence of two sequences @@ -652,12 +692,11 @@ def _compute(self, _l1, _l2, computeSubSequence = False): '''returns the longest common subsequence similarity - based on the threshold on distance between two elements of lists l1, l2 - similarityFunc returns True or False whether the two points are considered similar + l1 and l2 should be the right format + eg list of tuple points for cdist + or elements that can be compare using similarityFunc if aligned, returns the best matching if using a finite delta by shifting the series alignments - - eg distance(p1, p2) < epsilon ''' if len(_l2) < len(_l1): # l1 is the shortest l1 = _l2
--- a/scripts/classify-objects.py Wed Jul 22 14:17:19 2015 -0400 +++ b/scripts/classify-objects.py Wed Jul 22 14:17:44 2015 -0400 @@ -1,23 +1,116 @@ #! /usr/bin/env python +import cvutils, moving, ml, storage + import numpy as np import sys, argparse -from cv2 import SVM_RBF, SVM_C_SVC +#from cv2 import SVM_RBF, SVM_C_SVC +import cv2 +from scipy.stats import norm, lognorm -import cvutils, moving, ml +# TODO add mode detection live parser = argparse.ArgumentParser(description='The program processes indicators for all pairs of road users in the scene') parser.add_argument('--cfg', dest = 'configFilename', help = 'name of the configuration file', required = True) -parser.add_argument('-d', dest = 'directoryName', help = 'name of the parent directory containing the videos and extracted trajectories to process', required = True) -# parser.add_argument('-o', dest = 'homographyFilename', help = 'name of the image to world homography file') -# need a classification config file for speed distribution parameters, svm models, frequency parameters, area parameters etc -#parser.add_argument('--cfg', dest = 'svmType', help = 'SVM type', default = SVM_C_SVC, type = long) - - -#parser.add_argument('-s', dest = 'rescaleSize', help = 'rescale size of image samples', default = 64, type = int) -#parser.add_argument('-o', dest = 'nOrientations', help = 'number of orientations in HoG', default = 9, type = int) -#parser.add_argument('-p', dest = 'nPixelsPerCell', help = 'number of pixels per cell', default = 8, type = int) -#parser.add_argument('-c', dest = 'nCellsPerBlock', help = 'number of cells per block', default = 2, type = int) +parser.add_argument('-d', dest = 'databaseFilename', help = 'name of the Sqlite database file (overrides the configuration file)') +parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file (overrides the configuration file)') +parser.add_argument('-n', dest = 'nObjects', help = 'number of objects to classify', type = int, default = None) +parser.add_argument('--plot-speed-distributions', dest = 'plotSpeedDistribution', help = 'simply plots the distributions used for each user type', action = 'store_true') +parser.add_argument('--max-speed-distribution-plot', dest = 'maxSpeedDistributionPlot', help = 'if plotting the user distributions, the maximum speed to display', type = float, default = 50.) args = parser.parse_args() params = storage.ProcessParameters(args.configFilename) + +if args.videoFilename is not None: + videoFilename = args.videoFilename +else: + videoFilename = params.videoFilename +if args.databaseFilename is not None: + databaseFilename = args.databaseFilename +else: + databaseFilename = params.databaseFilename + +params.convertToFrames(3.6) +if params.homography is not None: + invHomography = np.linalg.inv(params.homography) + +if params.speedAggregationMethod == 'median': + speedAggregationFunc = np.median +elif params.speedAggregationMethod == 'mean': + speedAggregationFunc = np.mean +elif params.speedAggregationMethod == 'quantile': + speedAggregationFunc = lambda speeds: np.percentile(speeds, args.speedAggregationQuantile) +else: + print('Unknown speed aggregation method: {}. Exiting'.format(params.speedAggregationMethod)) + sys.exit() + +pedBikeCarSVM = ml.SVM() +pedBikeCarSVM.load(params.pedBikeCarSVMFilename) +bikeCarSVM = ml.SVM() +bikeCarSVM.load(params.bikeCarSVMFilename) + +# log logistic for ped and bik otherwise ((pedBeta/pedAlfa)*((sMean/pedAlfa)**(pedBeta-1)))/((1+(sMean/pedAlfa)**pedBeta)**2.) +speedProbabilities = {'car': lambda s: norm(params.meanVehicleSpeed, params.stdVehicleSpeed).pdf(s), + 'pedestrian': lambda s: norm(params.meanPedestrianSpeed, params.stdPedestrianSpeed).pdf(s), + 'bicycle': lambda s: lognorm(params.scaleCyclistSpeed, loc = 0., scale = np.exp(params.locationCyclistSpeed)).pdf(s)} # numpy lognorm shape, loc, scale: shape for numpy is scale (std of the normal) and scale for numpy is location (mean of the normal) + +if args.plotSpeedDistribution: + import matplotlib.pyplot as plt + plt.figure() + for k in speedProbabilities: + plt.plot(np.arange(0.1, args.maxSpeedDistributionPlot, 0.1), [speedProbabilities[k](s/3.6/25) for s in np.arange(0.1, args.maxSpeedDistributionPlot, 0.1)], label = k) + plt.xlabel('Speed (km/h)') + plt.ylabel('Probability') + plt.legend() + plt.title('Probability Density Function') + plt.show() + sys.exit() + +objects = storage.loadTrajectoriesFromSqlite(databaseFilename, 'object', args.nObjects, withFeatures = True) +#features = storage.loadTrajectoriesFromSqlite(databaseFilename, 'feature') +intervals = [] +for obj in objects: + #obj.setFeatures(features) + intervals.append(obj.getTimeInterval()) +timeInterval = moving.unionIntervals(intervals) + +capture = cv2.VideoCapture(videoFilename) +width = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)) +height = int(capture.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)) + +pastObjects = [] +if params.undistort: # setup undistortion + [map1, map2] = computeUndistortMaps(width, height, undistortedImageMultiplication, intrinsicCameraMatrix, distortionCoefficients) +if capture.isOpened(): + ret = True + frameNum = timeInterval.first + capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, frameNum) + lastFrameNum = timeInterval.last + + while ret and frameNum <= lastFrameNum: + ret, img = capture.read() + if ret: + if frameNum%50 == 0: + print('frame number: {}'.format(frameNum)) + currentObjects = [] + for obj in objects: + if obj.getLastInstant() < frameNum: + obj.classifyUserTypeHoGSVM(minSpeedEquiprobable = params.minSpeedEquiprobable, speedProbabilities = speedProbabilities) + pastObjects.append(obj) + else: + currentObjects.append(obj) + objects = currentObjects + if params.undistort: + img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR) + for obj in objects: + if obj.existsAtInstant(frameNum): + if obj.getFirstInstant() == frameNum: + obj.initClassifyUserTypeHoGSVM(speedAggregationFunc, pedBikeCarSVM, bikeCarSVM, params.maxPedestrianSpeed, params.maxCyclistSpeed, params.nFramesIgnoreAtEnds) + obj.classifyUserTypeHoGSVMAtInstant(img, frameNum, invHomography, width, height, 0.2, 0.2, 800) # px, py, pixelThreshold + frameNum += 1 + + for obj in objects: + obj.classifyUserTypeHoGSVM(minSpeedEquiprobable = params.minSpeedEquiprobable, speedProbabilities = speedProbabilities) + pastObjects.append(obj) + print('Saving user types') + storage.setRoadUserTypes(databaseFilename, pastObjects)
--- a/scripts/train-object-classification.py Wed Jul 22 14:17:19 2015 -0400 +++ b/scripts/train-object-classification.py Wed Jul 22 14:17:44 2015 -0400 @@ -36,31 +36,32 @@ for k, v in imageDirectories.iteritems(): print('Loading {} samples'.format(k)) - trainingSamplesPBV[k], trainingLabelsPBV[k] = cvutils.createHOGTrainingSet(v, moving.userType2Num[k], rescaleSize, args.nOrientations, nPixelsPerCell, nCellsPerBlock) + trainingSamples, trainingLabels = cvutils.createHOGTrainingSet(v, moving.userType2Num[k], rescaleSize, args.nOrientations, nPixelsPerCell, nCellsPerBlock) + trainingSamplesPBV[k], trainingLabelsPBV[k] = trainingSamples, trainingLabels if k != 'pedestrian': - trainingSamplesBV[k], trainingLabelsBV[k] = cvutils.createHOGTrainingSet(v, moving.userType2Num[k], rescaleSize, args.nOrientations, nPixelsPerCell, nCellsPerBlock) + trainingSamplesBV[k], trainingLabelsBV[k] = trainingSamples, trainingLabels if k != 'car': - trainingSamplesPB[k], trainingLabelsPB[k] = cvutils.createHOGTrainingSet(v, moving.userType2Num[k], rescaleSize, args.nOrientations, nPixelsPerCell, nCellsPerBlock) + trainingSamplesPB[k], trainingLabelsPB[k] = trainingSamples, trainingLabels if k != 'bicycle': - trainingSamplesPV[k], trainingLabelsPV[k] = cvutils.createHOGTrainingSet(v, moving.userType2Num[k], rescaleSize, args.nOrientations, nPixelsPerCell, nCellsPerBlock) + trainingSamplesPV[k], trainingLabelsPV[k] = trainingSamples, trainingLabels # Training the Support Vector Machine print "Training Pedestrian-Cyclist-Vehicle Model" -model = ml.SVM(args.svmType, args.kernelType) -model.train(np.concatenate(trainingSamplesPBV.values()), np.concatenate(trainingLabelsPBV.values())) +model = ml.SVM() +model.train(np.concatenate(trainingSamplesPBV.values()), np.concatenate(trainingLabelsPBV.values()), args.svmType, args.kernelType) model.save(args.directoryName + "/modelPBV.xml") print "Training Cyclist-Vehicle Model" -model = ml.SVM(args.svmType, args.kernelType) -model.train(np.concatenate(trainingSamplesBV.values()), np.concatenate(trainingLabelsBV.values())) +model = ml.SVM() +model.train(np.concatenate(trainingSamplesBV.values()), np.concatenate(trainingLabelsBV.values()), args.svmType, args.kernelType) model.save(args.directoryName + "/modelBV.xml") print "Training Pedestrian-Cyclist Model" -model = ml.SVM(args.svmType, args.kernelType) -model.train(np.concatenate(trainingSamplesPB.values()), np.concatenate(trainingLabelsPB.values())) +model = ml.SVM() +model.train(np.concatenate(trainingSamplesPB.values()), np.concatenate(trainingLabelsPB.values()), args.svmType, args.kernelType) model.save(args.directoryName + "/modelPB.xml") print "Training Pedestrian-Vehicle Model" -model = ml.SVM(args.svmType, args.kernelType) -model.train(np.concatenate(trainingSamplesPV.values()), np.concatenate(trainingLabelsPV.values())) +model = ml.SVM() +model.train(np.concatenate(trainingSamplesPV.values()), np.concatenate(trainingLabelsPV.values()), args.svmType, args.kernelType) model.save(args.directoryName + "/modelPV.xml")
--- a/scripts/uninstall-scripts.sh Wed Jul 22 14:17:19 2015 -0400 +++ b/scripts/uninstall-scripts.sh Wed Jul 22 14:17:44 2015 -0400 @@ -1,7 +1,15 @@ #!/bin/sh -installDirname='/usr/local/bin' +if [ $# -ge 1 ]; +then + installDirname=$1 + echo 'Removing from directory '$installDirname +else + installDirname='/usr/local/bin' + echo 'Removing from default directory '$installDirname +fi + for filename in * do echo 'rm '$installDirname/$filename rm $installDirname/$filename -done \ No newline at end of file +done
--- a/tracking.cfg Wed Jul 22 14:17:19 2015 -0400 +++ b/tracking.cfg Wed Jul 22 14:17:44 2015 -0400 @@ -81,23 +81,33 @@ # minimum average number of features per frame to create a vehicle hypothesis min-nfeatures-group = 3 # Road user classification +# min number of pixels in cropped image to classify by SVM +min-npixels-crop = 400 +# method to aggregate road user speed +speed-aggregation-method = median +# number of frames to ignore at both ends of a series (noisy) +nframes-ignore-at-ends = 2 +# quantile for the speed aggregation, if quantile is chosen +speed-aggregation-quantile = 50 +# speed value below which all classes are equiprobable (distributions give odd values there) (km/h) +min-speed-equiprobable = 3.33 # filename of the general ped/cyc/veh SVM classifier pbv-svm-filename = modelPBV.xml # filename of the cyc/veh SVM classifier -pbv-svm-filename = modelBV.xml -# maximum pedestrian speed (agregate: mean, median, 85th centile, etc.) 3.6 m/s -max-ped-speed = 0.12 -# maximum cyclist speed (agregate: mean, median, 85th centile, etc.) 10.8 m/s (3xped) -max-cyc-speed = 0.36 -# mean pedestrian speed and standard deviation (in a normal distribution) 1.36+-0.24 m/s -mean-ped-speed = 0.45 -std-ped-speed = 0.008 -# mean cyclist speed and standard deviation (in a log-normal distribution) 1.36+-0.24 m/s -mean-cyc-speed = 0.45 -std-cyc-speed = 0.008 -# mean vehicle speed and standard deviation (in a normal distribution) 5.12+-2.11 m/s -mean-veh-speed = 0.17 -std-veh-speed = 0.07 +bv-svm-filename = modelBV.xml +# maximum pedestrian speed (agregate: mean, median, 85th centile, etc.) 10 km/h +max-ped-speed = 10.0 +# maximum cyclist speed (agregate: mean, median, 85th centile, etc.) 30 km/h (3xped) +max-cyc-speed = 30.0 +# mean pedestrian speed and standard deviation (in a normal distribution) 4.91+-0.88 km/h +mean-ped-speed = 4.91 +std-ped-speed = 0.88 +# mean cyclist speed and standard deviation (in a log-normal distribution) 11.+-4.83 km/h +cyc-speed-loc = 2.31 +cyc-speed-scale = 0.42 +# mean vehicle speed and standard deviation (in a normal distribution) 18.45+-7.6 km/h +mean-veh-speed = 18.45 +std-veh-speed = 7.6 # Safety analysis # maximum speed when predicting future motion (km/h) max-predicted-speed = 50