Mercurial > hg > nsaunier > traffic-intelligence
comparison scripts/manual-video-analysis.py @ 890:85bcc758ee5b
new version to manual annotation, easy to configure to add new road user type and characteristics
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Tue, 28 Mar 2017 17:17:02 -0400 |
| parents | 4ea296ee1ae2 |
| children | ab3a4cb524a9 |
comparison
equal
deleted
inserted
replaced
| 889:4ea296ee1ae2 | 890:85bcc758ee5b |
|---|---|
| 1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
| 2 | 2 |
| 3 import sys, argparse, cv2 | 3 import sys, argparse, cv2, numpy as np |
| 4 | 4 |
| 5 parser = argparse.ArgumentParser(description=''''The program replays the video and allows to manually id vehicles and mark instants, eg when they cross given areas in the scene. Use this program in combination with a screen marker program (For example, Presentation Assistant) to draw multiple lines on the screen.''', | 5 parser = argparse.ArgumentParser(description=''''The program replays the video and allows to manually id vehicles and mark instants, eg when they cross given areas in the scene. Use this program in combination with a screen marker program (For example, Presentation Assistant) to draw multiple lines on the screen.''', |
| 6 epilog = '''The output should give you a .csv file with the same name as your video file with columns in this format: | 6 epilog = '''The output should give you a .csv file with the same name as your video file with columns in this format: |
| 7 vehicle number, frame number | 7 vehicle number, frame number |
| 8 You can easily spot mistakes in the csv file for a line with number, SKIP. If this happens, just delete the previous vehicle observation.''', | 8 You can easily spot mistakes in the csv file for a line with number, SKIP. If this happens, just delete the previous vehicle observation.''', |
| 9 formatter_class=argparse.RawDescriptionHelpFormatter) | 9 formatter_class=argparse.RawDescriptionHelpFormatter) |
| 10 parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file', required = True) | 10 parser.add_argument('-i', dest = 'videoFilename', help = 'name of the video file', required = True) |
| 11 parser.add_argument('-o', dest = 'outputFilename', help = 'name of the output file (csv file)') | 11 parser.add_argument('-o', dest = 'outputFilename', help = 'name of the output file (csv file)') |
| 12 parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to display', default = 0, type = int) | 12 parser.add_argument('-f', dest = 'firstFrameNum', help = 'number of first frame number to display', default = 0, type = int) |
| 13 parser.add_argument('-n', dest = 'nAttributes', help = 'number of attributes characterizing users', default = 0, type = int) | |
| 13 | 14 |
| 14 args = parser.parse_args() | 15 args = parser.parse_args() |
| 15 | 16 |
| 16 print('''Commands: | 17 print('''Commands: |
| 17 u: New vehicle crossing the first line | 18 Press o when you make a mistake in input |
| 18 i: Vehicle crossing subsequent lines | 19 Press d to skip 100 frames |
| 19 o: Press o when you make a mistake in input | 20 Press s to skip 10 frames |
| 20 p: Press p for a new pedestrian event (eg crossing) | 21 Press c to go back 100 frames |
| 21 d: Skip 100 frames | 22 Press x to go back 10 frames |
| 22 s: Skip 10 frames | 23 Press spacebar to go forward one frame |
| 23 c: Go back 100 frames | 24 Press l to skip to frame number |
| 24 x: Go back 10 frames | 25 Press Enter to finish inputting user characteristics (if any in pop up window) |
| 25 Spacebar: Go forward one frame | 26 Press q to quit and end program''') |
| 26 l: Skip to frame number | |
| 27 q: Quit and end program''') | |
| 28 # configuration of keys and user types (see moving) | 27 # configuration of keys and user types (see moving) |
| 29 userTypeNames = ['unknown', | 28 userTypeNames = ['unknown', |
| 30 'car', | 29 'car', |
| 31 'pedestrian', | 30 'pedestrian', |
| 32 'motorcycle', | 31 'motorcycle', |
| 33 'bicycle', | 32 'bicycle', |
| 34 'bus', | 33 'bus', |
| 35 'truck'] | 34 'truck'] |
| 36 class UserConfiguration(object): | 35 class UserConfiguration(object): |
| 37 def __init__(self, name, keyNew, keyAddInstant): | 36 def __init__(self, name, keyNew, keyAddInstant, nAttributes): |
| 38 self.name = name | 37 self.name = name |
| 39 self.keyNew = ord(keyNew) | 38 self.keyNew = ord(keyNew) |
| 40 self.keyAddInstant = ord(keyAddInstant) | 39 self.keyAddInstant = ord(keyAddInstant) |
| 41 self.userNum = 0 | 40 self.userNum = 0 |
| 41 self.nAttributes = nAttributes | |
| 42 self.resetAttributes() | |
| 43 | |
| 44 def getHelpStr(self): | |
| 45 return 'Press {} for new {}, {} for new instant for current {}'.format(chr(self.keyNew), self.name, chr(self.keyAddInstant), self.name) | |
| 46 | |
| 47 def resetAttributes(self): | |
| 42 self.userInstant = 0 | 48 self.userInstant = 0 |
| 49 self.attributes = [-1]*self.nAttributes | |
| 43 | 50 |
| 51 def setAttribute(self, i, value): | |
| 52 self.attributes[i%self.nAttributes] = value | |
| 53 | |
| 54 def getAttributeStr(self): | |
| 55 if self.nAttributes > 0: | |
| 56 return ','.join([str(i) for i in self.attributes])+',' | |
| 57 else: | |
| 58 return '' | |
| 59 | |
| 44 def isKeyNew(self, k): | 60 def isKeyNew(self, k): |
| 45 return (k == self.keyNew) | 61 return (k == self.keyNew) |
| 46 | 62 |
| 47 def isKeyAddInstant(self, k): | 63 def isKeyAddInstant(self, k): |
| 48 return (k == self.keyAddInstant) | 64 return (k == self.keyAddInstant) |
| 49 | 65 |
| 50 def isKey(self, k): | 66 def isKey(self, k): |
| 51 return self.isKeyNew() or self.isKeyAddInstant() | 67 return self.isKeyNew(k) or self.isKeyAddInstant(k) |
| 52 | 68 |
| 53 @staticmethod | 69 @staticmethod |
| 54 def isKey(configurations): | 70 def getConfigurationWithKey(configurations, k): |
| 55 for c in configurations: | 71 for c in configurations: |
| 56 if c.isKey(): | 72 if c.isKey(k): |
| 57 return c | 73 return c |
| 58 return None | 74 return None |
| 59 | 75 |
| 60 userConfigurations = [UserConfiguration(userTypeNames[1],1,'u','i'), | 76 userConfigurations = [UserConfiguration(userTypeNames[1],'u','i', args.nAttributes), |
| 61 UserConfiguration(userTypeNames[2],2,'j','k')] | 77 UserConfiguration(userTypeNames[2],'j','k', args.nAttributes)] |
| 78 | |
| 79 print(' ') | |
| 80 for c in userConfigurations: | |
| 81 print(c.getHelpStr()) | |
| 62 | 82 |
| 63 # start of program | 83 # start of program |
| 64 cap = cv2.VideoCapture(args.videoFilename) | 84 cap = cv2.VideoCapture(args.videoFilename) |
| 65 cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, args.firstFrameNum) | 85 cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, args.firstFrameNum) |
| 86 fps = cap.get(cv2.cv.CV_CAP_PROP_FPS) | |
| 87 print('Video at {} frames/s'.format(fps)) | |
| 66 cv2.namedWindow('Video', cv2.WINDOW_NORMAL) | 88 cv2.namedWindow('Video', cv2.WINDOW_NORMAL) |
| 67 | 89 |
| 68 # output filename | 90 # output filename |
| 69 if args.outputFilename is None: | 91 if args.outputFilename is None: |
| 70 i = args.videoFilename.rfind('.') | 92 i = args.videoFilename.rfind('.') |
| 87 key= cv2.waitKey(0) | 109 key= cv2.waitKey(0) |
| 88 | 110 |
| 89 if key == ord('q'): | 111 if key == ord('q'): |
| 90 break | 112 break |
| 91 else: | 113 else: |
| 92 config = UserConfiguration.isKey(userConfigurations) | 114 config = UserConfiguration.getConfigurationWithKey(userConfigurations, key) |
| 93 if config is not None: | 115 if config is not None: |
| 94 if c.isKeyNew(): | 116 if config.isKeyNew(key): |
| 95 pass # increment userNum | 117 config.userNum += 1 |
| 96 elif c.isKeyAddInstant(): | 118 config.resetAttributes() |
| 97 pass # increment userInstant | 119 print('New {} {}'.format(config.name, config.userNum)) |
| 98 # print/write | 120 if args.nAttributes > 0: |
| 99 | 121 key2 = ord('1') |
| 100 elif key == ord('u') or key == ord('i'): | 122 cv2.namedWindow('Input', cv2.WINDOW_NORMAL) |
| 101 if key == ord('u'): | 123 attributeNum = 0 |
| 102 vehNumber += 1 | 124 while key2 != ord('\n'): |
| 103 lineNum = 0 | 125 attrImg = 255*np.ones((20*args.nAttributes, 20, 3)) |
| 104 print('New Vehicle') | 126 for i in xrange(args.nAttributes): |
| 105 out.write('{},{}\n'.format(vehNumber,frameNum)) | 127 if i == (attributeNum%args.nAttributes): |
| 106 if vehNumber >= 1 and key == ord('i'): | 128 cv2.putText(attrImg, str(config.attributes[i]), (1,20*(i+1)), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255)) |
| 107 lineNum = lineNum+1 | 129 else: |
| 108 print('Line number {}'.format(lineNum)) | 130 cv2.putText(attrImg, str(config.attributes[i]), (1,20*(i+1)), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0)) |
| 109 elif key == ord('o'): | 131 cv2.imshow('Input', attrImg) |
| 110 out.write('{},SKIP\n'.format(vehNumber)) | 132 key2 = cv2.waitKey(0) |
| 111 print('SKIPPED') | 133 if chr(key2).isdigit(): |
| 112 elif key == ord('p'): | 134 config.setAttribute(attributeNum, chr(key2)) |
| 113 print("New Pedestrian") | 135 attributeNum += 1 |
| 114 out.write('Pedestrian,{}\n'.format(frameNum)) | 136 cv2.destroyWindow('Input') |
| 115 #Change the number of frames skipped or the keys in this section | 137 elif config.isKeyAddInstant(key): |
| 116 elif key == ord('d'): | 138 config.userInstant += 1 |
| 117 cap.set(1,frameNum+100) | 139 print('User {} no {} at line {}'.format(config.name, config.userNum, config.userInstant)) |
| 118 elif key == ord('s'): | 140 out.write('{},{},{}{}\n'.format(config.userNum, config.name, config.getAttributeStr(), config.userInstant)) |
| 119 cap.set(1,frameNum+10) | 141 oldUserConfig = config |
| 120 elif key == ord('a'): | 142 if key == ord('o'): |
| 121 cap.set(1,frameNum+1) | 143 print('SKIPPED') |
| 122 elif key == ord('x'): | 144 out.write('{},{},SKIP\n'.format(oldUserConfig.userNum, oldUserConfig.name)) |
| 123 cap.set(1,frameNum-10) | 145 elif key == ord('d'): |
| 124 elif key == ord('c'): | 146 cap.set(1,frameNum+100) |
| 125 cap.set(1,frameNum-100) | 147 elif key == ord('s'): |
| 126 elif key == ord('l'): | 148 cap.set(1,frameNum+10) |
| 127 frameNum = int(raw_input("Please enter the frame number you would like to skip to\n")) | 149 elif key == ord('a'): |
| 128 cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES,frameNum-5) | 150 cap.set(1,frameNum+1) |
| 151 elif key == ord('x'): | |
| 152 cap.set(1,frameNum-10) | |
| 153 elif key == ord('c'): | |
| 154 cap.set(1,frameNum-100) | |
| 155 elif key == ord('l'): | |
| 156 frameNum = int(raw_input("Please enter the frame number you would like to skip to\n")) | |
| 157 cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES,frameNum) | |
| 129 | 158 |
| 130 | 159 out.close() |
| 131 cap.release() | 160 cap.release() |
| 132 cv2.destroyAllWindows() | 161 cv2.destroyAllWindows() |
| 133 | 162 |
| 134 #97a | 163 #97a |
| 135 #115s | 164 #115s |
