Mercurial Hosting > 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 |