You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

824 lines
35 KiB

6 years ago
  1. # Copyright 2017 The TensorFlow Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # ==============================================================================
  15. """Tests for object_detection.utils.object_detection_evaluation."""
  16. from absl.testing import parameterized
  17. import numpy as np
  18. import tensorflow as tf
  19. from object_detection import eval_util
  20. from object_detection.core import standard_fields
  21. from object_detection.utils import object_detection_evaluation
  22. class OpenImagesV2EvaluationTest(tf.test.TestCase):
  23. def test_returns_correct_metric_values(self):
  24. categories = [{
  25. 'id': 1,
  26. 'name': 'cat'
  27. }, {
  28. 'id': 2,
  29. 'name': 'dog'
  30. }, {
  31. 'id': 3,
  32. 'name': 'elephant'
  33. }]
  34. oiv2_evaluator = object_detection_evaluation.OpenImagesDetectionEvaluator(
  35. categories)
  36. image_key1 = 'img1'
  37. groundtruth_boxes1 = np.array(
  38. [[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]], dtype=float)
  39. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  40. oiv2_evaluator.add_single_ground_truth_image_info(image_key1, {
  41. standard_fields.InputDataFields.groundtruth_boxes:
  42. groundtruth_boxes1,
  43. standard_fields.InputDataFields.groundtruth_classes:
  44. groundtruth_class_labels1,
  45. standard_fields.InputDataFields.groundtruth_group_of:
  46. np.array([], dtype=bool)
  47. })
  48. image_key2 = 'img2'
  49. groundtruth_boxes2 = np.array(
  50. [[10, 10, 11, 11], [500, 500, 510, 510], [10, 10, 12, 12]], dtype=float)
  51. groundtruth_class_labels2 = np.array([1, 1, 3], dtype=int)
  52. groundtruth_is_group_of_list2 = np.array([False, True, False], dtype=bool)
  53. oiv2_evaluator.add_single_ground_truth_image_info(image_key2, {
  54. standard_fields.InputDataFields.groundtruth_boxes:
  55. groundtruth_boxes2,
  56. standard_fields.InputDataFields.groundtruth_classes:
  57. groundtruth_class_labels2,
  58. standard_fields.InputDataFields.groundtruth_group_of:
  59. groundtruth_is_group_of_list2
  60. })
  61. image_key3 = 'img3'
  62. groundtruth_boxes3 = np.array([[0, 0, 1, 1]], dtype=float)
  63. groundtruth_class_labels3 = np.array([2], dtype=int)
  64. oiv2_evaluator.add_single_ground_truth_image_info(image_key3, {
  65. standard_fields.InputDataFields.groundtruth_boxes:
  66. groundtruth_boxes3,
  67. standard_fields.InputDataFields.groundtruth_classes:
  68. groundtruth_class_labels3
  69. })
  70. # Add detections
  71. image_key = 'img2'
  72. detected_boxes = np.array(
  73. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220]],
  74. dtype=float)
  75. detected_class_labels = np.array([1, 1, 3], dtype=int)
  76. detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
  77. oiv2_evaluator.add_single_detected_image_info(image_key, {
  78. standard_fields.DetectionResultFields.detection_boxes:
  79. detected_boxes,
  80. standard_fields.DetectionResultFields.detection_scores:
  81. detected_scores,
  82. standard_fields.DetectionResultFields.detection_classes:
  83. detected_class_labels
  84. })
  85. metrics = oiv2_evaluator.evaluate()
  86. self.assertAlmostEqual(
  87. metrics['OpenImagesV2_PerformanceByCategory/AP@0.5IOU/dog'], 0.0)
  88. self.assertAlmostEqual(
  89. metrics['OpenImagesV2_PerformanceByCategory/AP@0.5IOU/elephant'], 0.0)
  90. self.assertAlmostEqual(
  91. metrics['OpenImagesV2_PerformanceByCategory/AP@0.5IOU/cat'], 0.16666666)
  92. self.assertAlmostEqual(metrics['OpenImagesV2_Precision/mAP@0.5IOU'],
  93. 0.05555555)
  94. oiv2_evaluator.clear()
  95. self.assertFalse(oiv2_evaluator._image_ids)
  96. class OpenImagesDetectionChallengeEvaluatorTest(tf.test.TestCase):
  97. def test_returns_correct_metric_values(self):
  98. categories = [{
  99. 'id': 1,
  100. 'name': 'cat'
  101. }, {
  102. 'id': 2,
  103. 'name': 'dog'
  104. }, {
  105. 'id': 3,
  106. 'name': 'elephant'
  107. }]
  108. oivchallenge_evaluator = (
  109. object_detection_evaluation.OpenImagesDetectionChallengeEvaluator(
  110. categories, group_of_weight=0.5))
  111. image_key = 'img1'
  112. groundtruth_boxes = np.array(
  113. [[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]], dtype=float)
  114. groundtruth_class_labels = np.array([1, 3, 1], dtype=int)
  115. groundtruth_is_group_of_list = np.array([False, False, True], dtype=bool)
  116. groundtruth_verified_labels = np.array([1, 2, 3], dtype=int)
  117. oivchallenge_evaluator.add_single_ground_truth_image_info(
  118. image_key, {
  119. standard_fields.InputDataFields.groundtruth_boxes:
  120. groundtruth_boxes,
  121. standard_fields.InputDataFields.groundtruth_classes:
  122. groundtruth_class_labels,
  123. standard_fields.InputDataFields.groundtruth_group_of:
  124. groundtruth_is_group_of_list,
  125. standard_fields.InputDataFields.groundtruth_image_classes:
  126. groundtruth_verified_labels,
  127. })
  128. image_key = 'img2'
  129. groundtruth_boxes = np.array(
  130. [[10, 10, 11, 11], [500, 500, 510, 510], [10, 10, 12, 12]], dtype=float)
  131. groundtruth_class_labels = np.array([1, 1, 3], dtype=int)
  132. groundtruth_is_group_of_list = np.array([False, False, True], dtype=bool)
  133. oivchallenge_evaluator.add_single_ground_truth_image_info(
  134. image_key, {
  135. standard_fields.InputDataFields.groundtruth_boxes:
  136. groundtruth_boxes,
  137. standard_fields.InputDataFields.groundtruth_classes:
  138. groundtruth_class_labels,
  139. standard_fields.InputDataFields.groundtruth_group_of:
  140. groundtruth_is_group_of_list
  141. })
  142. image_key = 'img3'
  143. groundtruth_boxes = np.array([[0, 0, 1, 1]], dtype=float)
  144. groundtruth_class_labels = np.array([2], dtype=int)
  145. oivchallenge_evaluator.add_single_ground_truth_image_info(
  146. image_key, {
  147. standard_fields.InputDataFields.groundtruth_boxes:
  148. groundtruth_boxes,
  149. standard_fields.InputDataFields.groundtruth_classes:
  150. groundtruth_class_labels
  151. })
  152. image_key = 'img1'
  153. detected_boxes = np.array(
  154. [[10, 10, 11, 11], [100, 100, 120, 120]], dtype=float)
  155. detected_class_labels = np.array([2, 2], dtype=int)
  156. detected_scores = np.array([0.7, 0.8], dtype=float)
  157. oivchallenge_evaluator.add_single_detected_image_info(
  158. image_key, {
  159. standard_fields.DetectionResultFields.detection_boxes:
  160. detected_boxes,
  161. standard_fields.DetectionResultFields.detection_scores:
  162. detected_scores,
  163. standard_fields.DetectionResultFields.detection_classes:
  164. detected_class_labels
  165. })
  166. image_key = 'img2'
  167. detected_boxes = np.array(
  168. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220],
  169. [10, 10, 11, 11]],
  170. dtype=float)
  171. detected_class_labels = np.array([1, 1, 2, 3], dtype=int)
  172. detected_scores = np.array([0.7, 0.8, 0.5, 0.9], dtype=float)
  173. oivchallenge_evaluator.add_single_detected_image_info(
  174. image_key, {
  175. standard_fields.DetectionResultFields.detection_boxes:
  176. detected_boxes,
  177. standard_fields.DetectionResultFields.detection_scores:
  178. detected_scores,
  179. standard_fields.DetectionResultFields.detection_classes:
  180. detected_class_labels
  181. })
  182. image_key = 'img3'
  183. detected_boxes = np.array([[0, 0, 1, 1]], dtype=float)
  184. detected_class_labels = np.array([2], dtype=int)
  185. detected_scores = np.array([0.5], dtype=float)
  186. oivchallenge_evaluator.add_single_detected_image_info(
  187. image_key, {
  188. standard_fields.DetectionResultFields.detection_boxes:
  189. detected_boxes,
  190. standard_fields.DetectionResultFields.detection_scores:
  191. detected_scores,
  192. standard_fields.DetectionResultFields.detection_classes:
  193. detected_class_labels
  194. })
  195. metrics = oivchallenge_evaluator.evaluate()
  196. self.assertAlmostEqual(
  197. metrics['OpenImagesChallenge2018_PerformanceByCategory/AP@0.5IOU/dog'],
  198. 0.3333333333)
  199. self.assertAlmostEqual(
  200. metrics[
  201. 'OpenImagesChallenge2018_PerformanceByCategory/AP@0.5IOU/elephant'],
  202. 0.333333333333)
  203. self.assertAlmostEqual(
  204. metrics['OpenImagesChallenge2018_PerformanceByCategory/AP@0.5IOU/cat'],
  205. 0.142857142857)
  206. self.assertAlmostEqual(
  207. metrics['OpenImagesChallenge2018_Precision/mAP@0.5IOU'], 0.269841269)
  208. oivchallenge_evaluator.clear()
  209. self.assertFalse(oivchallenge_evaluator._image_ids)
  210. class PascalEvaluationTest(tf.test.TestCase):
  211. def test_returns_correct_metric_values_on_boxes(self):
  212. categories = [{'id': 1, 'name': 'cat'},
  213. {'id': 2, 'name': 'dog'},
  214. {'id': 3, 'name': 'elephant'}]
  215. # Add groundtruth
  216. pascal_evaluator = object_detection_evaluation.PascalDetectionEvaluator(
  217. categories)
  218. image_key1 = 'img1'
  219. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  220. dtype=float)
  221. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  222. pascal_evaluator.add_single_ground_truth_image_info(
  223. image_key1,
  224. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes1,
  225. standard_fields.InputDataFields.groundtruth_classes:
  226. groundtruth_class_labels1,
  227. standard_fields.InputDataFields.groundtruth_difficult:
  228. np.array([], dtype=bool)})
  229. image_key2 = 'img2'
  230. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  231. [10, 10, 12, 12]], dtype=float)
  232. groundtruth_class_labels2 = np.array([1, 1, 3], dtype=int)
  233. groundtruth_is_difficult_list2 = np.array([False, True, False], dtype=bool)
  234. pascal_evaluator.add_single_ground_truth_image_info(
  235. image_key2,
  236. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes2,
  237. standard_fields.InputDataFields.groundtruth_classes:
  238. groundtruth_class_labels2,
  239. standard_fields.InputDataFields.groundtruth_difficult:
  240. groundtruth_is_difficult_list2})
  241. image_key3 = 'img3'
  242. groundtruth_boxes3 = np.array([[0, 0, 1, 1]], dtype=float)
  243. groundtruth_class_labels3 = np.array([2], dtype=int)
  244. pascal_evaluator.add_single_ground_truth_image_info(
  245. image_key3,
  246. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes3,
  247. standard_fields.InputDataFields.groundtruth_classes:
  248. groundtruth_class_labels3})
  249. # Add detections
  250. image_key = 'img2'
  251. detected_boxes = np.array(
  252. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220]],
  253. dtype=float)
  254. detected_class_labels = np.array([1, 1, 3], dtype=int)
  255. detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
  256. pascal_evaluator.add_single_detected_image_info(
  257. image_key,
  258. {standard_fields.DetectionResultFields.detection_boxes: detected_boxes,
  259. standard_fields.DetectionResultFields.detection_scores:
  260. detected_scores,
  261. standard_fields.DetectionResultFields.detection_classes:
  262. detected_class_labels})
  263. metrics = pascal_evaluator.evaluate()
  264. self.assertAlmostEqual(
  265. metrics['PascalBoxes_PerformanceByCategory/AP@0.5IOU/dog'], 0.0)
  266. self.assertAlmostEqual(
  267. metrics['PascalBoxes_PerformanceByCategory/AP@0.5IOU/elephant'], 0.0)
  268. self.assertAlmostEqual(
  269. metrics['PascalBoxes_PerformanceByCategory/AP@0.5IOU/cat'], 0.16666666)
  270. self.assertAlmostEqual(metrics['PascalBoxes_Precision/mAP@0.5IOU'],
  271. 0.05555555)
  272. pascal_evaluator.clear()
  273. self.assertFalse(pascal_evaluator._image_ids)
  274. def test_returns_correct_metric_values_on_masks(self):
  275. categories = [{'id': 1, 'name': 'cat'},
  276. {'id': 2, 'name': 'dog'},
  277. {'id': 3, 'name': 'elephant'}]
  278. # Add groundtruth
  279. pascal_evaluator = (
  280. object_detection_evaluation.PascalInstanceSegmentationEvaluator(
  281. categories))
  282. image_key1 = 'img1'
  283. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  284. dtype=float)
  285. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  286. groundtruth_masks_1_0 = np.array([[1, 0, 0, 0],
  287. [1, 0, 0, 0],
  288. [1, 0, 0, 0]], dtype=np.uint8)
  289. groundtruth_masks_1_1 = np.array([[0, 0, 1, 0],
  290. [0, 0, 1, 0],
  291. [0, 0, 1, 0]], dtype=np.uint8)
  292. groundtruth_masks_1_2 = np.array([[0, 1, 0, 0],
  293. [0, 1, 0, 0],
  294. [0, 1, 0, 0]], dtype=np.uint8)
  295. groundtruth_masks1 = np.stack(
  296. [groundtruth_masks_1_0, groundtruth_masks_1_1, groundtruth_masks_1_2],
  297. axis=0)
  298. pascal_evaluator.add_single_ground_truth_image_info(
  299. image_key1, {
  300. standard_fields.InputDataFields.groundtruth_boxes:
  301. groundtruth_boxes1,
  302. standard_fields.InputDataFields.groundtruth_instance_masks:
  303. groundtruth_masks1,
  304. standard_fields.InputDataFields.groundtruth_classes:
  305. groundtruth_class_labels1,
  306. standard_fields.InputDataFields.groundtruth_difficult:
  307. np.array([], dtype=bool)
  308. })
  309. image_key2 = 'img2'
  310. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  311. [10, 10, 12, 12]], dtype=float)
  312. groundtruth_class_labels2 = np.array([1, 1, 3], dtype=int)
  313. groundtruth_is_difficult_list2 = np.array([False, True, False], dtype=bool)
  314. groundtruth_masks_2_0 = np.array([[1, 1, 1, 1],
  315. [0, 0, 0, 0],
  316. [0, 0, 0, 0]], dtype=np.uint8)
  317. groundtruth_masks_2_1 = np.array([[0, 0, 0, 0],
  318. [1, 1, 1, 1],
  319. [0, 0, 0, 0]], dtype=np.uint8)
  320. groundtruth_masks_2_2 = np.array([[0, 0, 0, 0],
  321. [0, 0, 0, 0],
  322. [1, 1, 1, 1]], dtype=np.uint8)
  323. groundtruth_masks2 = np.stack(
  324. [groundtruth_masks_2_0, groundtruth_masks_2_1, groundtruth_masks_2_2],
  325. axis=0)
  326. pascal_evaluator.add_single_ground_truth_image_info(
  327. image_key2, {
  328. standard_fields.InputDataFields.groundtruth_boxes:
  329. groundtruth_boxes2,
  330. standard_fields.InputDataFields.groundtruth_instance_masks:
  331. groundtruth_masks2,
  332. standard_fields.InputDataFields.groundtruth_classes:
  333. groundtruth_class_labels2,
  334. standard_fields.InputDataFields.groundtruth_difficult:
  335. groundtruth_is_difficult_list2
  336. })
  337. image_key3 = 'img3'
  338. groundtruth_boxes3 = np.array([[0, 0, 1, 1]], dtype=float)
  339. groundtruth_class_labels3 = np.array([2], dtype=int)
  340. groundtruth_masks_3_0 = np.array([[1, 1, 1, 1],
  341. [1, 1, 1, 1],
  342. [1, 1, 1, 1]], dtype=np.uint8)
  343. groundtruth_masks3 = np.stack([groundtruth_masks_3_0], axis=0)
  344. pascal_evaluator.add_single_ground_truth_image_info(
  345. image_key3, {
  346. standard_fields.InputDataFields.groundtruth_boxes:
  347. groundtruth_boxes3,
  348. standard_fields.InputDataFields.groundtruth_instance_masks:
  349. groundtruth_masks3,
  350. standard_fields.InputDataFields.groundtruth_classes:
  351. groundtruth_class_labels3
  352. })
  353. # Add detections
  354. image_key = 'img2'
  355. detected_boxes = np.array(
  356. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220]],
  357. dtype=float)
  358. detected_class_labels = np.array([1, 1, 3], dtype=int)
  359. detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
  360. detected_masks_0 = np.array([[1, 1, 1, 1],
  361. [0, 0, 1, 0],
  362. [0, 0, 0, 0]], dtype=np.uint8)
  363. detected_masks_1 = np.array([[1, 0, 0, 0],
  364. [1, 1, 0, 0],
  365. [0, 0, 0, 0]], dtype=np.uint8)
  366. detected_masks_2 = np.array([[0, 1, 0, 0],
  367. [0, 1, 1, 0],
  368. [0, 1, 0, 0]], dtype=np.uint8)
  369. detected_masks = np.stack(
  370. [detected_masks_0, detected_masks_1, detected_masks_2], axis=0)
  371. pascal_evaluator.add_single_detected_image_info(
  372. image_key, {
  373. standard_fields.DetectionResultFields.detection_boxes:
  374. detected_boxes,
  375. standard_fields.DetectionResultFields.detection_masks:
  376. detected_masks,
  377. standard_fields.DetectionResultFields.detection_scores:
  378. detected_scores,
  379. standard_fields.DetectionResultFields.detection_classes:
  380. detected_class_labels
  381. })
  382. metrics = pascal_evaluator.evaluate()
  383. self.assertAlmostEqual(
  384. metrics['PascalMasks_PerformanceByCategory/AP@0.5IOU/dog'], 0.0)
  385. self.assertAlmostEqual(
  386. metrics['PascalMasks_PerformanceByCategory/AP@0.5IOU/elephant'], 0.0)
  387. self.assertAlmostEqual(
  388. metrics['PascalMasks_PerformanceByCategory/AP@0.5IOU/cat'], 0.16666666)
  389. self.assertAlmostEqual(metrics['PascalMasks_Precision/mAP@0.5IOU'],
  390. 0.05555555)
  391. pascal_evaluator.clear()
  392. self.assertFalse(pascal_evaluator._image_ids)
  393. def test_value_error_on_duplicate_images(self):
  394. categories = [{'id': 1, 'name': 'cat'},
  395. {'id': 2, 'name': 'dog'},
  396. {'id': 3, 'name': 'elephant'}]
  397. # Add groundtruth
  398. pascal_evaluator = object_detection_evaluation.PascalDetectionEvaluator(
  399. categories)
  400. image_key1 = 'img1'
  401. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  402. dtype=float)
  403. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  404. pascal_evaluator.add_single_ground_truth_image_info(
  405. image_key1,
  406. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes1,
  407. standard_fields.InputDataFields.groundtruth_classes:
  408. groundtruth_class_labels1})
  409. with self.assertRaises(ValueError):
  410. pascal_evaluator.add_single_ground_truth_image_info(
  411. image_key1,
  412. {standard_fields.InputDataFields.groundtruth_boxes:
  413. groundtruth_boxes1,
  414. standard_fields.InputDataFields.groundtruth_classes:
  415. groundtruth_class_labels1})
  416. class WeightedPascalEvaluationTest(tf.test.TestCase):
  417. def setUp(self):
  418. self.categories = [{'id': 1, 'name': 'cat'},
  419. {'id': 2, 'name': 'dog'},
  420. {'id': 3, 'name': 'elephant'}]
  421. def create_and_add_common_ground_truth(self):
  422. # Add groundtruth
  423. self.wp_eval = (
  424. object_detection_evaluation.WeightedPascalDetectionEvaluator(
  425. self.categories))
  426. image_key1 = 'img1'
  427. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  428. dtype=float)
  429. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  430. self.wp_eval.add_single_ground_truth_image_info(
  431. image_key1,
  432. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes1,
  433. standard_fields.InputDataFields.groundtruth_classes:
  434. groundtruth_class_labels1})
  435. # add 'img2' separately
  436. image_key3 = 'img3'
  437. groundtruth_boxes3 = np.array([[0, 0, 1, 1]], dtype=float)
  438. groundtruth_class_labels3 = np.array([2], dtype=int)
  439. self.wp_eval.add_single_ground_truth_image_info(
  440. image_key3,
  441. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes3,
  442. standard_fields.InputDataFields.groundtruth_classes:
  443. groundtruth_class_labels3})
  444. def add_common_detected(self):
  445. image_key = 'img2'
  446. detected_boxes = np.array(
  447. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220]],
  448. dtype=float)
  449. detected_class_labels = np.array([1, 1, 3], dtype=int)
  450. detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
  451. self.wp_eval.add_single_detected_image_info(
  452. image_key,
  453. {standard_fields.DetectionResultFields.detection_boxes: detected_boxes,
  454. standard_fields.DetectionResultFields.detection_scores:
  455. detected_scores,
  456. standard_fields.DetectionResultFields.detection_classes:
  457. detected_class_labels})
  458. def test_returns_correct_metric_values(self):
  459. self.create_and_add_common_ground_truth()
  460. image_key2 = 'img2'
  461. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  462. [10, 10, 12, 12]], dtype=float)
  463. groundtruth_class_labels2 = np.array([1, 1, 3], dtype=int)
  464. self.wp_eval.add_single_ground_truth_image_info(
  465. image_key2,
  466. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes2,
  467. standard_fields.InputDataFields.groundtruth_classes:
  468. groundtruth_class_labels2
  469. })
  470. self.add_common_detected()
  471. metrics = self.wp_eval.evaluate()
  472. self.assertAlmostEqual(
  473. metrics[self.wp_eval._metric_prefix +
  474. 'PerformanceByCategory/AP@0.5IOU/dog'], 0.0)
  475. self.assertAlmostEqual(
  476. metrics[self.wp_eval._metric_prefix +
  477. 'PerformanceByCategory/AP@0.5IOU/elephant'], 0.0)
  478. self.assertAlmostEqual(
  479. metrics[self.wp_eval._metric_prefix +
  480. 'PerformanceByCategory/AP@0.5IOU/cat'], 0.5 / 4)
  481. self.assertAlmostEqual(metrics[self.wp_eval._metric_prefix +
  482. 'Precision/mAP@0.5IOU'],
  483. 1. / (4 + 1 + 2) / 3)
  484. self.wp_eval.clear()
  485. self.assertFalse(self.wp_eval._image_ids)
  486. def test_returns_correct_metric_values_with_difficult_list(self):
  487. self.create_and_add_common_ground_truth()
  488. image_key2 = 'img2'
  489. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  490. [10, 10, 12, 12]], dtype=float)
  491. groundtruth_class_labels2 = np.array([1, 1, 3], dtype=int)
  492. groundtruth_is_difficult_list2 = np.array([False, True, False], dtype=bool)
  493. self.wp_eval.add_single_ground_truth_image_info(
  494. image_key2,
  495. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes2,
  496. standard_fields.InputDataFields.groundtruth_classes:
  497. groundtruth_class_labels2,
  498. standard_fields.InputDataFields.groundtruth_difficult:
  499. groundtruth_is_difficult_list2
  500. })
  501. self.add_common_detected()
  502. metrics = self.wp_eval.evaluate()
  503. self.assertAlmostEqual(
  504. metrics[self.wp_eval._metric_prefix +
  505. 'PerformanceByCategory/AP@0.5IOU/dog'], 0.0)
  506. self.assertAlmostEqual(
  507. metrics[self.wp_eval._metric_prefix +
  508. 'PerformanceByCategory/AP@0.5IOU/elephant'], 0.0)
  509. self.assertAlmostEqual(
  510. metrics[self.wp_eval._metric_prefix +
  511. 'PerformanceByCategory/AP@0.5IOU/cat'], 0.5 / 3)
  512. self.assertAlmostEqual(metrics[self.wp_eval._metric_prefix +
  513. 'Precision/mAP@0.5IOU'],
  514. 1. / (3 + 1 + 2) / 3)
  515. self.wp_eval.clear()
  516. self.assertFalse(self.wp_eval._image_ids)
  517. def test_value_error_on_duplicate_images(self):
  518. # Add groundtruth
  519. self.wp_eval = (
  520. object_detection_evaluation.WeightedPascalDetectionEvaluator(
  521. self.categories))
  522. image_key1 = 'img1'
  523. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  524. dtype=float)
  525. groundtruth_class_labels1 = np.array([1, 3, 1], dtype=int)
  526. self.wp_eval.add_single_ground_truth_image_info(
  527. image_key1,
  528. {standard_fields.InputDataFields.groundtruth_boxes: groundtruth_boxes1,
  529. standard_fields.InputDataFields.groundtruth_classes:
  530. groundtruth_class_labels1})
  531. with self.assertRaises(ValueError):
  532. self.wp_eval.add_single_ground_truth_image_info(
  533. image_key1,
  534. {standard_fields.InputDataFields.groundtruth_boxes:
  535. groundtruth_boxes1,
  536. standard_fields.InputDataFields.groundtruth_classes:
  537. groundtruth_class_labels1})
  538. class ObjectDetectionEvaluationTest(tf.test.TestCase):
  539. def setUp(self):
  540. num_groundtruth_classes = 3
  541. self.od_eval = object_detection_evaluation.ObjectDetectionEvaluation(
  542. num_groundtruth_classes)
  543. image_key1 = 'img1'
  544. groundtruth_boxes1 = np.array([[0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 3, 3]],
  545. dtype=float)
  546. groundtruth_class_labels1 = np.array([0, 2, 0], dtype=int)
  547. self.od_eval.add_single_ground_truth_image_info(
  548. image_key1, groundtruth_boxes1, groundtruth_class_labels1)
  549. image_key2 = 'img2'
  550. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  551. [10, 10, 12, 12]], dtype=float)
  552. groundtruth_class_labels2 = np.array([0, 0, 2], dtype=int)
  553. groundtruth_is_difficult_list2 = np.array([False, True, False], dtype=bool)
  554. groundtruth_is_group_of_list2 = np.array([False, False, True], dtype=bool)
  555. self.od_eval.add_single_ground_truth_image_info(
  556. image_key2, groundtruth_boxes2, groundtruth_class_labels2,
  557. groundtruth_is_difficult_list2, groundtruth_is_group_of_list2)
  558. image_key3 = 'img3'
  559. groundtruth_boxes3 = np.array([[0, 0, 1, 1]], dtype=float)
  560. groundtruth_class_labels3 = np.array([1], dtype=int)
  561. self.od_eval.add_single_ground_truth_image_info(
  562. image_key3, groundtruth_boxes3, groundtruth_class_labels3)
  563. image_key = 'img2'
  564. detected_boxes = np.array(
  565. [[10, 10, 11, 11], [100, 100, 120, 120], [100, 100, 220, 220]],
  566. dtype=float)
  567. detected_class_labels = np.array([0, 0, 2], dtype=int)
  568. detected_scores = np.array([0.7, 0.8, 0.9], dtype=float)
  569. self.od_eval.add_single_detected_image_info(
  570. image_key, detected_boxes, detected_scores, detected_class_labels)
  571. def test_value_error_on_zero_classes(self):
  572. with self.assertRaises(ValueError):
  573. object_detection_evaluation.ObjectDetectionEvaluation(
  574. num_groundtruth_classes=0)
  575. def test_add_single_ground_truth_image_info(self):
  576. expected_num_gt_instances_per_class = np.array([3, 1, 1], dtype=int)
  577. expected_num_gt_imgs_per_class = np.array([2, 1, 2], dtype=int)
  578. self.assertTrue(np.array_equal(expected_num_gt_instances_per_class,
  579. self.od_eval.num_gt_instances_per_class))
  580. self.assertTrue(np.array_equal(expected_num_gt_imgs_per_class,
  581. self.od_eval.num_gt_imgs_per_class))
  582. groundtruth_boxes2 = np.array([[10, 10, 11, 11], [500, 500, 510, 510],
  583. [10, 10, 12, 12]], dtype=float)
  584. self.assertTrue(np.allclose(self.od_eval.groundtruth_boxes['img2'],
  585. groundtruth_boxes2))
  586. groundtruth_is_difficult_list2 = np.array([False, True, False], dtype=bool)
  587. self.assertTrue(np.allclose(
  588. self.od_eval.groundtruth_is_difficult_list['img2'],
  589. groundtruth_is_difficult_list2))
  590. groundtruth_is_group_of_list2 = np.array([False, False, True], dtype=bool)
  591. self.assertTrue(
  592. np.allclose(self.od_eval.groundtruth_is_group_of_list['img2'],
  593. groundtruth_is_group_of_list2))
  594. groundtruth_class_labels1 = np.array([0, 2, 0], dtype=int)
  595. self.assertTrue(np.array_equal(self.od_eval.groundtruth_class_labels[
  596. 'img1'], groundtruth_class_labels1))
  597. def test_add_single_detected_image_info(self):
  598. expected_scores_per_class = [[np.array([0.8, 0.7], dtype=float)], [],
  599. [np.array([0.9], dtype=float)]]
  600. expected_tp_fp_labels_per_class = [[np.array([0, 1], dtype=bool)], [],
  601. [np.array([0], dtype=bool)]]
  602. expected_num_images_correctly_detected_per_class = np.array([0, 0, 0],
  603. dtype=int)
  604. for i in range(self.od_eval.num_class):
  605. for j in range(len(expected_scores_per_class[i])):
  606. self.assertTrue(np.allclose(expected_scores_per_class[i][j],
  607. self.od_eval.scores_per_class[i][j]))
  608. self.assertTrue(np.array_equal(expected_tp_fp_labels_per_class[i][
  609. j], self.od_eval.tp_fp_labels_per_class[i][j]))
  610. self.assertTrue(np.array_equal(
  611. expected_num_images_correctly_detected_per_class,
  612. self.od_eval.num_images_correctly_detected_per_class))
  613. def test_evaluate(self):
  614. (average_precision_per_class, mean_ap, precisions_per_class,
  615. recalls_per_class, corloc_per_class,
  616. mean_corloc) = self.od_eval.evaluate()
  617. expected_precisions_per_class = [np.array([0, 0.5], dtype=float),
  618. np.array([], dtype=float),
  619. np.array([0], dtype=float)]
  620. expected_recalls_per_class = [
  621. np.array([0, 1. / 3.], dtype=float), np.array([], dtype=float),
  622. np.array([0], dtype=float)
  623. ]
  624. expected_average_precision_per_class = np.array([1. / 6., 0, 0],
  625. dtype=float)
  626. expected_corloc_per_class = np.array([0, np.divide(0, 0), 0], dtype=float)
  627. expected_mean_ap = 1. / 18
  628. expected_mean_corloc = 0.0
  629. for i in range(self.od_eval.num_class):
  630. self.assertTrue(np.allclose(expected_precisions_per_class[i],
  631. precisions_per_class[i]))
  632. self.assertTrue(np.allclose(expected_recalls_per_class[i],
  633. recalls_per_class[i]))
  634. self.assertTrue(np.allclose(expected_average_precision_per_class,
  635. average_precision_per_class))
  636. self.assertTrue(np.allclose(expected_corloc_per_class, corloc_per_class))
  637. self.assertAlmostEqual(expected_mean_ap, mean_ap)
  638. self.assertAlmostEqual(expected_mean_corloc, mean_corloc)
  639. class ObjectDetectionEvaluatorTest(tf.test.TestCase, parameterized.TestCase):
  640. def setUp(self):
  641. self.categories = [{
  642. 'id': 1,
  643. 'name': 'person'
  644. }, {
  645. 'id': 2,
  646. 'name': 'dog'
  647. }, {
  648. 'id': 3,
  649. 'name': 'cat'
  650. }]
  651. self.od_eval = object_detection_evaluation.ObjectDetectionEvaluator(
  652. categories=self.categories)
  653. def _make_evaluation_dict(self,
  654. resized_groundtruth_masks=False,
  655. batch_size=1,
  656. max_gt_boxes=None,
  657. scale_to_absolute=False):
  658. input_data_fields = standard_fields.InputDataFields
  659. detection_fields = standard_fields.DetectionResultFields
  660. image = tf.zeros(shape=[batch_size, 20, 20, 3], dtype=tf.uint8)
  661. if batch_size == 1:
  662. key = tf.constant('image1')
  663. else:
  664. key = tf.constant([str(i) for i in range(batch_size)])
  665. detection_boxes = tf.concat([
  666. tf.tile(
  667. tf.constant([[[0., 0., 1., 1.]]]), multiples=[batch_size - 1, 1, 1
  668. ]),
  669. tf.constant([[[0., 0., 0.5, 0.5]]])
  670. ],
  671. axis=0)
  672. detection_scores = tf.concat([
  673. tf.tile(tf.constant([[0.5]]), multiples=[batch_size - 1, 1]),
  674. tf.constant([[0.8]])
  675. ],
  676. axis=0)
  677. detection_classes = tf.tile(tf.constant([[0]]), multiples=[batch_size, 1])
  678. detection_masks = tf.tile(
  679. tf.ones(shape=[1, 2, 20, 20], dtype=tf.float32),
  680. multiples=[batch_size, 1, 1, 1])
  681. groundtruth_boxes = tf.constant([[0., 0., 1., 1.]])
  682. groundtruth_classes = tf.constant([1])
  683. groundtruth_instance_masks = tf.ones(shape=[1, 20, 20], dtype=tf.uint8)
  684. num_detections = tf.ones([batch_size])
  685. if resized_groundtruth_masks:
  686. groundtruth_instance_masks = tf.ones(shape=[1, 10, 10], dtype=tf.uint8)
  687. if batch_size > 1:
  688. groundtruth_boxes = tf.tile(
  689. tf.expand_dims(groundtruth_boxes, 0), multiples=[batch_size, 1, 1])
  690. groundtruth_classes = tf.tile(
  691. tf.expand_dims(groundtruth_classes, 0), multiples=[batch_size, 1])
  692. groundtruth_instance_masks = tf.tile(
  693. tf.expand_dims(groundtruth_instance_masks, 0),
  694. multiples=[batch_size, 1, 1, 1])
  695. detections = {
  696. detection_fields.detection_boxes: detection_boxes,
  697. detection_fields.detection_scores: detection_scores,
  698. detection_fields.detection_classes: detection_classes,
  699. detection_fields.detection_masks: detection_masks,
  700. detection_fields.num_detections: num_detections
  701. }
  702. groundtruth = {
  703. input_data_fields.groundtruth_boxes:
  704. groundtruth_boxes,
  705. input_data_fields.groundtruth_classes:
  706. groundtruth_classes,
  707. input_data_fields.groundtruth_instance_masks:
  708. groundtruth_instance_masks,
  709. }
  710. if batch_size > 1:
  711. return eval_util.result_dict_for_batched_example(
  712. image,
  713. key,
  714. detections,
  715. groundtruth,
  716. scale_to_absolute=scale_to_absolute,
  717. max_gt_boxes=max_gt_boxes)
  718. else:
  719. return eval_util.result_dict_for_single_example(
  720. image,
  721. key,
  722. detections,
  723. groundtruth,
  724. scale_to_absolute=scale_to_absolute)
  725. @parameterized.parameters({
  726. 'batch_size': 1,
  727. 'expected_map': 0,
  728. 'max_gt_boxes': None,
  729. 'scale_to_absolute': True
  730. }, {
  731. 'batch_size': 8,
  732. 'expected_map': 0.765625,
  733. 'max_gt_boxes': [1],
  734. 'scale_to_absolute': True
  735. }, {
  736. 'batch_size': 1,
  737. 'expected_map': 0,
  738. 'max_gt_boxes': None,
  739. 'scale_to_absolute': False
  740. }, {
  741. 'batch_size': 8,
  742. 'expected_map': 0.765625,
  743. 'max_gt_boxes': [1],
  744. 'scale_to_absolute': False
  745. })
  746. def test_get_estimator_eval_metric_ops(self,
  747. batch_size=1,
  748. expected_map=1,
  749. max_gt_boxes=None,
  750. scale_to_absolute=False):
  751. eval_dict = self._make_evaluation_dict(
  752. batch_size=batch_size,
  753. max_gt_boxes=max_gt_boxes,
  754. scale_to_absolute=scale_to_absolute)
  755. tf.logging.info('eval_dict: {}'.format(eval_dict))
  756. metric_ops = self.od_eval.get_estimator_eval_metric_ops(eval_dict)
  757. _, update_op = metric_ops['Precision/mAP@0.5IOU']
  758. with self.test_session() as sess:
  759. metrics = {}
  760. for key, (value_op, _) in metric_ops.iteritems():
  761. metrics[key] = value_op
  762. sess.run(update_op)
  763. metrics = sess.run(metrics)
  764. self.assertAlmostEqual(expected_map, metrics['Precision/mAP@0.5IOU'])
  765. if __name__ == '__main__':
  766. tf.test.main()