12
12
# locally if you don't want this happening!)
13
13
14
14
#Settings
15
- imgWidth = 640
16
- imgHeight = 424
17
15
buildPath = os .environ .get ("TRAVIS_BUILD_DIR" )
18
16
19
17
if buildPath is None :
20
18
print ()
21
19
print ("TRAVIS_BUILD_DIR environment variable was not found - is this running on TravisCI?" )
22
20
print ("If you want to test this locally, set TRAVIS_BUILD_DIR to the base directory of the cloned darkflow repository." )
23
21
exit ()
24
- testImgPath = os .path .join (buildPath , "sample_img" , "sample_person.jpg" )
25
- expectedDetectedObjectsV1 = [{"label" : "dog" ,"confidence" : 0.46 ,"topleft" : {"x" : 84 , "y" : 249 },"bottomright" : {"x" : 208 ,"y" : 367 }},
26
- {"label" : "person" ,"confidence" : 0.60 ,"topleft" : {"x" : 159 , "y" : 102 },"bottomright" : {"x" : 304 ,"y" : 365 }}]
27
22
28
- expectedDetectedObjectsV2 = [{"label" :"person" ,"confidence" :0.82 ,"topleft" :{"x" :189 ,"y" :96 },"bottomright" :{"x" :271 ,"y" :380 }},
29
- {"label" :"dog" ,"confidence" :0.79 ,"topleft" :{"x" :69 ,"y" :258 },"bottomright" :{"x" :209 ,"y" :354 }},
30
- {"label" :"horse" ,"confidence" :0.89 ,"topleft" :{"x" :397 ,"y" :127 },"bottomright" :{"x" :605 ,"y" :352 }}]
23
+ testImg = {"path" : os .path .join (buildPath , "sample_img" , "sample_person.jpg" ), "width" : 640 , "height" : 424 ,
24
+ "expected-objects" : {"yolo-small" : [{"label" : "dog" , "confidence" : 0.46 , "topleft" : {"x" : 84 , "y" : 249 }, "bottomright" : {"x" : 208 , "y" : 367 }},
25
+ {"label" : "person" , "confidence" : 0.60 , "topleft" : {"x" : 159 , "y" : 102 }, "bottomright" : {"x" : 304 , "y" : 365 }}],
26
+ "yolo" : [{"label" : "person" , "confidence" : 0.82 , "topleft" : {"x" : 189 , "y" : 96 }, "bottomright" : {"x" : 271 , "y" : 380 }},
27
+ {"label" : "dog" , "confidence" : 0.79 , "topleft" : {"x" : 69 , "y" : 258 }, "bottomright" : {"x" : 209 , "y" : 354 }},
28
+ {"label" : "horse" , "confidence" : 0.89 , "topleft" : {"x" : 397 , "y" : 127 }, "bottomright" : {"x" : 605 , "y" : 352 }}]}}
29
+
30
+ trainImgBikePerson = {"path" : os .path .join (buildPath , "test" , "training" , "images" , "1.jpg" ), "width" : 500 , "height" : 375 ,
31
+ "expected-objects" : {"tiny-yolo-voc-TRAINED" : [{"label" : "bicycle" , "confidence" : 0.46 , "topleft" : {"x" : 121 , "y" : 126 }, "bottomright" : {"x" : 234 , "y" : 244 }},
32
+ {"label" : "cow" , "confidence" : 0.54 , "topleft" : {"x" : 262 , "y" : 218 }, "bottomright" : {"x" : 385 , "y" : 311 }},
33
+ {"label" : "person" , "confidence" : 0.70 , "topleft" : {"x" : 132 , "y" : 34 }, "bottomright" : {"x" : 232 , "y" : 167 }}]}}
34
+
35
+ trainImgHorsePerson = {"path" : os .path .join (buildPath , "test" , "training" , "images" , "2.jpg" ), "width" : 500 , "height" : 332 ,
36
+ "expected-objects" : {"tiny-yolo-voc-TRAINED" : [{"label" : "horse" , "confidence" : 0.97 , "topleft" : {"x" : 157 , "y" : 95 }, "bottomright" : {"x" : 420 , "y" : 304 }},
37
+ {"label" : "person" , "confidence" : 0.89 , "topleft" : {"x" : 258 , "y" : 53 }, "bottomright" : {"x" : 300 , "y" : 218 }}]}}
38
+
39
+
31
40
posCompareThreshold = 0.05 #Comparisons must match be within 5% of width/height when compared to expected value
32
41
threshCompareThreshold = 0.1 #Comparisons must match within 0.1 of expected threshold for each prediction
33
- yoloDownloadV1 = "https://pjreddie.com/media/files/yolo-small.weights"
34
- yoloDownloadV2 = "https://pjreddie.com/media/files/yolo.weights"
42
+ yolo_small_Download = "https://pjreddie.com/media/files/yolo-small.weights" #YOLOv1
43
+ yolo_Download = "https://pjreddie.com/media/files/yolo.weights" #YOLOv2
44
+ tiny_yolo_voc_Download = "https://pjreddie.com/media/files/tiny-yolo-voc.weights" #YOLOv2
35
45
36
46
def download_file (url , savePath ):
37
47
fileName = savePath .split ("/" )[- 1 ]
@@ -47,19 +57,23 @@ def download_file(url, savePath):
47
57
else :
48
58
print ("Found existing " + fileName + " file." )
49
59
50
- yoloWeightPathV1 = os .path .join (buildPath , "bin" , yoloDownloadV1 .split ("/" )[- 1 ])
51
- yoloCfgPathV1 = os .path .join (buildPath , "cfg" , "v1" , "{0}.cfg" .format (os .path .splitext (os .path .basename (yoloWeightPathV1 ))[0 ]))
60
+ yolo_small_WeightPath = os .path .join (buildPath , "bin" , yolo_small_Download .split ("/" )[- 1 ])
61
+ yolo_small_CfgPath = os .path .join (buildPath , "cfg" , "v1" , "{0}.cfg" .format (os .path .splitext (os .path .basename (yolo_small_WeightPath ))[0 ]))
52
62
53
- yoloWeightPathV2 = os .path .join (buildPath , "bin" , yoloDownloadV2 .split ("/" )[- 1 ])
54
- yoloCfgPathV2 = os .path .join (buildPath , "cfg" , "{0}.cfg" .format (os .path .splitext (os .path .basename (yoloWeightPathV2 ))[0 ]))
63
+ yolo_WeightPath = os .path .join (buildPath , "bin" , yolo_Download .split ("/" )[- 1 ])
64
+ yolo_CfgPath = os .path .join (buildPath , "cfg" , "{0}.cfg" .format (os .path .splitext (os .path .basename (yolo_WeightPath ))[0 ]))
55
65
56
- pbPath = os .path .join (buildPath , "built_graph" , os .path .splitext (os .path .basename (yoloWeightPathV2 ))[0 ] + ".pb" )
57
- metaPath = os .path .join (buildPath , "built_graph" , os .path .splitext (os .path .basename (yoloWeightPathV2 ))[0 ] + ".meta" )
66
+ tiny_yolo_voc_WeightPath = os .path .join (buildPath , "bin" , tiny_yolo_voc_Download .split ("/" )[- 1 ])
67
+ tiny_yolo_voc_CfgPath = os .path .join (buildPath , "cfg" , "{0}.cfg" .format (os .path .splitext (os .path .basename (tiny_yolo_voc_WeightPath ))[0 ]))
68
+
69
+ pbPath = os .path .join (buildPath , "built_graph" , os .path .splitext (os .path .basename (yolo_WeightPath ))[0 ] + ".pb" )
70
+ metaPath = os .path .join (buildPath , "built_graph" , os .path .splitext (os .path .basename (yolo_WeightPath ))[0 ] + ".meta" )
58
71
59
72
generalConfigPath = os .path .join (buildPath , "cfg" )
60
73
61
- download_file (yoloDownloadV1 , yoloWeightPathV1 ) #Check if we need to download (and if so download) the YOLOv1 weights
62
- download_file (yoloDownloadV2 , yoloWeightPathV2 ) #Check if we need to download (and if so download) the YOLOv2 weights
74
+ download_file (yolo_small_Download , yolo_small_WeightPath ) #Check if we need to download (and if so download) the yolo-small weights (YOLOv1)
75
+ download_file (yolo_Download , yolo_WeightPath ) #Check if we need to download (and if so download) the yolo weights (YOLOv2)
76
+ download_file (tiny_yolo_voc_Download , tiny_yolo_voc_WeightPath ) #Check if we need to download (and if so download) the tiny-yolo-voc weights (YOLOv2)
63
77
64
78
def executeCLI (commandString ):
65
79
print ()
@@ -95,43 +109,45 @@ def compareObjectData(defaultObjects, newObjects, width, height):
95
109
return True
96
110
97
111
#Delete all images that won't be tested on so forwarding the whole folder doesn't take forever
98
- filelist = [f for f in os .listdir (os .path .dirname (testImgPath )) if os .path .isfile (os .path .join (os .path .dirname (testImgPath ), f )) and f != os .path .basename (testImgPath )]
112
+ filelist = [f for f in os .listdir (os .path .dirname (testImg [ "path" ] )) if os .path .isfile (os .path .join (os .path .dirname (testImg [ "path" ] ), f )) and f != os .path .basename (testImg [ "path" ] )]
99
113
for f in filelist :
100
- os .remove (os .path .join (os .path .dirname (testImgPath ), f ))
114
+ os .remove (os .path .join (os .path .dirname (testImg ["path" ]), f ))
115
+
101
116
117
+ #TESTS FOR INFERENCE
102
118
def test_CLI_IMG_YOLOv2 ():
103
119
#Test predictions outputted to an image using the YOLOv2 model through CLI
104
120
#NOTE: This test currently does not verify anything about the image created (i.e. proper labeling, proper positioning of prediction boxes, etc.)
105
121
# it simply verifies that the code executes properly and that the expected output image is indeed created in ./test/img/out
106
122
107
- testString = "flow --imgdir {0} --model {1} --load {2} --config {3} --threshold 0.4" .format (os .path .dirname (testImgPath ), yoloCfgPathV2 , yoloWeightPathV2 , generalConfigPath )
123
+ testString = "flow --imgdir {0} --model {1} --load {2} --config {3} --threshold 0.4" .format (os .path .dirname (testImg [ "path" ] ), yolo_CfgPath , yolo_WeightPath , generalConfigPath )
108
124
executeCLI (testString )
109
125
110
- outputImgPath = os .path .join (os .path .dirname (testImgPath ), "out" , os .path .basename (testImgPath ))
126
+ outputImgPath = os .path .join (os .path .dirname (testImg [ "path" ] ), "out" , os .path .basename (testImg [ "path" ] ))
111
127
assert os .path .exists (outputImgPath ), "Expected output image: {0} was not found." .format (outputImgPath )
112
128
113
129
def test_CLI_JSON_YOLOv2 ():
114
130
#Test predictions outputted to a JSON file using the YOLOv2 model through CLI
115
131
#NOTE: This test verifies that the code executes properly, the JSON file is created properly and the predictions generated are within a certain
116
132
# margin of error when compared to the expected predictions.
117
133
118
- testString = "flow --imgdir {0} --model {1} --load {2} --config {3} --threshold 0.4 --json" .format (os .path .dirname (testImgPath ), yoloCfgPathV2 , yoloWeightPathV2 , generalConfigPath )
134
+ testString = "flow --imgdir {0} --model {1} --load {2} --config {3} --threshold 0.4 --json" .format (os .path .dirname (testImg [ "path" ] ), yolo_CfgPath , yolo_WeightPath , generalConfigPath )
119
135
executeCLI (testString )
120
136
121
- outputJSONPath = os .path .join (os .path .dirname (testImgPath ), "out" , os .path .splitext (os .path .basename (testImgPath ))[0 ] + ".json" )
137
+ outputJSONPath = os .path .join (os .path .dirname (testImg [ "path" ] ), "out" , os .path .splitext (os .path .basename (testImg [ "path" ] ))[0 ] + ".json" )
122
138
assert os .path .exists (outputJSONPath ), "Expected output JSON file: {0} was not found." .format (outputJSONPath )
123
139
124
140
with open (outputJSONPath ) as json_file :
125
141
loadedPredictions = json .load (json_file )
126
142
127
- assert compareObjectData (expectedDetectedObjectsV2 , loadedPredictions , imgWidth , imgHeight ), "Generated object predictions from JSON were not within margin of error compared to expected values."
143
+ assert compareObjectData (testImg [ "expected-objects" ][ "yolo" ] , loadedPredictions , testImg [ "width" ], testImg [ "height" ] ), "Generated object predictions from JSON were not within margin of error compared to expected values."
128
144
129
145
def test_CLI_SAVEPB_YOLOv2 ():
130
146
#Save .pb and .meta as generated from the YOLOv2 model through CLI
131
- #NOTE: This test verifies that the code executes properly, and the .pb and .meta files are successfully created. A subsequent test will verify the
147
+ #NOTE: This test verifies that the code executes properly, and the .pb and .meta files are successfully created. The subsequent test will verify the
132
148
# contents of those files.
133
149
134
- testString = "flow --model {0} --load {1} --config {2} --threshold 0.4 --savepb" .format (yoloCfgPathV2 , yoloWeightPathV2 , generalConfigPath )
150
+ testString = "flow --model {0} --load {1} --config {2} --threshold 0.4 --savepb" .format (yolo_CfgPath , yolo_WeightPath , generalConfigPath )
135
151
136
152
with pytest .raises (SystemExit ):
137
153
executeCLI (testString )
@@ -146,18 +162,44 @@ def test_RETURNPREDICT_PBLOAD_YOLOv2():
146
162
147
163
options = {"pbLoad" : pbPath , "metaLoad" : metaPath , "threshold" : 0.4 }
148
164
tfnet = TFNet (options )
149
- imgcv = cv2 .imread (testImgPath )
165
+ imgcv = cv2 .imread (testImg [ "path" ] )
150
166
loadedPredictions = tfnet .return_predict (imgcv )
151
167
152
- assert compareObjectData (expectedDetectedObjectsV2 , loadedPredictions , imgWidth , imgHeight ), "Generated object predictions from return_predict() were not within margin of error compared to expected values."
168
+ assert compareObjectData (testImg [ "expected-objects" ][ "yolo" ] , loadedPredictions , testImg [ "width" ], testImg [ "height" ] ), "Generated object predictions from return_predict() were not within margin of error compared to expected values."
153
169
154
170
def test_RETURNPREDICT_YOLOv1 ():
155
171
#Test YOLOv1 using normal .weights and .cfg
156
172
#NOTE: This test verifies that the code executes properly, and that the predictions generated are within the accepted margin of error to the expected predictions.
157
173
158
- options = {"model" : yoloCfgPathV1 , "load" : yoloWeightPathV1 , "config" : generalConfigPath , "threshold" : 0.4 }
174
+ options = {"model" : yolo_small_CfgPath , "load" : yolo_small_WeightPath , "config" : generalConfigPath , "threshold" : 0.4 }
175
+ tfnet = TFNet (options )
176
+ imgcv = cv2 .imread (testImg ["path" ])
177
+ loadedPredictions = tfnet .return_predict (imgcv )
178
+
179
+ assert compareObjectData (testImg ["expected-objects" ]["yolo-small" ], loadedPredictions , testImg ["width" ], testImg ["height" ]), "Generated object predictions from return_predict() were not within margin of error compared to expected values."
180
+
181
+ #TESTS FOR TRAINING
182
+ def test_TRAIN_FROM_WEIGHTS_CLI__LOAD_CHECKPOINT_RETURNPREDICT_YOLOv2 ():
183
+ #Test training using pre-generated weights for tiny-yolo-voc
184
+ #NOTE: This test verifies that the code executes properly, and that the expected checkpoint file (tiny-yolo-voc-20.meta in this case) is generated.
185
+ # In addition, predictions are generated using the checkpoint file to verify that training completed successfully.
186
+
187
+ testString = "flow --model {0} --load {1} --train --dataset {2} --annotation {3} --epoch 20" .format (tiny_yolo_voc_CfgPath , tiny_yolo_voc_WeightPath , os .path .join (buildPath , "test" , "training" , "images" ), os .path .join (buildPath , "test" , "training" , "annotations" ))
188
+ with pytest .raises (SystemExit ):
189
+ executeCLI (testString )
190
+
191
+ checkpointPath = os .path .join (buildPath , "ckpt" , "tiny-yolo-voc-20.meta" )
192
+ assert os .path .exists (checkpointPath ), "Expected output checkpoint file: {0} was not found." .format (checkpointPath )
193
+
194
+ options = {"model" : tiny_yolo_voc_CfgPath , "load" : 20 , "config" : generalConfigPath , "threshold" : 0.4 }
159
195
tfnet = TFNet (options )
160
- imgcv = cv2 .imread (testImgPath )
196
+
197
+ #Make sure predictions match the expected values for image with bike and person
198
+ imgcv = cv2 .imread (trainImgBikePerson ["path" ])
161
199
loadedPredictions = tfnet .return_predict (imgcv )
200
+ assert compareObjectData (trainImgBikePerson ["expected-objects" ]["tiny-yolo-voc-TRAINED" ], loadedPredictions , trainImgBikePerson ["width" ], trainImgBikePerson ["height" ]), "Generated object predictions from training were not within margin of error compared to expected values for the image with the bike and person.\n Training may not have completed successfully."
162
201
163
- assert compareObjectData (expectedDetectedObjectsV1 , loadedPredictions , imgWidth , imgHeight ), "Generated object predictions from return_predict() were not within margin of error compared to expected values."
202
+ #Make sure predictions match the expected values for image with horse and person
203
+ imgcv = cv2 .imread (trainImgHorsePerson ["path" ])
204
+ loadedPredictions = tfnet .return_predict (imgcv )
205
+ assert compareObjectData (trainImgHorsePerson ["expected-objects" ]["tiny-yolo-voc-TRAINED" ], loadedPredictions , trainImgHorsePerson ["width" ], trainImgHorsePerson ["height" ]), "Generated object predictions from training were not within margin of error compared to expected values for the image with the bike and person.\n Training may not have completed successfully."
0 commit comments