comparison trafficintelligence/events.py @ 1267:ad60e5adf084

cleaned interaction categorization and added stationary category
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 29 May 2024 09:52:42 -0400
parents ebb18043616e
children ca70a79688ae
comparison
equal deleted inserted replaced
1266:ebb18043616e 1267:ad60e5adf084
194 cvutils.displayTrajectories(videoFilename, [self.roadUser1, self.roadUser2], homography = homography, firstFrameNum = firstFrameNum, lastFrameNumArg = lastFrameNum, undistort = undistort, intrinsicCameraMatrix = intrinsicCameraMatrix, distortionCoefficients = distortionCoefficients, undistortedImageMultiplication = undistortedImageMultiplication) 194 cvutils.displayTrajectories(videoFilename, [self.roadUser1, self.roadUser2], homography = homography, firstFrameNum = firstFrameNum, lastFrameNumArg = lastFrameNum, undistort = undistort, intrinsicCameraMatrix = intrinsicCameraMatrix, distortionCoefficients = distortionCoefficients, undistortedImageMultiplication = undistortedImageMultiplication)
195 else: 195 else:
196 print('Please set the interaction road user attributes roadUser1 and roadUser1 through the method setRoadUsers') 196 print('Please set the interaction road user attributes roadUser1 and roadUser1 through the method setRoadUsers')
197 197
198 def computeIndicators(self): 198 def computeIndicators(self):
199 '''Computes the collision course cosine only if the cosine is positive''' 199 '''Computes all cinematic indicators but the expensive safety indicators (TTC, PET)'''
200 collisionCourseDotProducts = {} 200 collisionCourseDotProducts = {}
201 collisionCourseAngles = {} 201 collisionCourseAngles = {}
202 velocityAngles = {} 202 velocityAngles = {}
203 distances = {} 203 distances = {}
204 speedDifferentials = {} 204 speedDifferentials = {}
231 self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[3], minDistances, mostSevereIsMax = False)) 231 self.addIndicator(indicators.SeverityIndicator(Interaction.indicatorNames[3], minDistances, mostSevereIsMax = False))
232 232
233 def categorize(self, velocityAngleTolerance, parallelAngleTolerance, headonCollisionCourseAngleTolerance = None, speedThreshold = 0.): 233 def categorize(self, velocityAngleTolerance, parallelAngleTolerance, headonCollisionCourseAngleTolerance = None, speedThreshold = 0.):
234 '''Computes the interaction category by instant 234 '''Computes the interaction category by instant
235 all 3 angle arguments in radian 235 all 3 angle arguments in radian
236 velocityAngleTolerance: indicates the angle threshold for rear and head on (180-velocityAngleTolerance), as well as the maximum collision course angle for head on (if headonCollisionCourseAngleTolerance is None) 236 velocityAngleTolerance: indicates the angle threshold for rear and head on (180-velocityAngleTolerance),
237 parallelAngleTolerance: indicates the angle between velocity vector (average for parallel) and position vector 237 as well as the maximum collision course angle for head on (if headonCollisionCourseAngleTolerance is None)
238 parallelAngleTolerance: indicates the tolerance on the expected 90 deg angle
239 between velocity vector (average for parallel) and position vector for a parallel interaction
240 speedThreshold defines stationary users: a stationary interaction is between one moving and
241 one stationary user, and their distance decreases
238 242
239 an instant may not be categorized if it matches the side definition (angle) 243 an instant may not be categorized if it matches the side definition (angle)
240 but the distance is growing (at least one user is probably past the point of trajectory crossing)''' 244 but the distance is growing (at least one user is probably past the point of trajectory crossing)'''
241 parallelAngleToleranceCosine = np.cos(parallelAngleTolerance) 245 minParallelAngleCosine = np.cos(np.pi/2+parallelAngleTolerance)
246 maxParallelAngleCosine = np.cos(np.pi/2-parallelAngleTolerance)
242 if headonCollisionCourseAngleTolerance is None: 247 if headonCollisionCourseAngleTolerance is None:
243 headonCollisionCourseAngleTolerance = velocityAngleTolerance 248 headonCollisionCourseAngleTolerance = velocityAngleTolerance
244 speedThreshold2 = speedThreshold**2 249 speedThreshold2 = speedThreshold**2
245 250
246 self.categories = {} 251 self.categories = {}
247 collisionCourseDotProducts = self.getIndicator(Interaction.indicatorNames[0]) 252 collisionCourseDotProducts = self.getIndicator(Interaction.indicatorNames[0])
248 collisionCourseAngles = self.getIndicator(Interaction.indicatorNames[1]) 253 collisionCourseAngles = self.getIndicator(Interaction.indicatorNames[1])
249 distances = self.getIndicator(Interaction.indicatorNames[2]) 254 distances = self.getIndicator(Interaction.indicatorNames[2])
250 velocityAngles = self.getIndicator(Interaction.indicatorNames[4]) 255 velocityAngles = self.getIndicator(Interaction.indicatorNames[4])
251 for instant in self.timeInterval: 256 for instant in self.timeInterval:
252 if instant in velocityAngles: 257 stationaryUser1 = self.roadUser1.getVelocityAtInstant(instant).norm2Squared() <= speedThreshold2
258 stationaryUser2 = self.roadUser2.getVelocityAtInstant(instant).norm2Squared() <= speedThreshold2
259 if stationaryUser1 != stationaryUser2 and collisionCourseDotProducts[instant] > 0: # only one is not moving and is getting closer
260 self.categories[instant] = Interaction.categories["stationary"]
261 # true stationary would be all the times (parked, difficult without semantic knowledge of the scene
262 # alternatively, one could get the previous or next non zero velocity to identify user orientation
263 elif velocityAngles.existsAtInstant(instant):
253 if velocityAngles[instant] < velocityAngleTolerance: # parallel or rear end 264 if velocityAngles[instant] < velocityAngleTolerance: # parallel or rear end
254 midVelocity = self.roadUser1.getVelocityAtInstant(instant) + self.roadUser2.getVelocityAtInstant(instant) 265 midVelocity = self.roadUser1.getVelocityAtInstant(instant) + self.roadUser2.getVelocityAtInstant(instant)
255 deltap = self.roadUser1.getPositionAtInstant(instant)-self.roadUser2.getPositionAtInstant(instant) 266 deltap = self.roadUser1.getPositionAtInstant(instant)-self.roadUser2.getPositionAtInstant(instant)
256 if abs(moving.Point.dot(midVelocity, deltap)/(midVelocity.norm2()*distances[instant])) < parallelAngleToleranceCosine: 267 if minParallelAngleCosine < abs(moving.Point.dot(midVelocity, deltap)/(midVelocity.norm2()*distances[instant])) < maxParallelAngleCosine:
257 self.categories[instant] = Interaction.categories["parallel"] 268 self.categories[instant] = Interaction.categories["parallel"]
258 else: 269 else:
259 self.categories[instant] = Interaction.categories["rearend"] 270 self.categories[instant] = Interaction.categories["rearend"]
260 elif velocityAngles[instant] > np.pi - velocityAngleTolerance and collisionCourseAngles[instant] < headonCollisionCourseAngleTolerance: # head on 271 elif velocityAngles[instant] > np.pi - velocityAngleTolerance and collisionCourseAngles[instant] < headonCollisionCourseAngleTolerance: # head on
261 self.categories[instant] = Interaction.categories["headon"] 272 self.categories[instant] = Interaction.categories["headon"]
262 elif collisionCourseDotProducts[instant] > 0: 273 elif collisionCourseDotProducts[instant] > 0:
263 self.categories[instant] = Interaction.categories["side"] 274 self.categories[instant] = Interaction.categories["side"]
264 # true stationary is when object does not move for the whole period of the interaction, otherwise get last (or next) velocity vector for user orientation 275 # true stationary is when object does not move for the whole period of the interaction, otherwise get last (or next) velocity vector for user orientation
265 # if instant not in self.categories: # if it's none of the other categories (could be with almost stationary vehicle) and only one speed is 0 276 # leaving is not a good interaction category (issue in Etienne's 2022 paper):
266 # stationaryUser1 = self.roadUser1.getVelocityAtInstant(instant).norm2Squared() <= speedThreshold2 277 # means we are past the situation in which users are approaching
267 # stationaryUser2 = self.roadUser2.getVelocityAtInstant(instant).norm2Squared() <= speedThreshold2
268 # if stationaryUser1 != stationaryUser2 and collisionCourseDotProducts[instant] > 0: # only one is not moving
269 # self.categories[instant] = Interaction.categories["stationary"]
270 # leaving is not a good interaction category (issue in Etienne's 2022 paper): means we are past the situation in which users are approaching
271 # could try to predict what happened before, but it's not observed 278 # could try to predict what happened before, but it's not observed
272 279
273 280
274 def computeCrossingsCollisions(self, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False, timeInterval = None): 281 def computeCrossingsCollisions(self, predictionParameters, collisionDistanceThreshold, timeHorizon, computeCZ = False, debug = False, timeInterval = None):
275 '''Computes all crossing and collision points at each common instant for two road users. ''' 282 '''Computes all crossing and collision points at each common instant for two road users. '''