def test_get_windows(self): extent = Box(0, 0, 100, 100) windows = list(extent.get_windows(10, 10)) self.assertEqual(len(windows), 100) extent = Box(0, 0, 100, 100) windows = list(extent.get_windows(10, 5)) self.assertEqual(len(windows), 400) extent = Box(0, 0, 20, 20) windows = set( [window.tuple_format() for window in extent.get_windows(10, 10)]) expected_windows = [ Box.make_square(0, 0, 10), Box.make_square(10, 0, 10), Box.make_square(0, 10, 10), Box.make_square(10, 10, 10) ] expected_windows = set( [window.tuple_format() for window in expected_windows]) self.assertSetEqual(windows, expected_windows) extent = Box(10, 10, 20, 20) windows = set( [window.tuple_format() for window in extent.get_windows(6, 6)]) expected_windows = [ Box.make_square(10, 10, 6), Box.make_square(10, 16, 6), Box.make_square(16, 10, 6), Box.make_square(16, 16, 6) ] expected_windows = set( [window.tuple_format() for window in expected_windows]) self.assertSetEqual(windows, expected_windows)
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 read_labels(geojson, extent=None): """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
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 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_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 _get_shifted_window(self, window): do_shift = self.x_shift != 0.0 or self.y_shift != 0.0 if do_shift: ymin, xmin, ymax, xmax = window.tuple_format() width = window.get_width() height = window.get_height() # Transform image coordinates into world coordinates transform = self.image_dataset.transform xmin2, ymin2 = transform * (xmin, ymin) # Transform from world coordinates to WGS84 if self.crs != wgs84_proj4 and self.proj: lon, lat = pyproj.transform(self.proj, wgs84, xmin2, ymin2) else: lon, lat = xmin2, ymin2 # Shift. This is performed by computing the shifts in # meters to shifts in degrees. Those shifts are then # applied to the WGS84 coordinate. # # Courtesy of https://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters # noqa lat_radians = math.pi * lat / 180.0 dlon = Decimal(self.x_shift) / Decimal( meters_per_degree * math.cos(lat_radians)) dlat = Decimal(self.y_shift) / Decimal(meters_per_degree) lon = float(Decimal(lon) + dlon) lat = float(Decimal(lat) + dlat) # Transform from WGS84 to world coordinates if self.crs != wgs84_proj4 and self.proj: xmin3, ymin3 = pyproj.transform(wgs84, self.proj, lon, lat) xmin3 = int(round(xmin3)) ymin3 = int(round(ymin3)) else: xmin3, ymin3 = lon, lat # Trasnform from world coordinates back into image coordinates xmin4, ymin4 = ~transform * (xmin3, ymin3) window = Box(ymin4, xmin4, ymin4 + height, xmin4 + width) return window
def from_geojson(geojson, extent=None): """Convert GeoJSON to ObjectDetectionLabels object. If extent is provided, filter out the boxes that lie "more than a little bit" outside the extent. Args: geojson: (dict) normalized GeoJSON (see VectorSource) extent: (Box) in pixel coords Returns: ObjectDetectionLabels """ boxes = [] class_ids = [] scores = [] for f in geojson['features']: geom = shape(f['geometry']) (xmin, ymin, xmax, ymax) = geom.bounds boxes.append(Box(ymin, xmin, ymax, xmax)) props = f['properties'] class_ids.append(props['class_id']) scores.append(props.get('score', 1.0)) if len(boxes): boxes = np.array( [box.npbox_format() for box in boxes], dtype=float) class_ids = np.array(class_ids) scores = np.array(scores) labels = ObjectDetectionLabels(boxes, class_ids, scores=scores) else: labels = ObjectDetectionLabels.make_empty() if extent is not None: labels = ObjectDetectionLabels.get_overlapping( labels, extent, ioa_thresh=0.8, clip=True) return labels
def test_int(self): other = Box( float(self.ymin) + 0.01, float(self.xmin), float(self.ymax), float(self.xmax)) self.assertTrue(other.to_int() == self.box)
def test_neq(self): other = Box(self.ymin + 1, self.xmin, self.ymax, self.xmax) self.assertTrue(self.box != other)
def test_make_square(self): square = Box(0, 0, 10, 10) output_square = Box.make_square(0, 0, 10) self.assertEqual(output_square, square) self.assertEqual(output_square.get_width(), output_square.get_height())
def setUp(self): self.ymin = 0 self.xmin = 0 self.ymax = 2 self.xmax = 3 self.box = Box(self.ymin, self.xmin, self.ymax, self.xmax)
def get_extent(self): return Box(0, 0, self.height, self.width)