def _test_class_inf(self, props, exp_class_ids, default_class_id=None): geojson = { 'type': 'FeatureCollection', 'features': [{ 'properties': props, 'geometry': { 'type': 'Point', 'coordinates': [1, 1] } }] } json_to_file(geojson, self.uri) class_config = ClassConfig(names=['building', 'car', 'tree']) class_id_to_filter = { 0: ['==', 'type', 'building'], 1: ['any', ['==', 'type', 'car'], ['==', 'type', 'auto']] } vs_cfg = GeoJSONVectorSourceConfig( uri=self.uri, class_id_to_filter=class_id_to_filter, default_class_id=default_class_id) vs = vs_cfg.build(class_config, IdentityCRSTransformer()) trans_geojson = vs.get_geojson() class_ids = [ f['properties']['class_id'] for f in trans_geojson['features'] ] self.assertEqual(class_ids, exp_class_ids)
def test_read_with_extent(self): # Extent only includes the first box. extent = Box.make_square(0, 0, 3) config = ObjectDetectionLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig( uri=self.file_path, default_class_id=None)) source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_dir.name) labels = source.get_labels() npboxes = np.array([[0., 0., 2., 2.]]) class_ids = np.array([0]) 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) config = ObjectDetectionLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig( uri=self.file_path, default_class_id=None)) source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_dir.name) labels = source.get_labels() npboxes = np.array([[0., 0., 2., 2.], [2., 2., 3.9, 3.9]]) class_ids = np.array([0, 1]) scores = np.array([0.9, 0.9]) expected_labels = ObjectDetectionLabels( npboxes, class_ids, scores=scores) labels.assert_equal(expected_labels)
def test_accounts_for_aoi(self): class_config = ClassConfig(names=['car', 'building', 'background']) label_source_uri = data_file_path('evaluator/cc-label-filtered.json') label_source_cfg = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig( uri=label_source_uri, default_class_id=None)) label_store_uri = data_file_path('evaluator/cc-label-full.json') label_store_cfg = ChipClassificationGeoJSONStoreConfig( uri=label_store_uri) raster_source_uri = data_file_path('evaluator/cc-label-img-blank.tif') raster_source_cfg = RasterioSourceConfig(uris=[raster_source_uri]) aoi_uri = data_file_path('evaluator/cc-label-aoi.json') s = SceneConfig( id='test', raster_source=raster_source_cfg, label_source=label_source_cfg, label_store=label_store_cfg, aoi_uris=[aoi_uri]) with rv_config.get_tmp_dir() as tmp_dir: scene = s.build(class_config, tmp_dir) output_uri = os.path.join(tmp_dir, 'eval.json') evaluator = ChipClassificationEvaluatorConfig( output_uri=output_uri).build(class_config) evaluator.process([scene], tmp_dir) overall = file_to_json(output_uri)['overall'] for item in overall: self.assertEqual(item['f1'], 1.0)
def hrefs_to_sceneconfig( imagery: str, labels: Optional[str], name: str, class_id_filter_dict: Dict[int, str], extent_crop: Optional[CropOffsets] = None) -> SceneConfig: transformers = [CastTransformerConfig(to_dtype='float16')] image_source = RasterioSourceConfig( channel_order=list(range(224)), uris=[imagery], allow_streaming=True, transformers=transformers, extent_crop=extent_crop, ) label_vector_source = GeoJSONVectorSourceConfig( uri=labels, class_id_to_filter=class_id_filter_dict, default_class_id=0xff) label_raster_source = RasterizedSourceConfig( vector_source=label_vector_source, rasterizer_config=RasterizerConfig(background_class_id=0, all_touched=True)) label_source = SemanticSegmentationLabelSourceConfig( raster_source=label_raster_source) return SceneConfig(id=name, raster_source=image_source, label_source=label_source)
def transform_geojson(self, geojson, line_bufs=None, point_bufs=None, crs_transformer=None, to_map_coords=False): if crs_transformer is None: crs_transformer = IdentityCRSTransformer() class_config = ClassConfig(names=['building']) json_to_file(geojson, self.uri) cfg = GeoJSONVectorSourceConfig( uri=self.uri, line_bufs=line_bufs, point_bufs=point_bufs, default_class_id=0) source = cfg.build(class_config, crs_transformer) return source.get_geojson(to_map_coords=to_map_coords)
def make_scene(scene_id, img_path, label_path): raster_source = RasterioSourceConfig(channel_order=[0, 1, 2], uris=[img_path]) label_source = ObjectDetectionLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=label_path, default_class_id=None)) return SceneConfig(id=scene_id, raster_source=raster_source, label_source=label_source)
def test_using_null_class_bufs(self): vs = GeoJSONVectorSourceConfig(uri=self.uri, default_class_id=None, line_bufs={0: None}) with self.assertRaises(ConfigError): config = RasterizedSourceConfig( vector_source=vs, rasterizer_config=RasterizerConfig( background_class_id=self.background_class_id)) config.validate_config()
def build_source(self, geojson, all_touched=False): json_to_file(geojson, self.uri) config = RasterizedSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=self.uri, default_class_id=None), rasterizer_config=RasterizerConfig( background_class_id=self.background_class_id, all_touched=all_touched)) source = config.build(self.class_config, self.crs_transformer, self.extent) return source
def get_vector_scene(self, class_id, use_aoi=False): gt_uri = data_file_path('{}-gt-polygons.geojson'.format(class_id)) pred_uri = data_file_path('{}-pred-polygons.geojson'.format(class_id)) scene_id = str(class_id) rs = MockRasterSource(channel_order=[0, 1, 3], num_channels=3) rs.set_raster(np.zeros((10, 10, 3))) crs_transformer = IdentityCRSTransformer() extent = Box.make_square(0, 0, 360) config = RasterizedSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=gt_uri, default_class_id=0), rasterizer_config=RasterizerConfig(background_class_id=1)) gt_rs = config.build(self.class_config, crs_transformer, extent) gt_ls = SemanticSegmentationLabelSource(gt_rs, self.null_class_id) config = RasterizedSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=pred_uri, default_class_id=0), rasterizer_config=RasterizerConfig(background_class_id=1)) pred_rs = config.build(self.class_config, crs_transformer, extent) pred_ls = SemanticSegmentationLabelSource(pred_rs, self.null_class_id) pred_ls.vector_output = [ PolygonVectorOutputConfig(uri=pred_uri, denoise=0, class_id=class_id) ] if use_aoi: aoi_uri = data_file_path('{}-aoi.geojson'.format(class_id)) aoi_geojson = file_to_json(aoi_uri) aoi_polygons = [shape(aoi_geojson['features'][0]['geometry'])] return Scene(scene_id, rs, gt_ls, pred_ls, aoi_polygons) return Scene(scene_id, rs, gt_ls, pred_ls)
def test_read_without_extent(self): config = ObjectDetectionLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig( uri=self.file_path, default_class_id=None)) extent = None source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_dir.name) labels = source.get_labels() npboxes = np.array([[0., 0., 2., 2.], [2., 2., 4., 4.]]) class_ids = np.array([0, 1]) scores = np.array([0.9, 0.9]) expected_labels = ObjectDetectionLabels( npboxes, class_ids, scores=scores) labels.assert_equal(expected_labels)
def test_getitem(self): # Extent contains both boxes. extent = Box.make_square(0, 0, 8) config = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=self.uri, default_class_id=None)) source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_dir.name) labels = source.get_labels() cells = labels.get_cells() self.assertEqual(len(cells), 2) self.assertEqual(source[cells[0]], self.class_id1) self.assertEqual(source[cells[1]], self.class_id2)
def test_get_labels_small_extent(self): # Extent only has enough of first box in it. extent = Box.make_square(0, 0, 2) config = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=self.uri, default_class_id=None)) source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_dir.name) labels = source.get_labels() cells = labels.get_cells() self.assertEqual(len(cells), 1) class_id = labels.get_cell_class_id(self.box1) self.assertEqual(class_id, self.class_id1) class_id = labels.get_cell_class_id(self.box2) self.assertEqual(class_id, None)
def make_scene(img_path, label_path): id = basename(img_path) label_source = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=label_path, default_class_id=None, ignore_crs_field=True), ioa_thresh=0.5, use_intersection_over_cell=False, pick_min_class_id=True, background_class_id=2, infer_cells=True) raster_source = RasterioSourceConfig( channel_order=[0, 1, 2], uris=[img_path], transformers=[StatsTransformerConfig()]) return SceneConfig(id=id, raster_source=raster_source, label_source=label_source)
def test_get_labels_inferred(self): extent = Box.make_square(0, 0, 8) config = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=self.uri, default_class_id=None), ioa_thresh=0.5, use_intersection_over_cell=False, pick_min_class_id=False, background_class_id=self.background_class_id, infer_cells=True, cell_sz=4) source = config.build(self.class_config, self.crs_transformer, extent, self.tmp_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)
def save_image_crop(image_uri, image_crop_uri, label_uri=None, label_crop_uri=None, size=600, min_features=10, vector_labels=True, class_config=None): """Save a crop of an image to use for testing. If label_uri is set, the crop needs to cover >= min_features. Args: image_uri: URI of original image image_crop_uri: URI of cropped image to save label_uri: optional URI of label file label_crop_uri: optional URI of cropped labels to save size: height and width of crop Raises: ValueError if cannot find a crop satisfying min_features constraint. """ if not file_exists(image_crop_uri): print('Saving test crop to {}...'.format(image_crop_uri)) old_environ = os.environ.copy() try: request_payer = S3FileSystem.get_request_payer() if request_payer == 'requester': os.environ['AWS_REQUEST_PAYER'] = request_payer im_dataset = rasterio.open(image_uri) h, w = im_dataset.height, im_dataset.width extent = Box(0, 0, h, w) windows = extent.get_windows(size, size) if label_uri and vector_labels: crs_transformer = RasterioCRSTransformer.from_dataset( im_dataset) geojson_vs_config = GeoJSONVectorSourceConfig( uri=label_uri, default_class_id=0, ignore_crs_field=True) vs = geojson_vs_config.build(class_config, crs_transformer) geojson = vs.get_geojson() geoms = [] for f in geojson['features']: g = shape(f['geometry']) geoms.append(g) tree = STRtree(geoms) def p2m(x, y, z=None): return crs_transformer.pixel_to_map((x, y)) for w in windows: use_window = True if label_uri and vector_labels: w_polys = tree.query(w.to_shapely()) use_window = len(w_polys) >= min_features if use_window and label_crop_uri is not None: print('Saving test crop labels to {}...'.format( label_crop_uri)) label_crop_features = [ mapping(transform(p2m, wp)) for wp in w_polys ] label_crop_json = { 'type': 'FeatureCollection', 'features': [{ 'geometry': f } for f in label_crop_features] } json_to_file(label_crop_json, label_crop_uri) if use_window: crop_image(image_uri, w, image_crop_uri) if not vector_labels and label_uri and label_crop_uri: crop_image(label_uri, w, label_crop_uri) break if not use_window: raise ValueError('Could not find a good crop.') finally: os.environ.clear() os.environ.update(old_environ)