We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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....
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rastervision/data/label/object_detection_labels.py`
Content:
```
1 import numpy as np
2 from shapely.geometry import shape
3 
4 from rastervision.core.box import Box
5 from rastervision.data.label import Labels
6 
7 
8 class ObjectDetectionLabels(Labels):
9     """A set of boxes and associated class_ids and scores.
10 
11     Implemented using the Tensorflow Object Detection API's BoxList class.
12     """
13 
14     def __init__(self, npboxes, class_ids, scores=None):
15         """Construct a set of object detection labels.
16 
17         Args:
18             npboxes: float numpy array of size nx4 with cols
19                 ymin, xmin, ymax, xmax. Should be in pixel coordinates within
20                 the global frame of reference.
21             class_ids: int numpy array of size n with class ids starting at 1
22             scores: float numpy array of size n
23         """
24         # Lazily load TF Object Detection
25         from object_detection.utils.np_box_list import BoxList
26 
27         self.boxlist = BoxList(npboxes)
28         # This field name actually needs to be 'classes' to be able to use
29         # certain utility functions in the TF Object Detection API.
30         self.boxlist.add_field('classes', class_ids)
31         # We need to ensure that there is always a scores field so that the
32         # concatenate method will work with empty labels objects.
33         if scores is None:
34             scores = np.ones(class_ids.shape)
35         self.boxlist.add_field('scores', scores)
36 
37     def __add__(self, other):
38         return ObjectDetectionLabels.concatenate(self, other)
39 
40     def __eq__(self, other):
41         return (isinstance(other, ObjectDetectionLabels)
42                 and self.to_dict() == other.to_dict())
43 
44     def assert_equal(self, expected_labels):
45         np.testing.assert_array_equal(self.get_npboxes(),
46                                       expected_labels.get_npboxes())
47         np.testing.assert_array_equal(self.get_class_ids(),
48                                       expected_labels.get_class_ids())
49         np.testing.assert_array_equal(self.get_scores(),
50                                       expected_labels.get_scores())
51 
52     def filter_by_aoi(self, aoi_polygons):
53         boxes = self.get_boxes()
54         class_ids = self.get_class_ids()
55         scores = self.get_scores()
56 
57         new_boxes = []
58         new_class_ids = []
59         new_scores = []
60         for box, class_id, score in zip(boxes, class_ids, scores):
61             box_poly = box.to_shapely()
62             for aoi in aoi_polygons:
63                 if box_poly.within(aoi):
64                     new_boxes.append(box)
65                     new_class_ids.append(class_id)
66                     new_scores.append(score)
67                     break
68 
69         return ObjectDetectionLabels(
70             np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))
71 
72     @staticmethod
73     def make_empty():
74         npboxes = np.empty((0, 4))
75         class_ids = np.empty((0, ))
76         scores = np.empty((0, ))
77         return ObjectDetectionLabels(npboxes, class_ids, scores)
78 
79     @staticmethod
80     def from_boxlist(boxlist):
81         """Make ObjectDetectionLabels from BoxList object."""
82         scores = (boxlist.get_field('scores')
83                   if boxlist.has_field('scores') else None)
84         return ObjectDetectionLabels(
85             boxlist.get(), boxlist.get_field('classes'), scores=scores)
86 
87     @staticmethod
88     def from_geojson(geojson, extent=None):
89         """Convert GeoJSON to ObjectDetectionLabels object.
90 
91         If extent is provided, filter out the boxes that lie "more than a little
92         bit" outside the extent.
93 
94         Args:
95             geojson: (dict) normalized GeoJSON (see VectorSource)
96             extent: (Box) in pixel coords
97 
98         Returns:
99             ObjectDetectionLabels
100         """
101         boxes = []
102         class_ids = []
103         scores = []
104 
105         for f in geojson['features']:
106             geom = shape(f['geometry'])
107             (xmin, ymin, xmax, ymax) = geom.bounds
108             boxes.append(Box(ymin, xmin, ymax, xmax))
109 
110             props = f['properties']
111             class_ids.append(props['class_id'])
112             scores.append(props.get('score', 1.0))
113 
114         if len(boxes):
115             boxes = np.array(
116                 [box.npbox_format() for box in boxes], dtype=float)
117             class_ids = np.array(class_ids)
118             scores = np.array(scores)
119             labels = ObjectDetectionLabels(boxes, class_ids, scores=scores)
120         else:
121             labels = ObjectDetectionLabels.make_empty()
122 
123         if extent is not None:
124             labels = ObjectDetectionLabels.get_overlapping(
125                 labels, extent, ioa_thresh=0.8, clip=True)
126         return labels
127 
128     def get_boxes(self):
129         """Return list of Boxes."""
130         return [Box.from_npbox(npbox) for npbox in self.boxlist.get()]
131 
132     def get_npboxes(self):
133         return self.boxlist.get()
134 
135     def get_scores(self):
136         if self.boxlist.has_field('scores'):
137             return self.boxlist.get_field('scores')
138         return None
139 
140     def get_class_ids(self):
141         return self.boxlist.get_field('classes')
142 
143     def __len__(self):
144         return self.boxlist.get().shape[0]
145 
146     def __str__(self):
147         return str(self.boxlist.get())
148 
149     def to_boxlist(self):
150         return self.boxlist
151 
152     def to_dict(self):
153         """Returns a dict version of these labels.
154 
155         The Dict has a Box as a key, and a tuple of (class_id, score)
156         as the values.
157         """
158         d = {}
159         boxes = list(map(Box.from_npbox, self.get_npboxes()))
160         classes = list(self.get_class_ids())
161         scores = list(self.get_scores())
162         for box, class_id, score in zip(boxes, classes, scores):
163             d[box.tuple_format()] = (class_id, score)
164         return d
165 
166     @staticmethod
167     def local_to_global(npboxes, window):
168         """Convert from local to global coordinates.
169 
170         The local coordinates are row/col within the window frame of reference.
171         The global coordinates are row/col within the extent of a RasterSource.
172         """
173         xmin = window.xmin
174         ymin = window.ymin
175         return npboxes + np.array([[ymin, xmin, ymin, xmin]])
176 
177     @staticmethod
178     def global_to_local(npboxes, window):
179         """Convert from global to local coordinates.
180 
181         The global coordinates are row/col within the extent of a RasterSource.
182         The local coordinates are row/col within the window frame of reference.
183         """
184         xmin = window.xmin
185         ymin = window.ymin
186         return npboxes - np.array([[ymin, xmin, ymin, xmin]])
187 
188     @staticmethod
189     def local_to_normalized(npboxes, window):
190         """Convert from local to normalized coordinates.
191 
192         The local coordinates are row/col within the window frame of reference.
193         Normalized coordinates range from 0 to 1 on each (height/width) axis.
194         """
195         height = window.get_height()
196         width = window.get_width()
197         return npboxes / np.array([[height, width, height, width]])
198 
199     @staticmethod
200     def normalized_to_local(npboxes, window):
201         """Convert from normalized to local coordinates.
202 
203         Normalized coordinates range from 0 to 1 on each (height/width) axis.
204         The local coordinates are row/col within the window frame of reference.
205         """
206         height = window.get_height()
207         width = window.get_width()
208         return npboxes * np.array([[height, width, height, width]])
209 
210     @staticmethod
211     def get_overlapping(labels, window, ioa_thresh=0.000001, clip=False):
212         """Return subset of labels that overlap with window.
213 
214         Args:
215             labels: ObjectDetectionLabels
216             window: Box
217             ioa_thresh: the minimum IOA for a box to be considered as
218                 overlapping
219             clip: if True, clip label boxes to the window
220         """
221         # Lazily load TF Object Detection
222         from object_detection.utils.np_box_list import BoxList
223         from object_detection.utils.np_box_list_ops import (
224             prune_non_overlapping_boxes, clip_to_window)
225 
226         window_npbox = window.npbox_format()
227         window_boxlist = BoxList(np.expand_dims(window_npbox, axis=0))
228         boxlist = prune_non_overlapping_boxes(
229             labels.boxlist, window_boxlist, minoverlap=ioa_thresh)
230         if clip:
231             boxlist = clip_to_window(boxlist, window_npbox)
232 
233         return ObjectDetectionLabels.from_boxlist(boxlist)
234 
235     @staticmethod
236     def concatenate(labels1, labels2):
237         """Return concatenation of labels.
238 
239         Args:
240             labels1: ObjectDetectionLabels
241             labels2: ObjectDetectionLabels
242         """
243         from object_detection.utils.np_box_list_ops import concatenate
244 
245         new_boxlist = concatenate([labels1.to_boxlist(), labels2.to_boxlist()])
246         return ObjectDetectionLabels.from_boxlist(new_boxlist)
247 
248     @staticmethod
249     def prune_duplicates(labels, score_thresh, merge_thresh):
250         """Remove duplicate boxes.
251 
252         Runs non-maximum suppression to remove duplicate boxes that result from
253         sliding window prediction algorithm.
254 
255         Args:
256             labels: ObjectDetectionLabels
257             score_thresh: the minimum allowed score of boxes
258             merge_thresh: the minimum IOA allowed when merging two boxes
259                 together
260 
261         Returns:
262             ObjectDetectionLabels
263         """
264         from object_detection.utils.np_box_list_ops import non_max_suppression
265 
266         max_output_size = 1000000
267         pruned_boxlist = non_max_suppression(
268             labels.boxlist,
269             max_output_size=max_output_size,
270             iou_threshold=merge_thresh,
271             score_threshold=score_thresh)
272         return ObjectDetectionLabels.from_boxlist(pruned_boxlist)
273
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
             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))

{"golden_diff": "diff --git a/rastervision/data/label/object_detection_labels.py b/rastervision/data/label/object_detection_labels.py\n--- a/rastervision/data/label/object_detection_labels.py\n+++ b/rastervision/data/label/object_detection_labels.py\n@@ -61,11 +61,14 @@\n             box_poly = box.to_shapely()\n             for aoi in aoi_polygons:\n                 if box_poly.within(aoi):\n-                    new_boxes.append(box)\n+                    new_boxes.append(box.npbox_format())\n                     new_class_ids.append(class_id)\n                     new_scores.append(score)\n                     break\n \n+        if len(new_boxes) == 0:\n+            return ObjectDetectionLabels.make_empty()\n+\n         return ObjectDetectionLabels(\n             np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))\n", "issue": "Evaluation for object detection with AOIs crashes\n```\r\nRunning evaluator: ObjectDetectionEvaluator...\r\n2019-03-28 16:47:07:rastervision.evaluation.classification_evaluator: INFO - Computing evaluation for scene 01986917-30ea-4f7f-8e01-985d73b8aa2a...\r\nTraceback (most recent call last):\r\n  File \"/usr/lib/python3.5/runpy.py\", line 184, in _run_module_as_main\r\n    \"__main__\", mod_spec)\r\n  File \"/usr/lib/python3.5/runpy.py\", line 85, in _run_code\r\n    exec(code, run_globals)\r\n  File \"/opt/src/rastervision/__main__.py\", line 17, in <module>\r\n    rv.main()\r\n  File \"/usr/local/lib/python3.5/dist-packages/click/core.py\", line 722, in __call__\r\n    return self.main(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.5/dist-packages/click/core.py\", line 697, in main\r\n    rv = self.invoke(ctx)\r\n  File \"/usr/local/lib/python3.5/dist-packages/click/core.py\", line 1066, in invoke\r\n    return _process_result(sub_ctx.command.invoke(sub_ctx))\r\n  File \"/usr/local/lib/python3.5/dist-packages/click/core.py\", line 895, in invoke\r\n    return ctx.invoke(self.callback, **ctx.params)\r\n  File \"/usr/local/lib/python3.5/dist-packages/click/core.py\", line 535, in invoke\r\n    return callback(*args, **kwargs)\r\n  File \"/opt/src/rastervision/cli/main.py\", line 260, in run_command\r\n    rv.runner.CommandRunner.run(command_config_uri)\r\n  File \"/opt/src/rastervision/runner/command_runner.py\", line 11, in run\r\n    CommandRunner.run_from_proto(msg)\r\n  File \"/opt/src/rastervision/runner/command_runner.py\", line 17, in run_from_proto\r\n    command.run()\r\n  File \"/opt/src/rastervision/command/eval_command.py\", line 24, in run\r\n    evaluator.process(scenes, tmp_dir)\r\n  File \"/opt/src/rastervision/evaluation/classification_evaluator.py\", line 36, in process\r\n    scene.aoi_polygons)\r\n  File \"/opt/src/rastervision/data/label/object_detection_labels.py\", line 70, in filter_by_aoi\r\n    np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))\r\n  File \"/opt/src/rastervision/data/label/object_detection_labels.py\", line 27, in __init__\r\n    self.boxlist = BoxList(npboxes)\r\n  File \"/opt/tf-models/object_detection/utils/np_box_list.py\", line 46, in __init__\r\n    raise ValueError('Invalid dimensions for box data.')\r\nValueError: Invalid dimensions for box data.\r\n/tmp/tmpwie3_vrf/tmp41bj3kgh/Makefile:9: recipe for target '3' failed\r\nmake: *** [3] Error 1\r\nmake: *** Waiting for unfinished jobs....\r\n```\n", "before_files": [{"content": "import numpy as np\nfrom shapely.geometry import shape\n\nfrom rastervision.core.box import Box\nfrom rastervision.data.label import Labels\n\n\nclass ObjectDetectionLabels(Labels):\n    \"\"\"A set of boxes and associated class_ids and scores.\n\n    Implemented using the Tensorflow Object Detection API's BoxList class.\n    \"\"\"\n\n    def __init__(self, npboxes, class_ids, scores=None):\n        \"\"\"Construct a set of object detection labels.\n\n        Args:\n            npboxes: float numpy array of size nx4 with cols\n                ymin, xmin, ymax, xmax. Should be in pixel coordinates within\n                the global frame of reference.\n            class_ids: int numpy array of size n with class ids starting at 1\n            scores: float numpy array of size n\n        \"\"\"\n        # Lazily load TF Object Detection\n        from object_detection.utils.np_box_list import BoxList\n\n        self.boxlist = BoxList(npboxes)\n        # This field name actually needs to be 'classes' to be able to use\n        # certain utility functions in the TF Object Detection API.\n        self.boxlist.add_field('classes', class_ids)\n        # We need to ensure that there is always a scores field so that the\n        # concatenate method will work with empty labels objects.\n        if scores is None:\n            scores = np.ones(class_ids.shape)\n        self.boxlist.add_field('scores', scores)\n\n    def __add__(self, other):\n        return ObjectDetectionLabels.concatenate(self, other)\n\n    def __eq__(self, other):\n        return (isinstance(other, ObjectDetectionLabels)\n                and self.to_dict() == other.to_dict())\n\n    def assert_equal(self, expected_labels):\n        np.testing.assert_array_equal(self.get_npboxes(),\n                                      expected_labels.get_npboxes())\n        np.testing.assert_array_equal(self.get_class_ids(),\n                                      expected_labels.get_class_ids())\n        np.testing.assert_array_equal(self.get_scores(),\n                                      expected_labels.get_scores())\n\n    def filter_by_aoi(self, aoi_polygons):\n        boxes = self.get_boxes()\n        class_ids = self.get_class_ids()\n        scores = self.get_scores()\n\n        new_boxes = []\n        new_class_ids = []\n        new_scores = []\n        for box, class_id, score in zip(boxes, class_ids, scores):\n            box_poly = box.to_shapely()\n            for aoi in aoi_polygons:\n                if box_poly.within(aoi):\n                    new_boxes.append(box)\n                    new_class_ids.append(class_id)\n                    new_scores.append(score)\n                    break\n\n        return ObjectDetectionLabels(\n            np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))\n\n    @staticmethod\n    def make_empty():\n        npboxes = np.empty((0, 4))\n        class_ids = np.empty((0, ))\n        scores = np.empty((0, ))\n        return ObjectDetectionLabels(npboxes, class_ids, scores)\n\n    @staticmethod\n    def from_boxlist(boxlist):\n        \"\"\"Make ObjectDetectionLabels from BoxList object.\"\"\"\n        scores = (boxlist.get_field('scores')\n                  if boxlist.has_field('scores') else None)\n        return ObjectDetectionLabels(\n            boxlist.get(), boxlist.get_field('classes'), scores=scores)\n\n    @staticmethod\n    def from_geojson(geojson, extent=None):\n        \"\"\"Convert GeoJSON to ObjectDetectionLabels object.\n\n        If extent is provided, filter out the boxes that lie \"more than a little\n        bit\" outside the extent.\n\n        Args:\n            geojson: (dict) normalized GeoJSON (see VectorSource)\n            extent: (Box) in pixel coords\n\n        Returns:\n            ObjectDetectionLabels\n        \"\"\"\n        boxes = []\n        class_ids = []\n        scores = []\n\n        for f in geojson['features']:\n            geom = shape(f['geometry'])\n            (xmin, ymin, xmax, ymax) = geom.bounds\n            boxes.append(Box(ymin, xmin, ymax, xmax))\n\n            props = f['properties']\n            class_ids.append(props['class_id'])\n            scores.append(props.get('score', 1.0))\n\n        if len(boxes):\n            boxes = np.array(\n                [box.npbox_format() for box in boxes], dtype=float)\n            class_ids = np.array(class_ids)\n            scores = np.array(scores)\n            labels = ObjectDetectionLabels(boxes, class_ids, scores=scores)\n        else:\n            labels = ObjectDetectionLabels.make_empty()\n\n        if extent is not None:\n            labels = ObjectDetectionLabels.get_overlapping(\n                labels, extent, ioa_thresh=0.8, clip=True)\n        return labels\n\n    def get_boxes(self):\n        \"\"\"Return list of Boxes.\"\"\"\n        return [Box.from_npbox(npbox) for npbox in self.boxlist.get()]\n\n    def get_npboxes(self):\n        return self.boxlist.get()\n\n    def get_scores(self):\n        if self.boxlist.has_field('scores'):\n            return self.boxlist.get_field('scores')\n        return None\n\n    def get_class_ids(self):\n        return self.boxlist.get_field('classes')\n\n    def __len__(self):\n        return self.boxlist.get().shape[0]\n\n    def __str__(self):\n        return str(self.boxlist.get())\n\n    def to_boxlist(self):\n        return self.boxlist\n\n    def to_dict(self):\n        \"\"\"Returns a dict version of these labels.\n\n        The Dict has a Box as a key, and a tuple of (class_id, score)\n        as the values.\n        \"\"\"\n        d = {}\n        boxes = list(map(Box.from_npbox, self.get_npboxes()))\n        classes = list(self.get_class_ids())\n        scores = list(self.get_scores())\n        for box, class_id, score in zip(boxes, classes, scores):\n            d[box.tuple_format()] = (class_id, score)\n        return d\n\n    @staticmethod\n    def local_to_global(npboxes, window):\n        \"\"\"Convert from local to global coordinates.\n\n        The local coordinates are row/col within the window frame of reference.\n        The global coordinates are row/col within the extent of a RasterSource.\n        \"\"\"\n        xmin = window.xmin\n        ymin = window.ymin\n        return npboxes + np.array([[ymin, xmin, ymin, xmin]])\n\n    @staticmethod\n    def global_to_local(npboxes, window):\n        \"\"\"Convert from global to local coordinates.\n\n        The global coordinates are row/col within the extent of a RasterSource.\n        The local coordinates are row/col within the window frame of reference.\n        \"\"\"\n        xmin = window.xmin\n        ymin = window.ymin\n        return npboxes - np.array([[ymin, xmin, ymin, xmin]])\n\n    @staticmethod\n    def local_to_normalized(npboxes, window):\n        \"\"\"Convert from local to normalized coordinates.\n\n        The local coordinates are row/col within the window frame of reference.\n        Normalized coordinates range from 0 to 1 on each (height/width) axis.\n        \"\"\"\n        height = window.get_height()\n        width = window.get_width()\n        return npboxes / np.array([[height, width, height, width]])\n\n    @staticmethod\n    def normalized_to_local(npboxes, window):\n        \"\"\"Convert from normalized to local coordinates.\n\n        Normalized coordinates range from 0 to 1 on each (height/width) axis.\n        The local coordinates are row/col within the window frame of reference.\n        \"\"\"\n        height = window.get_height()\n        width = window.get_width()\n        return npboxes * np.array([[height, width, height, width]])\n\n    @staticmethod\n    def get_overlapping(labels, window, ioa_thresh=0.000001, clip=False):\n        \"\"\"Return subset of labels that overlap with window.\n\n        Args:\n            labels: ObjectDetectionLabels\n            window: Box\n            ioa_thresh: the minimum IOA for a box to be considered as\n                overlapping\n            clip: if True, clip label boxes to the window\n        \"\"\"\n        # Lazily load TF Object Detection\n        from object_detection.utils.np_box_list import BoxList\n        from object_detection.utils.np_box_list_ops import (\n            prune_non_overlapping_boxes, clip_to_window)\n\n        window_npbox = window.npbox_format()\n        window_boxlist = BoxList(np.expand_dims(window_npbox, axis=0))\n        boxlist = prune_non_overlapping_boxes(\n            labels.boxlist, window_boxlist, minoverlap=ioa_thresh)\n        if clip:\n            boxlist = clip_to_window(boxlist, window_npbox)\n\n        return ObjectDetectionLabels.from_boxlist(boxlist)\n\n    @staticmethod\n    def concatenate(labels1, labels2):\n        \"\"\"Return concatenation of labels.\n\n        Args:\n            labels1: ObjectDetectionLabels\n            labels2: ObjectDetectionLabels\n        \"\"\"\n        from object_detection.utils.np_box_list_ops import concatenate\n\n        new_boxlist = concatenate([labels1.to_boxlist(), labels2.to_boxlist()])\n        return ObjectDetectionLabels.from_boxlist(new_boxlist)\n\n    @staticmethod\n    def prune_duplicates(labels, score_thresh, merge_thresh):\n        \"\"\"Remove duplicate boxes.\n\n        Runs non-maximum suppression to remove duplicate boxes that result from\n        sliding window prediction algorithm.\n\n        Args:\n            labels: ObjectDetectionLabels\n            score_thresh: the minimum allowed score of boxes\n            merge_thresh: the minimum IOA allowed when merging two boxes\n                together\n\n        Returns:\n            ObjectDetectionLabels\n        \"\"\"\n        from object_detection.utils.np_box_list_ops import non_max_suppression\n\n        max_output_size = 1000000\n        pruned_boxlist = non_max_suppression(\n            labels.boxlist,\n            max_output_size=max_output_size,\n            iou_threshold=merge_thresh,\n            score_threshold=score_thresh)\n        return ObjectDetectionLabels.from_boxlist(pruned_boxlist)\n", "path": "rastervision/data/label/object_detection_labels.py"}], "after_files": [{"content": "import numpy as np\nfrom shapely.geometry import shape\n\nfrom rastervision.core.box import Box\nfrom rastervision.data.label import Labels\n\n\nclass ObjectDetectionLabels(Labels):\n    \"\"\"A set of boxes and associated class_ids and scores.\n\n    Implemented using the Tensorflow Object Detection API's BoxList class.\n    \"\"\"\n\n    def __init__(self, npboxes, class_ids, scores=None):\n        \"\"\"Construct a set of object detection labels.\n\n        Args:\n            npboxes: float numpy array of size nx4 with cols\n                ymin, xmin, ymax, xmax. Should be in pixel coordinates within\n                the global frame of reference.\n            class_ids: int numpy array of size n with class ids starting at 1\n            scores: float numpy array of size n\n        \"\"\"\n        # Lazily load TF Object Detection\n        from object_detection.utils.np_box_list import BoxList\n\n        self.boxlist = BoxList(npboxes)\n        # This field name actually needs to be 'classes' to be able to use\n        # certain utility functions in the TF Object Detection API.\n        self.boxlist.add_field('classes', class_ids)\n        # We need to ensure that there is always a scores field so that the\n        # concatenate method will work with empty labels objects.\n        if scores is None:\n            scores = np.ones(class_ids.shape)\n        self.boxlist.add_field('scores', scores)\n\n    def __add__(self, other):\n        return ObjectDetectionLabels.concatenate(self, other)\n\n    def __eq__(self, other):\n        return (isinstance(other, ObjectDetectionLabels)\n                and self.to_dict() == other.to_dict())\n\n    def assert_equal(self, expected_labels):\n        np.testing.assert_array_equal(self.get_npboxes(),\n                                      expected_labels.get_npboxes())\n        np.testing.assert_array_equal(self.get_class_ids(),\n                                      expected_labels.get_class_ids())\n        np.testing.assert_array_equal(self.get_scores(),\n                                      expected_labels.get_scores())\n\n    def filter_by_aoi(self, aoi_polygons):\n        boxes = self.get_boxes()\n        class_ids = self.get_class_ids()\n        scores = self.get_scores()\n\n        new_boxes = []\n        new_class_ids = []\n        new_scores = []\n        for box, class_id, score in zip(boxes, class_ids, scores):\n            box_poly = box.to_shapely()\n            for aoi in aoi_polygons:\n                if box_poly.within(aoi):\n                    new_boxes.append(box.npbox_format())\n                    new_class_ids.append(class_id)\n                    new_scores.append(score)\n                    break\n\n        if len(new_boxes) == 0:\n            return ObjectDetectionLabels.make_empty()\n\n        return ObjectDetectionLabels(\n            np.array(new_boxes), np.array(new_class_ids), np.array(new_scores))\n\n    @staticmethod\n    def make_empty():\n        npboxes = np.empty((0, 4))\n        class_ids = np.empty((0, ))\n        scores = np.empty((0, ))\n        return ObjectDetectionLabels(npboxes, class_ids, scores)\n\n    @staticmethod\n    def from_boxlist(boxlist):\n        \"\"\"Make ObjectDetectionLabels from BoxList object.\"\"\"\n        scores = (boxlist.get_field('scores')\n                  if boxlist.has_field('scores') else None)\n        return ObjectDetectionLabels(\n            boxlist.get(), boxlist.get_field('classes'), scores=scores)\n\n    @staticmethod\n    def from_geojson(geojson, extent=None):\n        \"\"\"Convert GeoJSON to ObjectDetectionLabels object.\n\n        If extent is provided, filter out the boxes that lie \"more than a little\n        bit\" outside the extent.\n\n        Args:\n            geojson: (dict) normalized GeoJSON (see VectorSource)\n            extent: (Box) in pixel coords\n\n        Returns:\n            ObjectDetectionLabels\n        \"\"\"\n        boxes = []\n        class_ids = []\n        scores = []\n\n        for f in geojson['features']:\n            geom = shape(f['geometry'])\n            (xmin, ymin, xmax, ymax) = geom.bounds\n            boxes.append(Box(ymin, xmin, ymax, xmax))\n\n            props = f['properties']\n            class_ids.append(props['class_id'])\n            scores.append(props.get('score', 1.0))\n\n        if len(boxes):\n            boxes = np.array(\n                [box.npbox_format() for box in boxes], dtype=float)\n            class_ids = np.array(class_ids)\n            scores = np.array(scores)\n            labels = ObjectDetectionLabels(boxes, class_ids, scores=scores)\n        else:\n            labels = ObjectDetectionLabels.make_empty()\n\n        if extent is not None:\n            labels = ObjectDetectionLabels.get_overlapping(\n                labels, extent, ioa_thresh=0.8, clip=True)\n        return labels\n\n    def get_boxes(self):\n        \"\"\"Return list of Boxes.\"\"\"\n        return [Box.from_npbox(npbox) for npbox in self.boxlist.get()]\n\n    def get_npboxes(self):\n        return self.boxlist.get()\n\n    def get_scores(self):\n        if self.boxlist.has_field('scores'):\n            return self.boxlist.get_field('scores')\n        return None\n\n    def get_class_ids(self):\n        return self.boxlist.get_field('classes')\n\n    def __len__(self):\n        return self.boxlist.get().shape[0]\n\n    def __str__(self):\n        return str(self.boxlist.get())\n\n    def to_boxlist(self):\n        return self.boxlist\n\n    def to_dict(self):\n        \"\"\"Returns a dict version of these labels.\n\n        The Dict has a Box as a key, and a tuple of (class_id, score)\n        as the values.\n        \"\"\"\n        d = {}\n        boxes = list(map(Box.from_npbox, self.get_npboxes()))\n        classes = list(self.get_class_ids())\n        scores = list(self.get_scores())\n        for box, class_id, score in zip(boxes, classes, scores):\n            d[box.tuple_format()] = (class_id, score)\n        return d\n\n    @staticmethod\n    def local_to_global(npboxes, window):\n        \"\"\"Convert from local to global coordinates.\n\n        The local coordinates are row/col within the window frame of reference.\n        The global coordinates are row/col within the extent of a RasterSource.\n        \"\"\"\n        xmin = window.xmin\n        ymin = window.ymin\n        return npboxes + np.array([[ymin, xmin, ymin, xmin]])\n\n    @staticmethod\n    def global_to_local(npboxes, window):\n        \"\"\"Convert from global to local coordinates.\n\n        The global coordinates are row/col within the extent of a RasterSource.\n        The local coordinates are row/col within the window frame of reference.\n        \"\"\"\n        xmin = window.xmin\n        ymin = window.ymin\n        return npboxes - np.array([[ymin, xmin, ymin, xmin]])\n\n    @staticmethod\n    def local_to_normalized(npboxes, window):\n        \"\"\"Convert from local to normalized coordinates.\n\n        The local coordinates are row/col within the window frame of reference.\n        Normalized coordinates range from 0 to 1 on each (height/width) axis.\n        \"\"\"\n        height = window.get_height()\n        width = window.get_width()\n        return npboxes / np.array([[height, width, height, width]])\n\n    @staticmethod\n    def normalized_to_local(npboxes, window):\n        \"\"\"Convert from normalized to local coordinates.\n\n        Normalized coordinates range from 0 to 1 on each (height/width) axis.\n        The local coordinates are row/col within the window frame of reference.\n        \"\"\"\n        height = window.get_height()\n        width = window.get_width()\n        return npboxes * np.array([[height, width, height, width]])\n\n    @staticmethod\n    def get_overlapping(labels, window, ioa_thresh=0.000001, clip=False):\n        \"\"\"Return subset of labels that overlap with window.\n\n        Args:\n            labels: ObjectDetectionLabels\n            window: Box\n            ioa_thresh: the minimum IOA for a box to be considered as\n                overlapping\n            clip: if True, clip label boxes to the window\n        \"\"\"\n        # Lazily load TF Object Detection\n        from object_detection.utils.np_box_list import BoxList\n        from object_detection.utils.np_box_list_ops import (\n            prune_non_overlapping_boxes, clip_to_window)\n\n        window_npbox = window.npbox_format()\n        window_boxlist = BoxList(np.expand_dims(window_npbox, axis=0))\n        boxlist = prune_non_overlapping_boxes(\n            labels.boxlist, window_boxlist, minoverlap=ioa_thresh)\n        if clip:\n            boxlist = clip_to_window(boxlist, window_npbox)\n\n        return ObjectDetectionLabels.from_boxlist(boxlist)\n\n    @staticmethod\n    def concatenate(labels1, labels2):\n        \"\"\"Return concatenation of labels.\n\n        Args:\n            labels1: ObjectDetectionLabels\n            labels2: ObjectDetectionLabels\n        \"\"\"\n        from object_detection.utils.np_box_list_ops import concatenate\n\n        new_boxlist = concatenate([labels1.to_boxlist(), labels2.to_boxlist()])\n        return ObjectDetectionLabels.from_boxlist(new_boxlist)\n\n    @staticmethod\n    def prune_duplicates(labels, score_thresh, merge_thresh):\n        \"\"\"Remove duplicate boxes.\n\n        Runs non-maximum suppression to remove duplicate boxes that result from\n        sliding window prediction algorithm.\n\n        Args:\n            labels: ObjectDetectionLabels\n            score_thresh: the minimum allowed score of boxes\n            merge_thresh: the minimum IOA allowed when merging two boxes\n                together\n\n        Returns:\n            ObjectDetectionLabels\n        \"\"\"\n        from object_detection.utils.np_box_list_ops import non_max_suppression\n\n        max_output_size = 1000000\n        pruned_boxlist = non_max_suppression(\n            labels.boxlist,\n            max_output_size=max_output_size,\n            iou_threshold=merge_thresh,\n            score_threshold=score_thresh)\n        return ObjectDetectionLabels.from_boxlist(pruned_boxlist)\n", "path": "rastervision/data/label/object_detection_labels.py"}]}