PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/python/storage.py

https://bitbucket.org/mohamedgomaa/trafficintelligence
Python | 897 lines | 800 code | 62 blank | 35 comment | 62 complexity | 4b77e5f2d7d2c682434d25cfaced64f6 MD5 | raw file
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''Various utilities to save and load data'''
  4. import utils, moving, events, indicators
  5. import sqlite3, logging
  6. __metaclass__ = type
  7. commentChar = '#'
  8. delimiterChar = '%';
  9. ngsimUserTypes = {'twowheels':1,
  10. 'car':2,
  11. 'truck':3}
  12. #########################
  13. # Sqlite
  14. #########################
  15. # utils
  16. def printDBError(error):
  17. print('DB Error: {}'.format(error))
  18. def dropTables(connection, tableNames):
  19. 'deletes the table with names in tableNames'
  20. try:
  21. cursor = connection.cursor()
  22. for tableName in tableNames:
  23. cursor.execute('DROP TABLE IF EXISTS '+tableName)
  24. except sqlite3.OperationalError as error:
  25. printDBError(error)
  26. # TODO: add test if database connection is open
  27. # IO to sqlite
  28. def writeTrajectoriesToSqlite(objects, outputFilename, trajectoryType, objectNumbers = -1):
  29. """
  30. This function writers trajectories to a specified sqlite file
  31. @param[in] objects -> a list of trajectories
  32. @param[in] trajectoryType -
  33. @param[out] outputFilename -> the .sqlite file containting the written objects
  34. @param[in] objectNumber : number of objects loaded
  35. """
  36. connection = sqlite3.connect(outputFilename)
  37. cursor = connection.cursor()
  38. schema = "CREATE TABLE IF NOT EXISTS \"positions\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))"
  39. cursor.execute(schema)
  40. trajectory_id = 0
  41. frame_number = 0
  42. if trajectoryType == 'feature':
  43. if type(objectNumbers) == int and objectNumbers == -1:
  44. for trajectory in objects:
  45. trajectory_id += 1
  46. frame_number = 0
  47. for position in trajectory.getPositions():
  48. frame_number += 1
  49. query = "insert into positions (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)"
  50. cursor.execute(query,(trajectory_id,frame_number,position.x,position.y))
  51. connection.commit()
  52. connection.close()
  53. def writeFeaturesToSqlite(objects, outputFilename, trajectoryType, objectNumbers = -1):
  54. '''write features trajectories maintain trajectory ID,velocities dataset '''
  55. connection = sqlite3.connect(outputFilename)
  56. cursor = connection.cursor()
  57. cursor.execute("CREATE TABLE IF NOT EXISTS \"positions\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
  58. cursor.execute("CREATE TABLE IF NOT EXISTS \"velocities\"(trajectory_id INTEGER,frame_number INTEGER, x_coordinate REAL, y_coordinate REAL, PRIMARY KEY(trajectory_id, frame_number))")
  59. if trajectoryType == 'feature':
  60. if type(objectNumbers) == int and objectNumbers == -1:
  61. for trajectory in objects:
  62. trajectory_id = trajectory.num
  63. frame_number = trajectory.timeInterval.first
  64. for position,velocity in zip(trajectory.getPositions(),trajectory.getVelocities()):
  65. cursor.execute("insert into positions (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,position.x,position.y))
  66. cursor.execute("insert into velocities (trajectory_id, frame_number, x_coordinate, y_coordinate) values (?,?,?,?)",(trajectory_id,frame_number,velocity.x,velocity.y))
  67. frame_number += 1
  68. connection.commit()
  69. connection.close()
  70. def writePrototypesToSqlite(prototypes,nMatching, outputFilename):
  71. """ prototype dataset is a dictionary with keys== routes, values== prototypes Ids """
  72. connection = sqlite3.connect(outputFilename)
  73. cursor = connection.cursor()
  74. cursor.execute("CREATE TABLE IF NOT EXISTS \"prototypes\"(prototype_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, nMatching INTEGER, PRIMARY KEY(prototype_id))")
  75. for route in prototypes.keys():
  76. if prototypes[route]!=[]:
  77. for i in prototypes[route]:
  78. cursor.execute("insert into prototypes (prototype_id, routeIDstart,routeIDend, nMatching) values (?,?,?,?)",(i,route[0],route[1],nMatching[route][i]))
  79. connection.commit()
  80. connection.close()
  81. def loadPrototypesFromSqlite(filename):
  82. """
  83. This function loads the prototype file in the database
  84. It returns a dictionary for prototypes for each route and nMatching
  85. """
  86. prototypes = {}
  87. nMatching={}
  88. connection = sqlite3.connect(filename)
  89. cursor = connection.cursor()
  90. try:
  91. cursor.execute('SELECT * from prototypes order by prototype_id, routeIDstart,routeIDend, nMatching')
  92. except sqlite3.OperationalError as error:
  93. utils.printDBError(error)
  94. return []
  95. for row in cursor:
  96. route=(row[1],row[2])
  97. if route not in prototypes.keys():
  98. prototypes[route]=[]
  99. prototypes[route].append(row[0])
  100. nMatching[row[0]]=row[3]
  101. connection.close()
  102. return prototypes,nMatching
  103. def writeLabelsToSqlite(labels, outputFilename):
  104. """ labels is a dictionary with keys: routes, values: prototypes Ids
  105. """
  106. connection = sqlite3.connect(outputFilename)
  107. cursor = connection.cursor()
  108. cursor.execute("CREATE TABLE IF NOT EXISTS \"labels\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, prototype_id INTEGER, PRIMARY KEY(object_id))")
  109. for route in labels.keys():
  110. if labels[route]!=[]:
  111. for i in labels[route]:
  112. for j in labels[route][i]:
  113. cursor.execute("insert into labels (object_id, routeIDstart,routeIDend, prototype_id) values (?,?,?,?)",(j,route[0],route[1],i))
  114. connection.commit()
  115. connection.close()
  116. def loadLabelsFromSqlite(filename):
  117. labels = {}
  118. connection = sqlite3.connect(filename)
  119. cursor = connection.cursor()
  120. try:
  121. cursor.execute('SELECT * from labels order by object_id, routeIDstart,routeIDend, prototype_id')
  122. except sqlite3.OperationalError as error:
  123. utils.printDBError(error)
  124. return []
  125. for row in cursor:
  126. route=(row[1],row[2])
  127. p=row[3]
  128. if route not in labels.keys():
  129. labels[route]={}
  130. if p not in labels[route].keys():
  131. labels[route][p]=[]
  132. labels[route][p].append(row[0])
  133. connection.close()
  134. return labels
  135. def writeSpeedPrototypeToSqlite(prototypes,nmatching, outFilename):
  136. """ to match the format of second layer prototypes"""
  137. connection = sqlite3.connect(outFilename)
  138. cursor = connection.cursor()
  139. cursor.execute("CREATE TABLE IF NOT EXISTS \"speedprototypes\"(spdprototype_id INTEGER,prototype_id INTEGER,routeID_start INTEGER, routeID_end INTEGER, nMatching INTEGER, PRIMARY KEY(spdprototype_id))")
  140. for route in prototypes.keys():
  141. if prototypes[route]!={}:
  142. for i in prototypes[route]:
  143. if prototypes[route][i]!= []:
  144. for j in prototypes[route][i]:
  145. cursor.execute("insert into speedprototypes (spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching) values (?,?,?,?,?)",(j,i,route[0],route[1],nmatching[j]))
  146. connection.commit()
  147. connection.close()
  148. def loadSpeedPrototypeFromSqlite(filename):
  149. """
  150. This function loads the prototypes table in the database of name <filename>.
  151. """
  152. prototypes = {}
  153. nMatching={}
  154. connection = sqlite3.connect(filename)
  155. cursor = connection.cursor()
  156. try:
  157. cursor.execute('SELECT * from speedprototypes order by spdprototype_id,prototype_id, routeID_start, routeID_end, nMatching')
  158. except sqlite3.OperationalError as error:
  159. utils.printDBError(error)
  160. return []
  161. for row in cursor:
  162. route=(row[2],row[3])
  163. if route not in prototypes.keys():
  164. prototypes[route]={}
  165. if row[1] not in prototypes[route].keys():
  166. prototypes[route][row[1]]=[]
  167. prototypes[route][row[1]].append(row[0])
  168. nMatching[row[0]]=row[4]
  169. connection.close()
  170. return prototypes,nMatching
  171. def writeRoutesToSqlite(Routes, outputFilename):
  172. """ This function writes the activity path define by start and end IDs"""
  173. connection = sqlite3.connect(outputFilename)
  174. cursor = connection.cursor()
  175. cursor.execute("CREATE TABLE IF NOT EXISTS \"routes\"(object_id INTEGER,routeIDstart INTEGER,routeIDend INTEGER, PRIMARY KEY(object_id))")
  176. for route in Routes.keys():
  177. if Routes[route]!=[]:
  178. for i in Routes[route]:
  179. cursor.execute("insert into routes (object_id, routeIDstart,routeIDend) values (?,?,?)",(i,route[0],route[1]))
  180. connection.commit()
  181. connection.close()
  182. def loadRoutesFromSqlite(filename):
  183. Routes = {}
  184. connection = sqlite3.connect(filename)
  185. cursor = connection.cursor()
  186. try:
  187. cursor.execute('SELECT * from routes order by object_id, routeIDstart,routeIDend')
  188. except sqlite3.OperationalError as error:
  189. utils.printDBError(error)
  190. return []
  191. for row in cursor:
  192. route=(row[1],row[2])
  193. if route not in Routes.keys():
  194. Routes[route]=[]
  195. Routes[route].append(row[0])
  196. connection.close()
  197. return Routes
  198. def setRoutes(filename, objects):
  199. connection = sqlite3.connect(filename)
  200. cursor = connection.cursor()
  201. for obj in objects:
  202. cursor.execute('update objects set startRouteID = {} where object_id = {}'.format(obj.startRouteID, obj.getNum()))
  203. cursor.execute('update objects set endRouteID = {} where object_id = {}'.format(obj.endRouteID, obj.getNum()))
  204. connection.commit()
  205. connection.close()
  206. def setRoadUserTypes(filename, objects):
  207. '''Saves the user types of the objects in the sqlite database stored in filename
  208. The objects should exist in the objects table'''
  209. connection = sqlite3.connect(filename)
  210. cursor = connection.cursor()
  211. for obj in objects:
  212. cursor.execute('update objects set road_user_type = {} where object_id = {}'.format(obj.getUserType(), obj.getNum()))
  213. connection.commit()
  214. connection.close()
  215. def loadPrototypeMatchIndexesFromSqlite(filename):
  216. """
  217. This function loads the prototypes table in the database of name <filename>.
  218. It returns a list of tuples representing matching ids : [(prototype_id, matched_trajectory_id),...]
  219. """
  220. matched_indexes = []
  221. connection = sqlite3.connect(filename)
  222. cursor = connection.cursor()
  223. try:
  224. cursor.execute('SELECT * from prototypes order by prototype_id, trajectory_id_matched')
  225. except sqlite3.OperationalError as error:
  226. printDBError(error)
  227. return []
  228. for row in cursor:
  229. matched_indexes.append((row[0],row[1]))
  230. connection.close()
  231. return matched_indexes
  232. def getTrajectoryIdQuery(objectNumbers, trajectoryType):
  233. if trajectoryType == 'feature':
  234. statementBeginning = 'where trajectory_id '
  235. elif trajectoryType == 'object':
  236. statementBeginning = 'and OF.object_id '
  237. elif trajectoryType == 'bbtop' or 'bbbottom':
  238. statementBeginning = 'where object_id '
  239. else:
  240. print('no trajectory type was chosen')
  241. if objectNumbers is None:
  242. query = ''
  243. elif type(objectNumbers) == int:
  244. query = statementBeginning+'between 0 and {0} '.format(objectNumbers)
  245. elif type(objectNumbers) == list:
  246. query = statementBeginning+'in ('+', '.join([str(n) for n in objectNumbers])+') '
  247. return query
  248. def loadTrajectoriesFromTable(connection, tableName, trajectoryType, objectNumbers = None):
  249. '''Loads trajectories (in the general sense) from the given table
  250. can be positions or velocities
  251. returns a moving object'''
  252. cursor = connection.cursor()
  253. try:
  254. idQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
  255. if trajectoryType == 'feature':
  256. queryStatement = 'SELECT * from '+tableName+' '+idQuery+'ORDER BY trajectory_id, frame_number'
  257. cursor.execute(queryStatement)
  258. logging.debug(queryStatement)
  259. elif trajectoryType == 'object':
  260. 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'
  261. cursor.execute(queryStatement)
  262. logging.debug(queryStatement)
  263. elif trajectoryType in ['bbtop', 'bbbottom']:
  264. if trajectoryType == 'bbtop':
  265. corner = 'top_left'
  266. elif trajectoryType == 'bbbottom':
  267. corner = 'bottom_right'
  268. queryStatement = 'SELECT object_id, frame_number, x_'+corner+', y_'+corner+' FROM '+tableName+' '+idQuery+'ORDER BY object_id, frame_number'
  269. cursor.execute(queryStatement)
  270. logging.debug(queryStatement)
  271. else:
  272. print('no trajectory type was chosen')
  273. except sqlite3.OperationalError as error:
  274. printDBError(error)
  275. return []
  276. objId = -1
  277. obj = None
  278. objects = []
  279. for row in cursor:
  280. if row[0] != objId:
  281. objId = row[0]
  282. if obj != None and obj.length() == obj.positions.length():
  283. objects.append(obj)
  284. elif obj != None:
  285. print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length()))
  286. obj = moving.MovingObject(row[0], timeInterval = moving.TimeInterval(row[1], row[1]), positions = moving.Trajectory([[row[2]],[row[3]]]))
  287. else:
  288. obj.timeInterval.last = row[1]
  289. obj.positions.addPositionXY(row[2],row[3])
  290. if obj != None and obj.length() == obj.positions.length():
  291. objects.append(obj)
  292. elif obj != None:
  293. print('Object {} is missing {} positions'.format(obj.getNum(), int(obj.length())-obj.positions.length()))
  294. return objects
  295. def loadUserTypesFromTable(cursor, trajectoryType, objectNumbers):
  296. objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
  297. if objectIdQuery == '':
  298. cursor.execute('SELECT object_id, road_user_type from objects')
  299. else:
  300. cursor.execute('SELECT object_id, road_user_type from objects where '+objectIdQuery[7:])
  301. userTypes = {}
  302. for row in cursor:
  303. userTypes[row[0]] = row[1]
  304. return userTypes
  305. def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None):
  306. '''Loads the first objectNumbers objects or the indices in objectNumbers from the database'''
  307. connection = sqlite3.connect(filename)
  308. objects = loadTrajectoriesFromTable(connection, 'positions', trajectoryType, objectNumbers)
  309. objectVelocities = loadTrajectoriesFromTable(connection, 'velocities', trajectoryType, objectNumbers)
  310. if len(objectVelocities) > 0:
  311. for o,v in zip(objects, objectVelocities):
  312. if o.getNum() == v.getNum():
  313. o.velocities = v.positions
  314. o.velocities.duplicateLastPosition() # avoid having velocity shorter by one position than positions
  315. else:
  316. print('Could not match positions {0} with velocities {1}'.format(o.getNum(), v.getNum()))
  317. if trajectoryType == 'object':
  318. cursor = connection.cursor()
  319. try:
  320. # attribute feature numbers to objects
  321. objectIdQuery = getTrajectoryIdQuery(objectNumbers, trajectoryType)
  322. 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
  323. cursor.execute(queryStatement)
  324. logging.debug(queryStatement)
  325. featureNumbers = {}
  326. for row in cursor:
  327. objId = row[1]
  328. if objId not in featureNumbers:
  329. featureNumbers[objId] = [row[0]]
  330. else:
  331. featureNumbers[objId].append(row[0])
  332. for obj in objects:
  333. obj.featureNumbers = featureNumbers[obj.getNum()]
  334. # load userType
  335. userTypes = loadUserTypesFromTable(cursor, trajectoryType, objectNumbers)
  336. for obj in objects:
  337. obj.userType = userTypes[obj.getNum()]
  338. except sqlite3.OperationalError as error:
  339. printDBError(error)
  340. objects = []
  341. connection.close()
  342. return objects
  343. def loadGroundTruthFromSqlite(filename, gtType = 'bb', gtNumbers = None):
  344. 'Loads bounding box annotations (ground truth) from an SQLite '
  345. connection = sqlite3.connect(filename)
  346. gt = []
  347. if gtType == 'bb':
  348. topCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbtop', gtNumbers)
  349. bottomCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbbottom', gtNumbers)
  350. userTypes = loadUserTypesFromTable(connection.cursor(), 'object', gtNumbers) # string format is same as object
  351. for t, b in zip(topCorners, bottomCorners):
  352. num = t.getNum()
  353. if t.getNum() == b.getNum():
  354. annotation = moving.BBAnnotation(num, t.getTimeInterval(), t, b, userTypes[num])
  355. gt.append(annotation)
  356. else:
  357. print ('Unknown type of annotation {}'.format(gtType))
  358. connection.close()
  359. return gt
  360. def deleteFromSqlite(filename, dataType):
  361. 'Deletes (drops) some tables in the filename depending on type of data'
  362. import os
  363. if os.path.isfile(filename):
  364. connection = sqlite3.connect(filename)
  365. if dataType == 'object':
  366. dropTables(connection, ['objects', 'objects_features'])
  367. elif dataType == 'interaction':
  368. dropTables(connection, ['interactions', 'indicators'])
  369. elif dataType == 'bb':
  370. dropTables(connection, ['bounding_boxes'])
  371. else:
  372. print('Unknown data type {} to delete from database'.format(dataType))
  373. connection.close()
  374. else:
  375. print('{} does not exist'.format(filename))
  376. def createInteractionTable(cursor):
  377. cursor.execute('CREATE TABLE IF NOT EXISTS interactions (id INTEGER PRIMARY KEY, object_id1 INTEGER, object_id2 INTEGER, first_frame_number INTEGER, last_frame_number INTEGER, FOREIGN KEY(object_id1) REFERENCES objects(id), FOREIGN KEY(object_id2) REFERENCES objects(id))')
  378. def createIndicatorTables(cursor):
  379. # cursor.execute('CREATE TABLE IF NOT EXISTS indicators (id INTEGER PRIMARY KEY, interaction_id INTEGER, indicator_type INTEGER, FOREIGN KEY(interaction_id) REFERENCES interactions(id))')
  380. # cursor.execute('CREATE TABLE IF NOT EXISTS indicator_values (indicator_id INTEGER, frame_number INTEGER, value REAL, FOREIGN KEY(indicator_id) REFERENCES indicators(id), PRIMARY KEY(indicator_id, frame_number))')
  381. cursor.execute('CREATE TABLE IF NOT EXISTS indicators (interaction_id INTEGER, indicator_type INTEGER, frame_number INTEGER, value REAL, FOREIGN KEY(interaction_id) REFERENCES interactions(id), PRIMARY KEY(interaction_id, indicator_type, frame_number))')
  382. def saveInteraction(cursor, interaction):
  383. roadUserNumbers = list(interaction.getRoadUserNumbers())
  384. cursor.execute('INSERT INTO interactions VALUES({}, {}, {}, {}, {})'.format(interaction.getNum(), roadUserNumbers[0], roadUserNumbers[1], interaction.getFirstInstant(), interaction.getLastInstant()))
  385. def saveInteractions(filename, interactions):
  386. 'Saves the interactions in the table'
  387. connection = sqlite3.connect(filename)
  388. cursor = connection.cursor()
  389. try:
  390. createInteractionTable(cursor)
  391. for inter in interactions:
  392. saveInteraction(cursor, inter)
  393. except sqlite3.OperationalError as error:
  394. printDBError(error)
  395. connection.commit()
  396. connection.close()
  397. def saveIndicator(cursor, interactionNum, indicator):
  398. for instant in indicator.getTimeInterval():
  399. if indicator[instant]:
  400. cursor.execute('INSERT INTO indicators VALUES({}, {}, {}, {})'.format(interactionNum, events.Interaction.indicatorNameToIndices[indicator.getName()], instant, indicator[instant]))
  401. def saveIndicators(filename, interactions, indicatorNames = events.Interaction.indicatorNames):
  402. 'Saves the indicator values in the table'
  403. connection = sqlite3.connect(filename)
  404. cursor = connection.cursor()
  405. try:
  406. createInteractionTable(cursor)
  407. createIndicatorTables(cursor)
  408. for inter in interactions:
  409. saveInteraction(cursor, inter)
  410. for indicatorName in indicatorNames:
  411. indicator = inter.getIndicator(indicatorName)
  412. if indicator != None:
  413. saveIndicator(cursor, inter.getNum(), indicator)
  414. except sqlite3.OperationalError as error:
  415. printDBError(error)
  416. connection.commit()
  417. connection.close()
  418. def loadInteractions(filename):
  419. '''Loads interaction and their indicators
  420. TODO choose the interactions to load'''
  421. interactions = []
  422. connection = sqlite3.connect(filename)
  423. cursor = connection.cursor()
  424. try:
  425. 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')
  426. interactionNum = -1
  427. indicatorTypeNum = -1
  428. tmpIndicators = {}
  429. for row in cursor:
  430. if row[0] != interactionNum: # save interaction and create new interaction
  431. if interactionNum >= 0:
  432. interactions.append(events.Interaction(interactionNum, moving.TimeInterval(row[3],row[4]), roadUserNumbers[0], roadUserNumbers[1]))
  433. interactions[-1].indicators = tmpIndicators
  434. tmpIndicators = {}
  435. interactionNum = row[0]
  436. roadUserNumbers = row[1:3]
  437. if indicatorTypeNum != row[5]:
  438. if indicatorTypeNum >= 0:
  439. indicatorName = events.Interaction.indicatorNames[indicatorTypeNum]
  440. tmpIndicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues)
  441. indicatorTypeNum = row[5]
  442. indicatorValues = {row[6]:row[7]}
  443. else:
  444. indicatorValues[row[6]] = row[7]
  445. if interactionNum >= 0:
  446. if indicatorTypeNum >= 0:
  447. indicatorName = events.Interaction.indicatorNames[indicatorTypeNum]
  448. tmpIndicators[indicatorName] = indicators.SeverityIndicator(indicatorName, indicatorValues)
  449. interactions.append(events.Interaction(interactionNum, moving.TimeInterval(row[3],row[4]), roadUserNumbers[0], roadUserNumbers[1]))
  450. interactions[-1].indicators = tmpIndicators
  451. except sqlite3.OperationalError as error:
  452. printDBError(error)
  453. return []
  454. connection.close()
  455. return interactions
  456. # load first and last object instants
  457. # CREATE TEMP TABLE IF NOT EXISTS object_instants AS SELECT OF.object_id, min(frame_number) as first_instant, max(frame_number) as last_instant from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id group by OF.object_id order by OF.object_id
  458. def createBoundingBoxTable(filename, invHomography = None):
  459. '''Create the table to store the object bounding boxes in image space
  460. '''
  461. connection = sqlite3.connect(filename)
  462. cursor = connection.cursor()
  463. try:
  464. cursor.execute('CREATE TABLE IF NOT EXISTS bounding_boxes (object_id INTEGER, frame_number INTEGER, x_top_left REAL, y_top_left REAL, x_bottom_right REAL, y_bottom_right REAL, PRIMARY KEY(object_id, frame_number))')
  465. cursor.execute('INSERT INTO bounding_boxes SELECT object_id, frame_number, min(x), min(y), max(x), max(y) from '
  466. '(SELECT object_id, frame_number, (x*{}+y*{}+{})/w as x, (x*{}+y*{}+{})/w as y from '
  467. '(SELECT OF.object_id, P.frame_number, P.x_coordinate as x, P.y_coordinate as y, P.x_coordinate*{}+P.y_coordinate*{}+{} as w from positions P, objects_features OF where P.trajectory_id = OF.trajectory_id)) '.format(invHomography[0,0], invHomography[0,1], invHomography[0,2], invHomography[1,0], invHomography[1,1], invHomography[1,2], invHomography[2,0], invHomography[2,1], invHomography[2,2])+
  468. 'GROUP BY object_id, frame_number')
  469. except sqlite3.OperationalError as error:
  470. printDBError(error)
  471. connection.commit()
  472. connection.close()
  473. def loadBoundingBoxTableForDisplay(filename):
  474. connection = sqlite3.connect(filename)
  475. cursor = connection.cursor()
  476. boundingBoxes = {} # list of bounding boxes for each instant
  477. try:
  478. cursor.execute('SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'bounding_boxes\'')
  479. result = [row for row in cursor]
  480. if len(result) > 0:
  481. cursor.execute('SELECT * FROM bounding_boxes')
  482. for row in cursor:
  483. boundingBoxes.setdefault(row[1], []).append([moving.Point(row[2], row[3]), moving.Point(row[4], row[5])])
  484. except sqlite3.OperationalError as error:
  485. printDBError(error)
  486. return boundingBoxes
  487. connection.close()
  488. return boundingBoxes
  489. def loadBoundingBoxTable(filename):
  490. connection = sqlite3.connect(filename)
  491. cursor = connection.cursor()
  492. boundingBoxes = []
  493. try:
  494. pass
  495. except sqlite3.OperationalError as error:
  496. printDBError(error)
  497. return boundingBoxes
  498. connection.close()
  499. return boundingBoxes
  500. #########################
  501. # txt files
  502. #########################
  503. def openCheck(filename, option = 'r', quitting = False):
  504. '''Open file filename in read mode by default
  505. and checks it is open'''
  506. try:
  507. return open(filename, option)
  508. except IOError:
  509. print 'File %s could not be opened.' % filename
  510. if quitting:
  511. from sys import exit
  512. exit()
  513. return None
  514. def readline(f, commentCharacters = commentChar):
  515. '''Modified readline function to skip comments
  516. Can take a list of characters or a string (in will work in both)'''
  517. s = f.readline()
  518. while (len(s) > 0) and s[0] in commentCharacters:
  519. s = f.readline()
  520. return s.strip()
  521. def getLines(f, commentCharacters = commentChar):
  522. '''Gets a complete entry (all the lines) in between delimiterChar.'''
  523. dataStrings = []
  524. s = readline(f, commentCharacters)
  525. while len(s) > 0:
  526. dataStrings += [s.strip()]
  527. s = readline(f, commentCharacters)
  528. return dataStrings
  529. def writeList(filename, l):
  530. f = openCheck(filename, 'w')
  531. for x in l:
  532. f.write('{}\n'.format(x))
  533. f.close()
  534. def loadListStrings(filename, commentCharacters = commentChar):
  535. f = openCheck(filename, 'r')
  536. result = getLines(f, commentCharacters)
  537. f.close()
  538. return result
  539. def getValuesFromINIFile(filename, option, delimiterChar = '=', commentCharacters = commentChar):
  540. values = []
  541. for l in loadListStrings(filename, commentCharacters):
  542. if l.startswith(option):
  543. values.append(l.split(delimiterChar)[1].strip())
  544. return values
  545. class FakeSecHead(object):
  546. '''Add fake section header [asection]
  547. from http://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788
  548. use read_file in Python 3.2+
  549. '''
  550. def __init__(self, fp):
  551. self.fp = fp
  552. self.sechead = '[main]\n'
  553. def readline(self):
  554. if self.sechead:
  555. try: return self.sechead
  556. finally: self.sechead = None
  557. else: return self.fp.readline()
  558. def loadTrajectoriesFromVissimFile(filename, simulationStepsPerTimeUnit, nObjects = -1, warmUpLastInstant = None):
  559. '''Reads data from VISSIM .fzp trajectory file
  560. simulationStepsPerTimeUnit is the number of simulation steps per unit of time used by VISSIM
  561. for example, there seems to be 5 simulation steps per simulated second in VISSIM,
  562. so simulationStepsPerTimeUnit should be 5,
  563. so that all times correspond to the number of the simulation step (and can be stored as integers)
  564. Assumed to be sorted over time'''
  565. objects = {} # dictionary of objects index by their id
  566. firstInstants = {}
  567. inputfile = openCheck(filename, quitting = True)
  568. # data = pd.read_csv(filename, skiprows=15, delimiter=';')
  569. # skip header: 15 lines + 1
  570. line = readline(inputfile, '*$')
  571. while len(line) > 0:#for line in inputfile:
  572. data = line.strip().split(';')
  573. objNum = int(data[1])
  574. instant = int(float(data[0])*simulationStepsPerTimeUnit)
  575. s = float(data[4])
  576. y = float(data[5])
  577. lane = data[2]+'_'+data[3]
  578. if objNum not in firstInstants:
  579. firstInstants[objNum] = instant
  580. if warmUpLastInstant == None or firstInstants[objNum] >= warmUpLastInstant:
  581. if nObjects < 0 or len(objects) < nObjects:
  582. objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(instant, instant))
  583. objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory()
  584. if (warmUpLastInstant == None or firstInstants[objNum] >= warmUpLastInstant) and objNum in objects:
  585. objects[objNum].timeInterval.last = instant
  586. objects[objNum].curvilinearPositions.addPositionSYL(s, y, lane)
  587. line = readline(inputfile, '*$')
  588. return objects.values()
  589. def loadTrajectoriesFromNgsimFile(filename, nObjects = -1, sequenceNum = -1):
  590. '''Reads data from the trajectory data provided by NGSIM project
  591. and returns the list of Feature objects'''
  592. objects = []
  593. inputfile = openCheck(filename, quitting = True)
  594. def createObject(numbers):
  595. firstFrameNum = int(numbers[1])
  596. # do the geometry and usertype
  597. firstFrameNum = int(numbers[1])
  598. lastFrameNum = firstFrameNum+int(numbers[2])-1
  599. #time = moving.TimeInterval(firstFrameNum, firstFrameNum+int(numbers[2])-1)
  600. obj = moving.MovingObject(num = int(numbers[0]),
  601. timeInterval = moving.TimeInterval(firstFrameNum, lastFrameNum),
  602. positions = moving.Trajectory([[float(numbers[6])],[float(numbers[7])]]),
  603. userType = int(numbers[10]))
  604. obj.userType = int(numbers[10])
  605. obj.laneNums = [int(numbers[13])]
  606. obj.precedingVehicles = [int(numbers[14])] # lead vehicle (before)
  607. obj.followingVehicles = [int(numbers[15])] # following vehicle (after)
  608. obj.spaceHeadways = [float(numbers[16])] # feet
  609. obj.timeHeadways = [float(numbers[17])] # seconds
  610. obj.curvilinearPositions = moving.CurvilinearTrajectory([float(numbers[5])],[float(numbers[4])], obj.laneNums) # X is the longitudinal coordinate
  611. obj.speeds = [float(numbers[11])]
  612. obj.size = [float(numbers[8]), float(numbers[9])] # 8 lengh, 9 width # TODO: temporary, should use a geometry object
  613. return obj
  614. numbers = readline(inputfile).strip().split()
  615. if (len(numbers) > 0):
  616. obj = createObject(numbers)
  617. for line in inputfile:
  618. numbers = line.strip().split()
  619. if obj.getNum() != int(numbers[0]):
  620. # check and adapt the length to deal with issues in NGSIM data
  621. if (obj.length() != obj.positions.length()):
  622. print 'length pb with object %s (%d,%d)' % (obj.getNum(),obj.length(),obj.positions.length())
  623. obj.last = obj.getFirstInstant()+obj.positions.length()-1
  624. #obj.velocities = utils.computeVelocities(f.positions) # compare norm to speeds ?
  625. objects.append(obj)
  626. if (nObjects>0) and (len(objects)>=nObjects):
  627. break
  628. obj = createObject(numbers)
  629. else:
  630. obj.laneNums.append(int(numbers[13]))
  631. obj.positions.addPositionXY(float(numbers[6]), float(numbers[7]))
  632. obj.curvilinearPositions.addPositionSYL(float(numbers[5]), float(numbers[4]), obj.laneNums[-1])
  633. obj.speeds.append(float(numbers[11]))
  634. obj.precedingVehicles.append(int(numbers[14]))
  635. obj.followingVehicles.append(int(numbers[15]))
  636. obj.spaceHeadways.append(float(numbers[16]))
  637. obj.timeHeadways.append(float(numbers[17]))
  638. if (obj.size[0] != float(numbers[8])):
  639. print 'changed length obj %d' % (obj.getNum())
  640. if (obj.size[1] != float(numbers[9])):
  641. print 'changed width obj %d' % (obj.getNum())
  642. inputfile.close()
  643. return objects
  644. def convertNgsimFile(inputfile, outputfile, append = False, nObjects = -1, sequenceNum = 0):
  645. '''Reads data from the trajectory data provided by NGSIM project
  646. and converts to our current format.'''
  647. if append:
  648. out = openCheck(outputfile,'a')
  649. else:
  650. out = openCheck(outputfile,'w')
  651. nObjectsPerType = [0,0,0]
  652. features = loadNgsimFile(inputfile, sequenceNum)
  653. for f in features:
  654. nObjectsPerType[f.userType-1] += 1
  655. f.write(out)
  656. print nObjectsPerType
  657. out.close()
  658. def writePositionsToCsv(f, obj):
  659. timeInterval = obj.getTimeInterval()
  660. positions = obj.getPositions()
  661. curvilinearPositions = obj.getCurvilinearPositions()
  662. for i in xrange(int(obj.length())):
  663. p1 = positions[i]
  664. s = '{},{},{},{}'.format(obj.num,timeInterval[i],p1.x,p1.y)
  665. if curvilinearPositions != None:
  666. p2 = curvilinearPositions[i]
  667. s += ',{},{}'.format(p2[0],p2[1])
  668. f.write(s+'\n')
  669. def writeTrajectoriesToCsv(filename, objects):
  670. f = openCheck(filename, 'w')
  671. for i,obj in enumerate(objects):
  672. writePositionsToCsv(f, obj)
  673. f.close()
  674. #########################
  675. # Utils to read .ini type text files for configuration, meta data...
  676. #########################
  677. class ProcessParameters:
  678. '''Class for all parameters controlling data processing: input,
  679. method parameters, etc. for tracking, classification and safety
  680. Note: framerate is already taken into account'''
  681. def loadConfigFile(self, filename):
  682. from ConfigParser import ConfigParser
  683. from numpy import loadtxt
  684. from os import path
  685. config = ConfigParser()
  686. config.readfp(FakeSecHead(openCheck(filename)))
  687. self.sectionHeader = config.sections()[0]
  688. # Tracking/display parameters
  689. self.videoFilename = config.get(self.sectionHeader, 'video-filename')
  690. self.databaseFilename = config.get(self.sectionHeader, 'database-filename')
  691. self.homographyFilename = config.get(self.sectionHeader, 'homography-filename')
  692. if (path.exists(self.homographyFilename)):
  693. self.homography = loadtxt(self.homographyFilename)
  694. else:
  695. self.homography = None
  696. self.intrinsicCameraFilename = config.get(self.sectionHeader, 'intrinsic-camera-filename')
  697. if (path.exists(self.intrinsicCameraFilename)):
  698. self.intrinsicCameraMatrix = loadtxt(self.intrinsicCameraFilename)
  699. else:
  700. self.intrinsicCameraMatrix = None
  701. distortionCoefficients = getValuesFromINIFile(filename, 'distortion-coefficients', '=')
  702. self.distortionCoefficients = [float(x) for x in distortionCoefficients]
  703. self.undistortedImageMultiplication = config.getfloat(self.sectionHeader, 'undistorted-size-multiplication')
  704. self.undistort = config.getboolean(self.sectionHeader, 'undistort')
  705. self.firstFrameNum = config.getint(self.sectionHeader, 'frame1')
  706. self.videoFrameRate = config.getfloat(self.sectionHeader, 'video-fps')
  707. # Classification parameters
  708. # Safety parameters
  709. self.maxPredictedSpeed = config.getfloat(self.sectionHeader, 'max-predicted-speed')/3.6/self.videoFrameRate
  710. self.predictionTimeHorizon = config.getfloat(self.sectionHeader, 'prediction-time-horizon')*self.videoFrameRate
  711. self.collisionDistance = config.getfloat(self.sectionHeader, 'collision-distance')
  712. self.crossingZones = config.getboolean(self.sectionHeader, 'crossing-zones')
  713. self.predictionMethod = config.get(self.sectionHeader, 'prediction-method')
  714. self.nPredictedTrajectories = config.getint(self.sectionHeader, 'npredicted-trajectories')
  715. self.maxNormalAcceleration = config.getfloat(self.sectionHeader, 'max-normal-acceleration')/self.videoFrameRate**2
  716. self.maxNormalSteering = config.getfloat(self.sectionHeader, 'max-normal-steering')/self.videoFrameRate
  717. self.minExtremeAcceleration = config.getfloat(self.sectionHeader, 'min-extreme-acceleration')/self.videoFrameRate**2
  718. self.maxExtremeAcceleration = config.getfloat(self.sectionHeader, 'max-extreme-acceleration')/self.videoFrameRate**2
  719. self.maxExtremeSteering = config.getfloat(self.sectionHeader, 'max-extreme-steering')/self.videoFrameRate
  720. self.useFeaturesForPrediction = config.getboolean(self.sectionHeader, 'use-features-prediction')
  721. def __init__(self, filename = None):
  722. if filename != None:
  723. self.loadConfigFile(filename)
  724. class SceneParameters:
  725. def __init__(self, config, sectionName):
  726. from ConfigParser import NoOptionError
  727. from ast import literal_eval
  728. try:
  729. self.sitename = config.get(sectionName, 'sitename')
  730. self.databaseFilename = config.get(sectionName, 'data-filename')
  731. self.homographyFilename = config.get(sectionName, 'homography-filename')
  732. self.calibrationFilename = config.get(sectionName, 'calibration-filename')
  733. self.videoFilename = config.get(sectionName, 'video-filename')
  734. self.frameRate = config.getfloat(sectionName, 'framerate')
  735. self.date = datetime.strptime(config.get(sectionName, 'date'), datetimeFormat) # 2011-06-22 11:00:39
  736. self.translation = literal_eval(config.get(sectionName, 'translation')) # = [0.0, 0.0]
  737. self.rotation = config.getfloat(sectionName, 'rotation')
  738. self.duration = config.getint(sectionName, 'duration')
  739. except NoOptionError as e:
  740. print(e)
  741. print('Not a section for scene meta-data')
  742. @staticmethod
  743. def loadConfigFile(filename):
  744. from ConfigParser import ConfigParser
  745. config = ConfigParser()
  746. config.readfp(openCheck(filename))
  747. configDict = dict()
  748. for sectionName in config.sections():
  749. configDict[sectionName] = SceneParameters(config, sectionName)
  750. return configDict
  751. if __name__ == "__main__":
  752. import doctest
  753. import unittest
  754. suite = doctest.DocFileSuite('tests/storage.txt')
  755. unittest.TextTestRunner().run(suite)
  756. # #doctest.testmod()
  757. # #doctest.testfile("example.txt")