6 from tests_common import NewOpenCVTests, unittest
8 def normAssert(test, a, b, msg=None, lInf=1e-5):
9 test.assertLess(np.max(np.abs(a - b)), lInf, msg)
11 def inter_area(box1, box2):
12 x_min, x_max = max(box1[0], box2[0]), min(box1[2], box2[2])
13 y_min, y_max = max(box1[1], box2[1]), min(box1[3], box2[3])
14 return (x_max - x_min) * (y_max - y_min)
17 return (box[2] - box[0]) * (box[3] - box[1])
20 left, top = box[0], box[1]
21 width, height = box[2] - left, box[3] - top
22 return '[%f x %f from (%f, %f)]' % (width, height, left, top)
24 def normAssertDetections(test, refClassIds, refScores, refBoxes, testClassIds, testScores, testBoxes,
25 confThreshold=0.0, scores_diff=1e-5, boxes_iou_diff=1e-4):
26 matchedRefBoxes = [False] * len(refBoxes)
28 for i in range(len(testBoxes)):
29 testScore = testScores[i]
30 if testScore < confThreshold:
33 testClassId, testBox = testClassIds[i], testBoxes[i]
35 for j in range(len(refBoxes)):
36 if (not matchedRefBoxes[j]) and testClassId == refClassIds[j] and \
37 abs(testScore - refScores[j]) < scores_diff:
38 interArea = inter_area(testBox, refBoxes[j])
39 iou = interArea / (area(testBox) + area(refBoxes[j]) - interArea)
40 if abs(iou - 1.0) < boxes_iou_diff:
42 matchedRefBoxes[j] = True
44 errMsg += '\nUnmatched prediction: class %d score %f box %s' % (testClassId, testScore, box2str(testBox))
46 for i in range(len(refBoxes)):
47 if (not matchedRefBoxes[i]) and refScores[i] > confThreshold:
48 errMsg += '\nUnmatched reference: class %d score %f box %s' % (refClassIds[i], refScores[i], box2str(refBoxes[i]))
52 def printParams(backend, target):
54 cv.dnn.DNN_BACKEND_OPENCV: 'OCV',
55 cv.dnn.DNN_BACKEND_INFERENCE_ENGINE: 'DLIE'
58 cv.dnn.DNN_TARGET_CPU: 'CPU',
59 cv.dnn.DNN_TARGET_OPENCL: 'OCL',
60 cv.dnn.DNN_TARGET_OPENCL_FP16: 'OCL_FP16',
61 cv.dnn.DNN_TARGET_MYRIAD: 'MYRIAD'
63 print('%s/%s' % (backendNames[backend], targetNames[target]))
65 testdata_required = bool(os.environ.get('OPENCV_DNN_TEST_REQUIRE_TESTDATA', False))
67 g_dnnBackendsAndTargets = None
69 class dnn_test(NewOpenCVTests):
72 super(dnn_test, self).setUp()
74 global g_dnnBackendsAndTargets
75 if g_dnnBackendsAndTargets is None:
76 g_dnnBackendsAndTargets = self.initBackendsAndTargets()
77 self.dnnBackendsAndTargets = g_dnnBackendsAndTargets
79 def initBackendsAndTargets(self):
80 self.dnnBackendsAndTargets = [
81 [cv.dnn.DNN_BACKEND_OPENCV, cv.dnn.DNN_TARGET_CPU],
84 if self.checkIETarget(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_CPU):
85 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_CPU])
86 if self.checkIETarget(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_MYRIAD):
87 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_MYRIAD])
89 if cv.ocl.haveOpenCL() and cv.ocl.useOpenCL():
90 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_OPENCV, cv.dnn.DNN_TARGET_OPENCL])
91 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_OPENCV, cv.dnn.DNN_TARGET_OPENCL_FP16])
92 if cv.ocl_Device.getDefault().isIntel():
93 if self.checkIETarget(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_OPENCL):
94 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_OPENCL])
95 if self.checkIETarget(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_OPENCL_FP16):
96 self.dnnBackendsAndTargets.append([cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_TARGET_OPENCL_FP16])
97 return self.dnnBackendsAndTargets
99 def find_dnn_file(self, filename, required=True):
101 required = testdata_required
102 return self.find_file(filename, [os.environ.get('OPENCV_DNN_TEST_DATA_PATH', os.getcwd()),
103 os.environ['OPENCV_TEST_DATA_PATH']],
106 def checkIETarget(self, backend, target):
107 proto = self.find_dnn_file('dnn/layers/layer_convolution.prototxt')
108 model = self.find_dnn_file('dnn/layers/layer_convolution.caffemodel')
109 net = cv.dnn.readNet(proto, model)
110 net.setPreferableBackend(backend)
111 net.setPreferableTarget(target)
112 inp = np.random.standard_normal([1, 2, 10, 11]).astype(np.float32)
116 except BaseException as e:
120 def test_getAvailableTargets(self):
121 targets = cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_OPENCV)
122 self.assertTrue(cv.dnn.DNN_TARGET_CPU in targets)
124 def test_blobFromImage(self):
132 # Test arguments names.
133 img = np.random.randint(0, 255, [4, 5, 3]).astype(np.uint8)
134 blob = cv.dnn.blobFromImage(img, scale, (width, height), mean, True, False)
135 blob_args = cv.dnn.blobFromImage(img, scalefactor=scale, size=(width, height),
136 mean=mean, swapRB=True, crop=False)
137 normAssert(self, blob, blob_args)
140 target = cv.resize(img, (width, height), interpolation=cv.INTER_LINEAR)
141 target = target.astype(np.float32)
142 target = target[:,:,[2, 1, 0]] # BGR2RGB
143 target[:,:,0] -= mean[0]
144 target[:,:,1] -= mean[1]
145 target[:,:,2] -= mean[2]
147 target = target.transpose(2, 0, 1).reshape(1, 3, height, width) # to NCHW
148 normAssert(self, blob, target)
151 def test_model(self):
152 img_path = self.find_dnn_file("dnn/street.png")
153 weights = self.find_dnn_file("dnn/MobileNetSSD_deploy.caffemodel", required=False)
154 config = self.find_dnn_file("dnn/MobileNetSSD_deploy.prototxt", required=False)
155 if weights is None or config is None:
156 raise unittest.SkipTest("Missing DNN test files (dnn/MobileNetSSD_deploy.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
158 frame = cv.imread(img_path)
159 model = cv.dnn_DetectionModel(weights, config)
160 model.setInputParams(size=(300, 300), mean=(127.5, 127.5, 127.5), scale=1.0/127.5)
163 confThreshold = 0.0001
167 classIds, confidences, boxes = model.detect(frame, confThreshold, nmsThreshold)
169 refClassIds = (7, 15)
170 refConfidences = (0.9998, 0.8793)
171 refBoxes = ((328, 238, 85, 102), (101, 188, 34, 138))
173 normAssertDetections(self, refClassIds, refConfidences, refBoxes,
174 classIds, confidences, boxes,confThreshold, scoreDiff, iouDiff)
177 cv.rectangle(frame, box, (0, 255, 0))
178 cv.rectangle(frame, np.array(box), (0, 255, 0))
179 cv.rectangle(frame, tuple(box), (0, 255, 0))
180 cv.rectangle(frame, list(box), (0, 255, 0))
183 def test_classification_model(self):
184 img_path = self.find_dnn_file("dnn/googlenet_0.png")
185 weights = self.find_dnn_file("dnn/squeezenet_v1.1.caffemodel", required=False)
186 config = self.find_dnn_file("dnn/squeezenet_v1.1.prototxt")
187 ref = np.load(self.find_dnn_file("dnn/squeezenet_v1.1_prob.npy"))
188 if weights is None or config is None:
189 raise unittest.SkipTest("Missing DNN test files (dnn/squeezenet_v1.1.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
191 frame = cv.imread(img_path)
192 model = cv.dnn_ClassificationModel(config, weights)
193 model.setInputSize(227, 227)
194 model.setInputCrop(True)
196 out = model.predict(frame)
197 normAssert(self, out, ref)
200 def test_face_detection(self):
201 proto = self.find_dnn_file('dnn/opencv_face_detector.prototxt')
202 model = self.find_dnn_file('dnn/opencv_face_detector.caffemodel', required=False)
203 if proto is None or model is None:
204 raise unittest.SkipTest("Missing DNN test files (dnn/opencv_face_detector.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
206 img = self.get_sample('gpu/lbpcascade/er.png')
207 blob = cv.dnn.blobFromImage(img, mean=(104, 177, 123), swapRB=False, crop=False)
209 ref = [[0, 1, 0.99520785, 0.80997437, 0.16379407, 0.87996572, 0.26685631],
210 [0, 1, 0.9934696, 0.2831718, 0.50738752, 0.345781, 0.5985168],
211 [0, 1, 0.99096733, 0.13629119, 0.24892329, 0.19756334, 0.3310290],
212 [0, 1, 0.98977017, 0.23901358, 0.09084064, 0.29902688, 0.1769477],
213 [0, 1, 0.97203469, 0.67965847, 0.06876482, 0.73999709, 0.1513494],
214 [0, 1, 0.95097077, 0.51901293, 0.45863652, 0.5777427, 0.5347801]]
217 for backend, target in self.dnnBackendsAndTargets:
218 printParams(backend, target)
220 net = cv.dnn.readNet(proto, model)
221 net.setPreferableBackend(backend)
222 net.setPreferableTarget(target)
224 out = net.forward().reshape(-1, 7)
226 scoresDiff = 4e-3 if target in [cv.dnn.DNN_TARGET_OPENCL_FP16, cv.dnn.DNN_TARGET_MYRIAD] else 1e-5
227 iouDiff = 2e-2 if target in [cv.dnn.DNN_TARGET_OPENCL_FP16, cv.dnn.DNN_TARGET_MYRIAD] else 1e-4
229 ref = np.array(ref, np.float32)
230 refClassIds, testClassIds = ref[:, 1], out[:, 1]
231 refScores, testScores = ref[:, 2], out[:, 2]
232 refBoxes, testBoxes = ref[:, 3:], out[:, 3:]
234 normAssertDetections(self, refClassIds, refScores, refBoxes, testClassIds,
235 testScores, testBoxes, 0.5, scoresDiff, iouDiff)
237 def test_async(self):
238 timeout = 10*1000*10**6 # in nanoseconds (10 sec)
239 proto = self.find_dnn_file('dnn/layers/layer_convolution.prototxt')
240 model = self.find_dnn_file('dnn/layers/layer_convolution.caffemodel')
241 if proto is None or model is None:
242 raise unittest.SkipTest("Missing DNN test files (dnn/layers/layer_convolution.{prototxt/caffemodel}). Verify OPENCV_DNN_TEST_DATA_PATH configuration parameter.")
245 for backend, target in self.dnnBackendsAndTargets:
246 if backend != cv.dnn.DNN_BACKEND_INFERENCE_ENGINE:
249 printParams(backend, target)
251 netSync = cv.dnn.readNet(proto, model)
252 netSync.setPreferableBackend(backend)
253 netSync.setPreferableTarget(target)
255 netAsync = cv.dnn.readNet(proto, model)
256 netAsync.setPreferableBackend(backend)
257 netAsync.setPreferableTarget(target)
262 for _ in range(numInputs):
263 inputs.append(np.random.standard_normal([2, 6, 75, 113]).astype(np.float32))
267 for i in range(numInputs):
268 netSync.setInput(inputs[i])
269 refs.append(netSync.forward())
271 # Run asynchronously. To make test more robust, process inputs in the reversed order.
273 for i in reversed(range(numInputs)):
274 netAsync.setInput(inputs[i])
275 outs.insert(0, netAsync.forwardAsync())
277 for i in reversed(range(numInputs)):
278 ret, result = outs[i].get(timeoutNs=float(timeout))
280 normAssert(self, refs[i], result, 'Index: %d' % i, 1e-10)
284 rects = ((0, 0, 0.4, 0.4), (0, 0, 0.2, 0.4)) # 0.5 overlap
286 self.assertTrue(all(cv.dnn.NMSBoxes(rects, confs, 0, 0.6).ravel() == (0, 1)))
288 def test_custom_layer(self):
289 class CropLayer(object):
290 def __init__(self, params, blobs):
295 # Our layer receives two inputs. We need to crop the first input blob
296 # to match a shape of the second one (keeping batch size and number of channels)
297 def getMemoryShapes(self, inputs):
298 inputShape, targetShape = inputs[0], inputs[1]
299 batchSize, numChannels = inputShape[0], inputShape[1]
300 height, width = targetShape[2], targetShape[3]
301 self.ystart = (inputShape[2] - targetShape[2]) // 2
302 self.xstart = (inputShape[3] - targetShape[3]) // 2
303 self.yend = self.ystart + height
304 self.xend = self.xstart + width
305 return [[batchSize, numChannels, height, width]]
306 def forward(self, inputs):
307 return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]]
309 cv.dnn_registerLayer('CropCaffe', CropLayer)
336 net = cv.dnn.readNetFromCaffe(bytearray(proto.encode()))
337 for backend, target in self.dnnBackendsAndTargets:
338 if backend != cv.dnn.DNN_BACKEND_OPENCV:
341 printParams(backend, target)
343 net.setPreferableBackend(backend)
344 net.setPreferableTarget(target)
345 src_shape = [1, 2, 5, 5]
346 dst_shape = [1, 2, 3, 3]
347 inp = np.arange(0, np.prod(src_shape), dtype=np.float32).reshape(src_shape)
348 roi = np.empty(dst_shape, dtype=np.float32)
349 net.setInput(inp, "input")
350 net.setInput(roi, "roi")
352 ref = inp[:, :, 1:4, 1:4]
353 normAssert(self, out, ref)
355 cv.dnn_unregisterLayer('CropCaffe')
357 if __name__ == '__main__':
358 NewOpenCVTests.bootstrap()