def setUp(self):
        self.windows = [
            Box.make_square(0, 0, 10),
            Box.make_square(0, 5, 10),
            Box.make_square(0, 10, 10)
        ]
        self.num_classes = 3
        self.scores_left = make_random_scores(self.num_classes, 10, 10)
        self.scores_mid = make_random_scores(self.num_classes, 10, 10)
        self.scores_right = make_random_scores(self.num_classes, 10, 10)

        self.scores_left = self.scores_left.astype(np.float16)
        self.scores_mid = self.scores_mid.astype(np.float16)
        self.scores_right = self.scores_right.astype(np.float16)

        self.extent = Box(0, 0, 10, 20)
        self.labels = SemanticSegmentationSmoothLabels(
            extent=self.extent, num_classes=self.num_classes)
        self.labels[self.windows[0]] = self.scores_left
        self.labels[self.windows[1]] = self.scores_mid
        self.labels[self.windows[2]] = self.scores_right

        arr = np.zeros((self.num_classes, 10, 20), dtype=np.float16)
        arr[..., :10] += self.scores_left
        arr[..., 5:15] += self.scores_mid
        arr[..., 10:] += self.scores_right
        self.expected_scores = arr

        hits = np.zeros((10, 20), dtype=np.uint8)
        hits[..., :10] += 1
        hits[..., 5:15] += 1
        hits[..., 10:] += 1
        self.expected_hits = hits
Ejemplo n.º 2
0
    def test_get_labels_inferred(self):
        extent = Box.make_square(0, 0, 8)

        msg = rv.LabelSourceConfig.builder(rv.CHIP_CLASSIFICATION) \
                .with_uri(self.uri) \
                .with_ioa_thresh(0.5) \
                .with_use_intersection_over_cell(False) \
                .with_pick_min_class_id(False) \
                .with_background_class_id(self.background_class_id) \
                .with_infer_cells(True) \
                .with_cell_size(4) \
                .build().to_proto()
        config = rv.LabelSourceConfig.builder(rv.CHIP_CLASSIFICATION) \
                   .from_proto(msg).build()
        source = config.create_source(self.task_config, extent,
                                      self.crs_transformer, self.temp_dir.name)

        labels = source.get_labels()
        cells = labels.get_cells()

        self.assertEqual(len(cells), 4)
        self.assertEqual(labels.get_cell_class_id(self.box1), self.class_id1)
        self.assertEqual(labels.get_cell_class_id(self.box2), self.class_id2)
        self.assertEqual(labels.get_cell_class_id(Box.make_square(0, 4, 4)),
                         self.background_class_id)
        self.assertEqual(labels.get_cell_class_id(Box.make_square(4, 0, 4)),
                         self.background_class_id)
Ejemplo n.º 3
0
    def test_read_with_extent(self):
        # Extent only includes the first box.
        extent = Box.make_square(0, 0, 3)
        store = ObjectDetectionLabelSource(self.file_path,
                                           self.crs_transformer,
                                           self.class_map,
                                           extent=extent)
        labels = store.get_labels()

        npboxes = np.array([[0., 0., 2., 2.]])
        class_ids = np.array([1])
        scores = np.array([0.9])
        expected_labels = ObjectDetectionLabels(npboxes,
                                                class_ids,
                                                scores=scores)
        labels.assert_equal(expected_labels)

        # Extent includes both boxes, but clips the second.
        extent = Box.make_square(0, 0, 3.9)
        store = ObjectDetectionLabelSource(self.file_path,
                                           self.crs_transformer,
                                           self.class_map,
                                           extent=extent)
        labels = store.get_labels()

        npboxes = np.array([[0., 0., 2., 2.], [2., 2., 3.9, 3.9]])
        class_ids = np.array([1, 2])
        scores = np.array([0.9, 0.9])
        expected_labels = ObjectDetectionLabels(npboxes,
                                                class_ids,
                                                scores=scores)
        labels.assert_equal(expected_labels)
 def setUp(self):
     self.windows = [Box.make_square(0, 0, 10), Box.make_square(0, 10, 10)]
     self.label_arr0 = np.random.choice([0, 1], (10, 10))
     self.label_arr1 = np.random.choice([0, 1], (10, 10))
     self.labels = SemanticSegmentationLabels()
     self.labels.set_label_arr(self.windows[0], self.label_arr0)
     self.labels.set_label_arr(self.windows[1], self.label_arr1)
    def test_get_overlapping(self):
        window = Box.make_square(0, 0, 2.01)
        labels = ObjectDetectionLabels.get_overlapping(self.labels, window)
        labels.assert_equal(self.labels)

        window = Box.make_square(0, 0, 3)
        labels = ObjectDetectionLabels.get_overlapping(
            self.labels, window, ioa_thresh=0.5)
        npboxes = np.array([[0., 0., 2., 2.]])
        class_ids = np.array([1])
        scores = np.array([0.9])
        expected_labels = ObjectDetectionLabels(
            npboxes, class_ids, scores=scores)
        labels.assert_equal(expected_labels)

        window = Box.make_square(0, 0, 3)
        labels = ObjectDetectionLabels.get_overlapping(
            self.labels, window, ioa_thresh=0.1, clip=True)
        expected_npboxes = np.array([
            [0., 0., 2., 2.],
            [2., 2., 3., 3.],
        ])
        expected_labels = ObjectDetectionLabels(
            expected_npboxes, self.class_ids, scores=self.scores)
        labels.assert_equal(expected_labels)
Ejemplo n.º 6
0
def read_labels(geojson, extent=None) -> ChipClassificationLabels:
    """Convert GeoJSON to ChipClassificationLabels.

    If the GeoJSON already contains a grid of cells, then it can be constructed
    in a straightforward manner without having to infer the class of cells.

    If extent is given, only labels that intersect with the extent are returned.

    Args:
        geojson: dict in normalized GeoJSON format (see VectorSource)
        extent: Box in pixel coords

    Returns:
       ChipClassificationLabels
    """
    labels = ChipClassificationLabels()

    for f in geojson['features']:
        geom = shape(f['geometry'])
        (xmin, ymin, xmax, ymax) = geom.bounds
        cell = Box(ymin, xmin, ymax, xmax)
        if extent is not None and not cell.to_shapely().intersects(
                extent.to_shapely()):
            continue

        props = f['properties']
        class_id = props['class_id']
        scores = props.get('scores')
        labels.set_cell(cell, class_id, scores)

    return labels
Ejemplo n.º 7
0
 def test_make_eroded(self):
     max_extent = Box.make_square(0, 0, 10)
     box = Box(1, 1, 3, 4)
     buffer_size = erosion_size = 1
     eroded_box = box.make_buffer(buffer_size, max_extent) \
                     .make_eroded(erosion_size)
     self.assertEqual(eroded_box, box)
 def setUp(self):
     self.windows = [Box.make_square(0, 0, 10), Box.make_square(0, 10, 10)]
     self.label_arr0 = np.random.choice([0, 1], (10, 10))
     self.label_arr1 = np.random.choice([0, 1], (10, 10))
     self.labels = SemanticSegmentationDiscreteLabels()
     self.labels[self.windows[0]] = self.label_arr0
     self.labels[self.windows[1]] = self.label_arr1
Ejemplo n.º 9
0
    def test_nonidentical_extents_and_resolutions(self):
        img_path_1 = data_file_path(
            'multi_raster_source/const_100_600x600.tiff')
        img_path_2 = data_file_path('multi_raster_source/const_175_60x60.tiff')
        img_path_3 = data_file_path('multi_raster_source/const_250_6x6.tiff')
        source_1 = RasterioSourceConfig(uris=[img_path_1], channel_order=[0])
        source_2 = RasterioSourceConfig(uris=[img_path_2], channel_order=[0])
        source_3 = RasterioSourceConfig(uris=[img_path_3], channel_order=[0])

        cfg = MultiRasterSourceConfig(raster_sources=[
            SubRasterSourceConfig(raster_source=source_1, target_channels=[0]),
            SubRasterSourceConfig(raster_source=source_2, target_channels=[1]),
            SubRasterSourceConfig(raster_source=source_3, target_channels=[2])
        ])
        rs = cfg.build(tmp_dir=self.tmp_dir)
        with rs.activate():
            for get_chip_fn in [rs._get_chip, rs.get_chip]:
                ch_1_only = get_chip_fn(Box(0, 0, 10, 10))
                self.assertEqual(tuple(ch_1_only.reshape(-1, 3).mean(axis=0)),
                                 (100, 0, 0))
                ch_2_only = get_chip_fn(Box(0, 600, 10, 600 + 10))
                self.assertEqual(tuple(ch_2_only.reshape(-1, 3).mean(axis=0)),
                                 (0, 175, 0))
                ch_3_only = get_chip_fn(Box(600, 0, 600 + 10, 10))
                self.assertEqual(tuple(ch_3_only.reshape(-1, 3).mean(axis=0)),
                                 (0, 0, 250))
                full_img = get_chip_fn(Box(0, 0, 600, 600))
                self.assertEqual(set(np.unique(full_img[..., 0])), {100})
                self.assertEqual(set(np.unique(full_img[..., 1])), {0, 175})
                self.assertEqual(set(np.unique(full_img[..., 2])), {0, 250})
Ejemplo n.º 10
0
    def setUp(self):
        self.crs_transformer = DoubleCRSTransformer()
        self.geojson = {
            'type':
            'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'geometry': {
                    'type':
                    'MultiPolygon',
                    'coordinates': [[[[0., 0.], [0., 2.], [2., 2.], [2., 0.],
                                      [0., 0.]]]]
                },
                'properties': {
                    'class_name': 'car',
                    'class_id': 1,
                    'score': 0.0
                }
            }, {
                'type': 'Feature',
                'geometry': {
                    'type':
                    'Polygon',
                    'coordinates': [[[2., 2.], [2., 4.], [4., 4.], [4., 2.],
                                     [2., 2.]]]
                },
                'properties': {
                    'score': 0.0,
                    'class_name': 'house',
                    'class_id': 2
                }
            }]
        }

        self.class_map = ClassMap([ClassItem(1, 'car'), ClassItem(2, 'house')])

        class MockTaskConfig():
            def __init__(self, class_map):
                self.class_map = class_map

        self.task_config = MockTaskConfig(self.class_map)

        self.box1 = Box.make_square(0, 0, 4)
        self.box2 = Box.make_square(4, 4, 4)
        self.class_id1 = 1
        self.class_id2 = 2
        self.background_class_id = 3

        geoms = []
        for f in self.geojson['features']:
            g = shape(f['geometry'])
            g.class_id = f['properties']['class_id']
            geoms.append(g)
        self.str_tree = STRtree(geoms)

        self.file_name = 'labels.json'
        self.temp_dir = RVConfig.get_tmp_dir()
        self.uri = os.path.join(self.temp_dir.name, self.file_name)
        json_to_file(self.geojson, self.uri)
Ejemplo n.º 11
0
 def get_extent(self):
     h, w = self.height, self.width
     if self.extent_crop is not None:
         skip_top, skip_left, skip_bottom, skip_right = self.extent_crop
         ymin, xmin = int(h * skip_top), int(w * skip_left)
         ymax, xmax = h - int(h * skip_bottom), w - int(w * skip_right)
         return Box(ymin, xmin, ymax, xmax)
     return Box(0, 0, h, w)
 def make_ground_truth_labels(self):
     size = 100
     nw = Box.make_square(0, 0, size)
     ne = Box.make_square(0, 200, size)
     se = Box.make_square(200, 200, size)
     sw = Box.make_square(200, 0, size)
     npboxes = Box.to_npboxes([nw, ne, se, sw])
     class_ids = np.array([1, 1, 2, 2])
     return ObjectDetectionLabels(npboxes, class_ids)
    def test_filter_by_aoi(self):
        windows = [Box.make_square(0, 0, 2), Box.make_square(0, 2, 2)]
        aoi_polygons = [Box.make_square(0, 0, 3).to_shapely()]

        filt_windows = Box.filter_by_aoi(windows, aoi_polygons, within=False)
        self.assertListEqual(filt_windows, windows)

        filt_windows = Box.filter_by_aoi(windows, aoi_polygons, within=True)
        self.assertListEqual(filt_windows, windows[0:1])
Ejemplo n.º 14
0
 def test_make_random_square(self):
     window = Box(5, 5, 15, 15)
     size = 5
     nb_tests = 100
     for _ in range(nb_tests):
         box = window.make_random_square(size)
         self.assertEqual(box.get_width(), box.get_height())
         self.assertEqual(box.get_width(), size)
         self.assertTrue(window.to_shapely().contains(box.to_shapely()))
    def setUp(self):
        self.labels = ChipClassificationLabels()

        self.cell1 = Box.make_square(0, 0, 2)
        self.class_id1 = 1
        self.labels.set_cell(self.cell1, self.class_id1)

        self.cell2 = Box.make_square(0, 2, 2)
        self.class_id2 = 2
        self.labels.set_cell(self.cell2, self.class_id2)
 def make_predicted_labels(self):
     size = 100
     # Predicted labels are only there for three of the ground truth boxes,
     # and are offset by 10 pixels.
     nw = Box.make_square(10, 0, size)
     ne = Box.make_square(10, 200, size)
     se = Box.make_square(210, 200, size)
     npboxes = Box.to_npboxes([nw, ne, se])
     class_ids = np.array([1, 1, 2])
     scores = np.ones(class_ids.shape)
     return ObjectDetectionLabels(npboxes, class_ids, scores=scores)
Ejemplo n.º 17
0
    def setUp(self):
        self.crs_transformer = DoubleCRSTransformer()
        self.geojson = {
            'type':
            'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'geometry': {
                    'type':
                    'MultiPolygon',
                    'coordinates': [[[[0., 0.], [0., 2.], [2., 2.], [2., 0.],
                                      [0., 0.]]]]
                },
                'properties': {
                    'class_name': 'car',
                    'class_id': 0,
                    'score': 0.0
                }
            }, {
                'type': 'Feature',
                'geometry': {
                    'type':
                    'Polygon',
                    'coordinates': [[[2., 2.], [2., 4.], [4., 4.], [4., 2.],
                                     [2., 2.]]]
                },
                'properties': {
                    'score': 0.0,
                    'class_name': 'house',
                    'class_id': 1
                }
            }]
        }

        self.class_config = ClassConfig(names=['car', 'house'])

        self.box1 = Box.make_square(0, 0, 4)
        self.box2 = Box.make_square(4, 4, 4)
        self.class_id1 = 0
        self.class_id2 = 1
        self.background_class_id = 2

        geoms = []
        for f in self.geojson['features']:
            g = shape(f['geometry'])
            g.class_id = f['properties']['class_id']
            geoms.append(g)
        self.str_tree = STRtree(geoms)

        self.file_name = 'labels.json'
        self.tmp_dir = rv_config.get_tmp_dir()
        self.uri = os.path.join(self.tmp_dir.name, self.file_name)
        json_to_file(self.geojson, self.uri)
Ejemplo n.º 18
0
    def test_make_buffer(self):
        buffer_size = 1
        max_extent = Box.make_square(0, 0, 3)
        buffer_box = Box(0, 0, 3, 3)
        output_buffer_box = self.box.make_buffer(buffer_size, max_extent)
        self.assertEqual(output_buffer_box, buffer_box)

        buffer_size = 0.5
        max_extent = Box.make_square(0, 0, 5)
        buffer_box = Box(0, 0, 3, 5)
        output_buffer_box = self.box.make_buffer(buffer_size, max_extent)
        self.assertEqual(output_buffer_box, buffer_box)
    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)
    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)
    def setUp(self):
        self.windows = [Box.make_square(0, 0, 10), Box.make_square(0, 10, 10)]
        self.label_arr0 = np.random.choice([1, 2], (10, 10))
        self.label_arr1 = np.random.choice([1, 2], (10, 10))

        def label_fn(window):
            if window == self.windows[0]:
                return self.label_arr0.copy()
            elif window == self.windows[1]:
                return self.label_arr1.copy()
            else:
                raise ValueError('Unknown window: {}'.format(window))

        self.label_fn = label_fn
        self.labels = SemanticSegmentationLabels(self.windows, label_fn)
Ejemplo n.º 22
0
    def filter_windows(windows: Sequence[Box]) -> List[Box]:
        """Filter out chips that
        (1) are outside the AOI
        (2) only consist of null labels
        (3) have NODATA proportion >= chip_nodata_threshold
        """
        total_windows = len(windows)
        if scene.aoi_polygons:
            windows = Box.filter_by_aoi(windows, scene.aoi_polygons)
            log.info(f'AOI filtering: {len(windows)}/{total_windows} '
                     'chips accepted')

        filt_windows = []
        for w in windows:
            chip = raster_source.get_chip(w)
            nodata_below_thresh = nodata_below_threshold(
                chip, chip_nodata_threshold, nodata_val=0)

            label_arr = label_source.get_labels(w).get_label_arr(w)
            null_labels = label_arr == class_config.get_null_class_id()

            if not np.all(null_labels) and nodata_below_thresh:
                filt_windows.append(w)
        log.info('Label and NODATA filtering: '
                 f'{len(filt_windows)}/{len(windows)} chips accepted')

        windows = filt_windows
        return windows
    def test_get_with_aoi(self):
        aoi_polygons = [Box.make_square(5, 15, 2).to_shapely()]
        exp_label_arr = self.label_arr1.copy()
        mask = np.zeros(exp_label_arr.shape)
        mask[5:7, 5:7] = 1
        exp_label_arr = exp_label_arr * mask

        labels = self.labels.filter_by_aoi(aoi_polygons)
        label_arr = labels.get_label_arr(self.windows[1])
        np.testing.assert_array_equal(label_arr, exp_label_arr)

        # Set clip_extent
        clip_extent = Box(0, 0, 10, 18)
        label_arr = labels.get_label_arr(self.windows[1],
                                         clip_extent=clip_extent)
        np.testing.assert_array_equal(label_arr, exp_label_arr[:, 0:8])
Ejemplo n.º 24
0
    def __init__(self,
                 uris,
                 raster_transformers,
                 tmp_dir,
                 channel_order=None,
                 x_shift=0.0,
                 y_shift=0.0):
        """Constructor.

        This RasterSource can read any file that can be opened by Rasterio/GDAL
        including georeferenced formats such as GeoTIFF and non-georeferenced formats
        such as JPG. See https://www.gdal.org/formats_list.html for more details.

        If channel_order is None, then use non-alpha channels. This also sets any
        masked or NODATA pixel values to be zeros.

        Args:
            channel_order: list of indices of channels to extract from raw imagery
        """
        self.uris = uris
        self.tmp_dir = tmp_dir
        self.image_tmp_dir = None
        self.image_dataset = None
        self.x_shift = x_shift
        self.y_shift = y_shift
        self.do_shift = self.x_shift != 0.0 or self.y_shift != 0.0

        num_channels = None

        # Activate in order to get information out of the raster
        with self.activate():
            num_channels = self.image_dataset.count
            if channel_order is None:
                colorinterp = self.image_dataset.colorinterp
                if colorinterp:
                    channel_order = [
                        i for i, color_interp in enumerate(colorinterp)
                        if color_interp != ColorInterp.alpha
                    ]
                else:
                    channel_order = list(range(0, num_channels))
            self.validate_channel_order(channel_order, num_channels)

            mask_flags = self.image_dataset.mask_flag_enums
            self.is_masked = any(
                [m for m in mask_flags if m != MaskFlags.all_valid])

            self.height = self.image_dataset.height
            self.width = self.image_dataset.width

            # Get 1x1 chip and apply raster transformers to test dtype.
            test_chip = self.get_raw_chip(Box.make_square(0, 0, 1))
            test_chip = test_chip[:, :, channel_order]
            for transformer in raster_transformers:
                test_chip = transformer.transform(test_chip, channel_order)
            self.dtype = test_chip.dtype

            self._set_crs_transformer()

        super().__init__(channel_order, num_channels, raster_transformers)
Ejemplo n.º 25
0
    def _filter_window_by_aoi(self, window: Box, aoi_polygons: list,
                              null_class_id: int) -> None:
        window_geom = window.to_shapely()
        label_arr = self[window]

        # For each aoi_polygon, intersect with window, and
        # put in window frame of reference.
        window_aois = []
        for aoi in aoi_polygons:
            window_aoi = aoi.intersection(window_geom)
            if not window_aoi.is_empty:

                def transform_shape(x, y, z=None):
                    return (x - window.xmin, y - window.ymin)

                window_aoi = transform(transform_shape, window_aoi)
                window_aois.append(window_aoi)

        # If window does't overlap with any AOI, then it won't be in
        # new_labels.
        if window_aois:
            # If window intersects with AOI, set pixels outside the
            # AOI polygon to 0 so they are ignored during eval.
            mask = rasterize([(p, 0) for p in window_aois],
                             out_shape=label_arr.shape[-2:],
                             fill=1,
                             dtype=np.uint8)
            mask = mask.astype(np.bool)
            self.mask_fill(window, mask, null_class_id)
        else:
            del self[window]
Ejemplo n.º 26
0
 def init_windows(self) -> None:
     """Pre-compute windows."""
     windows = self.scene.raster_source.get_extent().get_windows(
         chip_sz=self.size, stride=self.stride, padding=self.padding)
     if len(self.scene.aoi_polygons) > 0:
         windows = Box.filter_by_aoi(windows, self.scene.aoi_polygons)
     self.windows = windows
 def test_subscripting(self):
     box = Box(1, 2, 3, 4)
     self.assertEqual(box[0], 1)
     self.assertEqual(box[1], 2)
     self.assertEqual(box[2], 3)
     self.assertEqual(box[3], 4)
     self.assertRaises(IndexError, lambda: box[4])
    def test_constructor_save(self):
        # Read it, write it using label_store, read it again, and compare.
        extent = Box.make_square(0, 0, 10)

        msg = rv.LabelStoreConfig.builder(rv.CHIP_CLASSIFICATION_GEOJSON) \
                .with_uri(self.uri) \
                .build().to_proto()
        config = rv.LabelStoreConfig.builder(rv.CHIP_CLASSIFICATION_GEOJSON) \
                   .from_proto(msg).build()
        label_store = config.create_store(self.task_config, extent,
                                          self.crs_transformer,
                                          self.temp_dir.name)

        labels1 = label_store.get_labels()
        new_uri = os.path.join(self.temp_dir.name, 'test_save_reload.json')
        msg = rv.LabelStoreConfig.builder(rv.CHIP_CLASSIFICATION_GEOJSON) \
                .with_uri(new_uri) \
                .build().to_proto()
        config = rv.LabelStoreConfig.builder(rv.CHIP_CLASSIFICATION_GEOJSON) \
                   .from_proto(msg).build()
        label_store = config.create_store(self.task_config, extent,
                                          self.crs_transformer,
                                          self.temp_dir.name)
        label_store.save(labels1)
        labels2 = label_store.get_labels()

        self.assertDictEqual(labels1.cell_to_class_id,
                             labels2.cell_to_class_id)
    def test_normalized_to_local(self):
        norm_npboxes = np.array([[0., 0., 0.2, 0.02], [0.2, 0.02, 0.4, 0.04]])
        window = Box(0, 0, 10, 100)
        local_npboxes = ObjectDetectionLabels.normalized_to_local(
            norm_npboxes, window)

        expected_local_npboxes = np.array([[0., 0., 2., 2.], [2., 2., 4., 4.]])
        np.testing.assert_array_equal(local_npboxes, expected_local_npboxes)
    def test_global_to_local(self):
        global_npboxes = np.array([[10., 10., 12., 12.], [12., 12., 14., 14.]])
        window = Box.make_square(10, 10, 10)
        local_npboxes = ObjectDetectionLabels.global_to_local(
            global_npboxes, window)

        expected_local_npboxes = np.array([[0., 0., 2., 2.], [2., 2., 4., 4.]])
        np.testing.assert_array_equal(local_npboxes, expected_local_npboxes)