Repository: azavea/raster-vision

Issue:
Evaluation for object detection with AOIs crashes
```
Running evaluator: ObjectDetectionEvaluator...
2019-03-28 16:47:07:rastervision.evaluation.classification_evaluator: INFO - Computing evaluation for scene 01986917-30ea-4f7f-8e01-985d73b8aa2a...
Traceback (most recent call last):
  File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/opt/src/rastervision/__main__.py", line 17, in <module>
    rv.main()
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/opt/src/rastervision/cli/main.py", line 260, in run_command
    rv.runner.CommandRunner.run(command_config_uri)
  File "/opt/src/rastervision/runner/command_runner.py", line 11, in run
    CommandRunner.run_from_proto(msg)
  File "/opt/src/rastervision/runner/command_runner.py", line 17, in run_from_proto
    command.run()
  File "/opt/src/rastervision/command/eval_command.py", line 24, in run
    evaluator.process(scenes, tmp_dir)
  File "/opt/src/rastervision/evaluation/classification_evaluator.py", line 36, in process
    scene.aoi_polygons)
  File "/opt/src/rastervision/data/label/object_detection_labels.py", line 70, in filter_by_aoi
    np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))
  File "/opt/src/rastervision/data/label/object_detection_labels.py", line 27, in __init__
    self.boxlist = BoxList(npboxes)
  File "/opt/tf-models/object_detection/utils/np_box_list.py", line 46, in __init__
    raise ValueError('Invalid dimensions for box data.')
ValueError: Invalid dimensions for box data.
/tmp/tmpwie3_vrf/tmp41bj3kgh/Makefile:9: recipe for target '3' failed
make: *** [3] Error 1
make: *** Waiting for unfinished jobs....
```


Discussion:

Resolving patch:
diff --git a/rastervision/data/label/object_detection_labels.py b/rastervision/data/label/object_detection_labels.py
--- a/rastervision/data/label/object_detection_labels.py
+++ b/rastervision/data/label/object_detection_labels.py
@@ -61,11 +61,14 @@ def filter_by_aoi(self, aoi_polygons):
             box_poly = box.to_shapely()
             for aoi in aoi_polygons:
                 if box_poly.within(aoi):
-                    new_boxes.append(box)
+                    new_boxes.append(box.npbox_format())
                     new_class_ids.append(class_id)
                     new_scores.append(score)
                     break
 
+        if len(new_boxes) == 0:
+            return ObjectDetectionLabels.make_empty()
+
         return ObjectDetectionLabels(
             np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))
 


Test patch:
diff --git a/tests/data/label/test_chip_classification_labels.py b/tests/data/label/test_chip_classification_labels.py
--- a/tests/data/label/test_chip_classification_labels.py
+++ b/tests/data/label/test_chip_classification_labels.py
@@ -63,6 +63,22 @@ def test_extend(self):
         self.assertEqual(len(cells), 3)
         self.assertTrue(cell3 in cells)
 
+    def test_filter_by_aoi(self):
+        aois = [Box.make_square(0, 0, 2).to_shapely()]
+        filt_labels = self.labels.filter_by_aoi(aois)
+
+        exp_labels = ChipClassificationLabels()
+        cell1 = Box.make_square(0, 0, 2)
+        class_id1 = 1
+        exp_labels.set_cell(cell1, class_id1)
+        self.assertEqual(filt_labels, exp_labels)
+
+        aois = [Box.make_square(4, 4, 2).to_shapely()]
+        filt_labels = self.labels.filter_by_aoi(aois)
+
+        exp_labels = ChipClassificationLabels()
+        self.assertEqual(filt_labels, exp_labels)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/data/label/test_object_detection_labels.py b/tests/data/label/test_object_detection_labels.py
--- a/tests/data/label/test_object_detection_labels.py
+++ b/tests/data/label/test_object_detection_labels.py
@@ -182,6 +182,21 @@ def test_prune_duplicates(self):
             scores=expected_scores[pruned_inds])
         pruned_labels.assert_equal(expected_labels)
 
+    def test_filter_by_aoi(self):
+        aois = [Box.make_square(0, 0, 2).to_shapely()]
+        filt_labels = self.labels.filter_by_aoi(aois)
+
+        npboxes = np.array([[0., 0., 2., 2.]])
+        class_ids = np.array([1])
+        scores = np.array([0.9])
+        exp_labels = ObjectDetectionLabels(npboxes, class_ids, scores=scores)
+        self.assertEqual(filt_labels, exp_labels)
+
+        aois = [Box.make_square(4, 4, 2).to_shapely()]
+        filt_labels = self.labels.filter_by_aoi(aois)
+        exp_labels = ObjectDetectionLabels.make_empty()
+        self.assertEqual(filt_labels, exp_labels)
+
 
 if __name__ == '__main__':
     unittest.main()