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 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 nodata_transform(min_val, in_path, out_path):
    """Convert values less than min_val to 0/NODATA.

    This script was developed to deal with imagery over Belize City which contains values
    that appear to be NODATA values on the periphery of the image, but are actually very
    small values < 7. This script converts those small values to zeros which Raster
    Vision knows to ignore when making predictions.
    """
    min_val = float(min_val)
    chip_size = 1000
    with rasterio.open(in_path, 'r') as in_data:
        with rasterio.open(out_path, 'w', **in_data.profile) as out_data:
            extent = Box(0, 0, in_data.height, in_data.width)
            windows = extent.get_windows(chip_size, chip_size)
            for w in windows:
                # Avoid going off edge of array.
                if w.ymax > in_data.height:
                    w.ymax = in_data.height
                if w.xmax > in_data.width:
                    w.xmax = in_data.width

                print('.', end='', flush=True)
                w = w.rasterio_format()
                im = in_data.read(window=w)

                nodata_mask = np.all(im < min_val, axis=0)

                for b in range(im.shape[0]):
                    band = im[b, :, :]
                    band[nodata_mask] = 0
                    out_data.write_band(b + 1, band, window=w)
Beispiel #4
0
    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)

        gt_rs = RasterizedSource(GeoJSONVectorSource(gt_uri, crs_transformer),
                                 RasterizedSourceConfig.RasterizerOptions(2),
                                 extent, crs_transformer)
        gt_ls = SemanticSegmentationLabelSource(source=gt_rs)

        pred_rs = RasterizedSource(
            GeoJSONVectorSource(pred_uri, crs_transformer),
            RasterizedSourceConfig.RasterizerOptions(2), extent,
            crs_transformer)
        pred_ls = SemanticSegmentationLabelSource(source=pred_rs)
        pred_ls.vector_output = [{
            'uri': pred_uri,
            'denoise': 0,
            'mode': 'polygons',
            'class_id': class_id
        }]

        if use_aoi:
            aoi_uri = data_file_path('{}-aoi.geojson'.format(class_id))
            aoi_geojson = json.loads(file_to_str(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)
Beispiel #5
0
    def set_return_vals(self, raster=None):
        self.mock.get_extent.return_value = Box.make_square(0, 0, 2)
        self.mock.get_dtype.return_value = np.uint8
        self.mock.get_crs_transformer.return_value = IdentityCRSTransformer()
        self.mock._get_chip.return_value = np.random.rand(1, 2, 2, 3)

        if raster is not None:
            self.mock.get_extent.return_value = Box(0, 0, raster.shape[0],
                                                    raster.shape[1])
            self.mock.get_dtype.return_value = raster.dtype

            def get_chip(window):
                return raster[window.ymin:window.ymax,
                              window.xmin:window.xmax, :]

            self.mock._get_chip.side_effect = get_chip
Beispiel #6
0
 def setUp(self):
     self.crs_transformer = IdentityCRSTransformer()
     self.extent = Box.make_square(0, 0, 10)
     self.tmp_dir = RVConfig.get_tmp_dir()
     self.class_id = 2
     self.background_class_id = 3
     self.line_buffer = 1
     self.uri = os.path.join(self.tmp_dir.name, 'temp.json')
Beispiel #7
0
 def setUp(self):
     self.crs_transformer = IdentityCRSTransformer()
     self.extent = Box.make_square(0, 0, 10)
     self.tmp_dir_obj = rv_config.get_tmp_dir()
     self.tmp_dir = self.tmp_dir_obj.name
     self.class_id = 0
     self.background_class_id = 1
     self.line_buffer = 1
     self.class_config = ClassConfig(names=['a'])
     self.uri = join(self.tmp_dir, 'tmp.json')
 def test_enough_target_pixels_true(self):
     data = np.zeros((10, 10, 1), dtype=np.uint8)
     data[4:, 4:, :] = 1
     null_class_id = 2
     raster_source = MockRasterSource([0], 1)
     raster_source.set_raster(data)
     label_source = SemanticSegmentationLabelSource(raster_source,
                                                    null_class_id)
     with label_source.activate():
         extent = Box(0, 0, 10, 10)
         self.assertTrue(label_source.enough_target_pixels(extent, 30, [1]))
Beispiel #9
0
    def test_get_chip_no_polygons(self):
        geojson = {'type': 'FeatureCollection', 'features': []}

        source = self.build_source(geojson)
        with source.activate():
            # Get chip that partially overlaps extent. Expect that chip has zeros
            # outside of extent, and background_class_id otherwise.
            self.assertEqual(source.get_extent(), self.extent)
            chip = source.get_chip(Box.make_square(5, 5, 10))
            self.assertEqual(chip.shape, (10, 10, 1))

            expected_chip = np.full((10, 10, 1), self.background_class_id)
            np.testing.assert_array_equal(chip, expected_chip)
 def get_train_windows(self, scene):
     result = []
     extent = scene.raster_source.get_extent()
     chip_size = self.config.chip_size
     stride = chip_size
     windows = extent.get_windows(chip_size, stride)
     if scene.aoi_polygons:
         windows = Box.filter_by_aoi(windows, scene.aoi_polygons)
     for window in windows:
         chip = scene.raster_source.get_chip(window)
         if np.sum(chip.ravel()) > 0:
             result.append(window)
     return result
 def test_get_labels(self):
     data = np.zeros((10, 10, 1), dtype=np.uint8)
     data[7:, 7:, 0] = 1
     null_class_id = 2
     raster_source = MockRasterSource([0], 1)
     raster_source.set_raster(data)
     label_source = SemanticSegmentationLabelSource(raster_source,
                                                    null_class_id)
     with label_source.activate():
         window = Box.make_square(7, 7, 3)
         labels = label_source.get_labels(window=window)
         label_arr = labels.get_label_arr(window)
         expected_label_arr = np.ones((3, 3))
         np.testing.assert_array_equal(label_arr, expected_label_arr)
Beispiel #12
0
def geoms_to_raster(str_tree, rasterizer_options, window, extent):
    background_class_id = rasterizer_options.background_class_id
    all_touched = rasterizer_options.all_touched

    log.debug('Cropping shapes to window...')
    # Crop shapes against window, remove empty shapes, and put in window frame of
    # reference.
    window_geom = window.to_shapely()
    shapes = str_tree.query(window_geom)
    shapes = [(s, s.class_id) for s in shapes]
    shapes = [(s.intersection(window_geom), c) for s, c in shapes]
    shapes = [(s, c) for s, c in shapes if not s.is_empty]

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

    shapes = [(shapely.ops.transform(to_window_frame, s), c)
              for s, c in shapes]
    log.debug('# of shapes in window: {}'.format(len(shapes)))

    out_shape = (window.get_height(), window.get_width())

    # rasterize needs to be passed >= 1 shapes.
    if shapes:
        log.debug('rasterio.rasterize()...')
        raster = rasterize(
            shapes,
            out_shape=out_shape,
            fill=background_class_id,
            dtype=np.uint8,
            all_touched=all_touched)
    else:
        raster = np.full(out_shape, background_class_id, dtype=np.uint8)

    # Ensure that parts of window outside of extent have zero values which are counted as
    # the don't-care class for segmentation.
    valid_window = window_geom.intersection(extent.to_shapely())
    if valid_window.is_empty:
        raster[:, :] = 0
    else:
        vw = shapely.ops.transform(to_window_frame, valid_window)
        vw = Box.from_shapely(vw).to_int()
        new_raster = np.zeros(out_shape)
        new_raster[vw.ymin:vw.ymax, vw.xmin:vw.xmax] = \
            raster[vw.ymin:vw.ymax, vw.xmin:vw.xmax]
        raster = new_raster

    return raster
 def test_get_labels_rgb(self):
     data = np.zeros((10, 10, 3), dtype=np.uint8)
     data[7:, 7:, :] = [1, 1, 1]
     null_class_id = 2
     raster_source = MockRasterSource([0, 1, 2], 3)
     raster_source.set_raster(data)
     rgb_class_config = ClassConfig(names=['a'], colors=['#010101'])
     rgb_class_config.ensure_null_class()
     label_source = SemanticSegmentationLabelSource(
         raster_source, null_class_id, rgb_class_config=rgb_class_config)
     with label_source.activate():
         window = Box.make_square(7, 7, 3)
         labels = label_source.get_labels(window=window)
         label_arr = labels.get_label_arr(window)
         expected_label_arr = np.zeros((3, 3))
         np.testing.assert_array_equal(label_arr, expected_label_arr)
Beispiel #14
0
    def process(self, training_data, tmp_dir):
        augmented = TrainingData()
        nodata_aug_prob = self.aug_prob

        for chip, window, labels in training_data:
            # If negative chip, with some probability, add a random black square
            # to chip.
            if len(labels) == 0 and random.uniform(0, 1) < nodata_aug_prob:
                size = round(random.uniform(0, 1) * chip.shape[0])
                square = Box(0, 0, chip.shape[0],
                             chip.shape[1]).make_random_square(size)
                chip = np.copy(chip)
                chip[square.ymin:square.ymax, square.xmin:square.xmax, :] = 0

            augmented.append(chip, window, labels)

        return augmented
    def test_command_run_with_mocks(self):
        task_config = rv.TaskConfig.builder(mk.MOCK_TASK).build()
        backend_config = rv.BackendConfig.builder(mk.MOCK_BACKEND).build()
        backend = backend_config.create_backend(task_config)
        backend_config.mock.create_backend.return_value = backend
        task = task_config.create_task(backend)
        task_config.mock.create_task.return_value = task
        scene = mk.create_mock_scene()

        task.mock.get_predict_windows.return_value = [Box(0, 0, 1, 1)]

        cmd = rv.CommandConfig.builder(rv.PREDICT) \
                              .with_task(task_config) \
                              .with_backend(backend_config) \
                              .with_scenes([scene]) \
                              .with_root_uri('.') \
                              .build() \
                              .create_command()
        cmd.run()

        self.assertTrue(backend.mock.predict.called)
    def setUp(self):
        self.file_name = 'labels.json'
        self.tmp_dir = rv_config.get_tmp_dir()
        self.file_path = os.path.join(self.tmp_dir.name, self.file_name)

        self.crs_transformer = DoubleCRSTransformer()
        self.geojson = {
            'type':
            'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'geometry': {
                    'type':
                    'Polygon',
                    'coordinates': [[[0., 0.], [0., 1.], [1., 1.], [1., 0.],
                                     [0., 0.]]]
                },
                'properties': {
                    'class_id': 0,
                    'score': 0.9
                }
            }, {
                'type': 'Feature',
                'geometry': {
                    'type':
                    'Polygon',
                    'coordinates': [[[1., 1.], [1., 2.], [2., 2.], [2., 1.],
                                     [1., 1.]]]
                },
                'properties': {
                    'score': 0.9,
                    'class_id': 1
                }
            }]
        }

        self.extent = Box.make_square(0, 0, 10)
        self.class_config = ClassConfig(names=['car', 'house'])
        json_to_file(self.geojson, self.file_path)
    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 make_labels(self, class_ids):
        """Make 2x2 grid label store.

        Args:
            class_ids: 2x2 array of class_ids to use
        """
        cell_size = 200
        y_cells = 2
        x_cells = 2
        labels = ChipClassificationLabels()

        for yind in range(y_cells):
            for xind in range(x_cells):
                ymin = yind * cell_size
                xmin = xind * cell_size
                ymax = ymin + cell_size
                xmax = xmin + cell_size
                window = Box(ymin, xmin, ymax, xmax)
                class_id = class_ids[yind][xind]
                new_labels = ChipClassificationLabels()
                new_labels.set_cell(window, class_id)
                labels.extend(new_labels)

        return labels
Beispiel #19
0
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)
Beispiel #20
0
    def test_mocks(self):
        """Test to ensure all mocks are working as expected."""
        task_config = rv.TaskConfig.builder(mk.MOCK_TASK) \
                                   .build()

        backend_config = rv.BackendConfig.builder(mk.MOCK_BACKEND) \
                                         .build()

        raster_transformer_config = rv.RasterTransformerConfig.builder(
            mk.MOCK_TRANSFORMER).build()

        raster_source_config = rv.RasterSourceConfig.builder(mk.MOCK_SOURCE) \
                                                    .with_transformer(
                                                        raster_transformer_config) \
                                                    .build()

        label_source_config = rv.LabelSourceConfig.builder(mk.MOCK_SOURCE) \
                                                    .build()

        label_store_config = rv.LabelStoreConfig.builder(mk.MOCK_STORE) \
                                                    .build()

        scene_config = rv.SceneConfig.builder() \
                                     .with_id('test') \
                                     .with_raster_source(raster_source_config) \
                                     .with_label_source(label_source_config) \
                                     .with_label_store(label_store_config) \
                                     .build()

        augmentor_config = rv.AugmentorConfig.builder(mk.MOCK_AUGMENTOR) \
                                             .build()

        dataset = rv.DatasetConfig.builder() \
                                  .with_train_scene(scene_config) \
                                  .with_validation_scene(scene_config) \
                                  .with_augmentor(augmentor_config)  \
                                  .build()

        analyzer_config = rv.AnalyzerConfig.builder(mk.MOCK_ANALYZER).build()
        evaluator_config = rv.EvaluatorConfig.builder(
            mk.MOCK_EVALUATOR).build()

        # Create entities from configuration

        backend = backend_config.create_backend(task_config)
        task = task_config.create_task(backend)
        scene = scene_config.create_scene(task_config, '.')
        _ = augmentor_config.create_augmentor()  # noqa
        _ = analyzer_config.create_analyzer()  # noqa
        _ = evaluator_config.create_evaluator()  # noqa

        # Assert some things

        task_config.mock.create_task.assert_called_once_with(backend)
        self.assertEqual(task.get_predict_windows(Box(0, 0, 1, 1)), [])

        _ = scene.raster_source.get_chip(Box(0, 0, 1, 1))  # noqa
        self.assertTrue(
            scene.raster_source.raster_transformers[0].mock.transform.called)

        # Create and run experiment

        with tempfile.TemporaryDirectory() as tmp_dir:
            e = rv.ExperimentConfig.builder() \
                                   .with_task(task_config) \
                                   .with_backend(backend_config) \
                                   .with_dataset(dataset) \
                                   .with_analyzer(analyzer_config) \
                                   .with_evaluator(evaluator_config) \
                                   .with_root_uri(tmp_dir) \
                                   .with_id('test') \
                                   .build()

            rv.ExperimentRunner.get_runner(rv.LOCAL).run(e, splits=7)
 def get_extent(self):
     Box.make_square(0, 0, 2)
def save_image_crop(image_uri,
                    crop_uri,
                    label_uri=None,
                    size=600,
                    min_features=10):
    """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
        crop_uri: URI of cropped image to save
        label_uri: optional URI of GeoJSON file
        size: height and width of crop

    Raises:
        ValueError if cannot find a crop satisfying min_features constraint.
    """
    if not file_exists(crop_uri):
        print('Saving test crop to {}...'.format(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 is not None:
                crs_transformer = RasterioCRSTransformer.from_dataset(
                    im_dataset)
                vs = GeoJSONVectorSource(label_uri, crs_transformer)
                geojson = vs.get_geojson()
                geoms = []
                for f in geojson['features']:
                    g = shape(f['geometry'])
                    geoms.append(g)
                tree = STRtree(geoms)

            for w in windows:
                use_window = True
                if label_uri is not None:
                    w_polys = tree.query(w.to_shapely())
                    use_window = len(w_polys) >= min_features

                if use_window:
                    w = w.rasterio_format()
                    im = im_dataset.read(window=w)

                    if np.mean(np.sum(im, axis=2).ravel() == 0) < 0.9:
                        with tempfile.TemporaryDirectory() as tmp_dir:
                            crop_path = get_local_path(crop_uri, tmp_dir)
                            make_dir(crop_path, use_dirname=True)

                            meta = im_dataset.meta
                            meta['width'], meta['height'] = size, size
                            meta['transform'] = rasterio.windows.transform(
                                w, im_dataset.transform)

                            with rasterio.open(crop_path, 'w', **meta) as dst:
                                dst.colorinterp = im_dataset.colorinterp
                                dst.write(im)

                            upload_or_copy(crop_path, crop_uri)
                        break

            if not use_window:
                raise ValueError('Could not find a good crop.')
        finally:
            os.environ.clear()
            os.environ.update(old_environ)
Beispiel #23
0
 def filter_windows(windows):
     if scene.aoi_polygons:
         windows = Box.filter_by_aoi(windows, scene.aoi_polygons)
     return windows