Tiling imagery and labels using the solaris Python API

This tutorial will walk you through an example case of using the solaris Python API to tile one of the SpaceNet cities - in this case, Rio de Janeiro. We’ll assume that you have already installed solaris.

First, downloaded and extracted two files from the spacenet-dataset AWS S3 bucket:

  1. Imagery: https://s3.amazonaws.com/spacenet-dataset/AOIs/AOI_1_Rio/PS-RGB/PS-RGB_mosaic_013022223133.tif

  2. Vector labels: https://spacenet-dataset.s3.amazonaws.com/AOIs/AOI_1_Rio/srcData/buildingLabels/Rio_Buildings_Public_AOI_v2.geojson

Move both of these files to your working directory or alter the paths below to point to the files at the downloaded location.

As you’re getting started, your directory should have the following in it:

  • A directory named 3band which contains the imagery files

  • A directory named geojson which contains two files: Rio_Buildings_Public_AOI_v2.geojson and Rio_OUTLINE_Public_AOI.geojson (we only need the first of those two).

Feel free to open up the imagery/vector labels in QGIS or another browser and explore to see what you’re looking at.

Tiling the imagery

For this working example we’ll tile into 500-by-500-pixel chips beginning at the top left corner. Note that you can also tile based on the metric units covered by an image - for example, we could specify 250 meter-by-250 meter chips (which is the same size in this case). See the documentation for sol.tile.raster_tile.RasterTiler() for more details.

Initialize the RasterTiler object:

[1]:
import solaris as sol
import os

raster_tiler = sol.tile.raster_tile.RasterTiler(dest_dir='rio_chips',  # the directory to save images to
                                                src_tile_size=(500, 500),  # the size of the output chips
                                                verbose=True)
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:526: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint8 = np.dtype([("qint8", np.int8, 1)])
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:527: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_quint8 = np.dtype([("quint8", np.uint8, 1)])
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:528: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint16 = np.dtype([("qint16", np.int16, 1)])
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:529: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_quint16 = np.dtype([("quint16", np.uint16, 1)])
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:530: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  _np_qint32 = np.dtype([("qint32", np.int32, 1)])
/opt/miniconda3/envs/solaris/lib/python3.6/site-packages/tensorflow/python/framework/dtypes.py:535: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
  np_resource = np.dtype([("resource", np.ubyte, 1)])
Initializing Tiler...
Tiler initialized.
dest_dir: rio_chips
dest_crs will be inferred from source data.
src_tile_size: (500, 500)
tile size units metric: False

This object can be re-used with the same parameters for multiple images if desired. This way, you can tile multiple images collected over the same geography with the same settings. There are additional arguments that you can provide (for example, the destination coordinate reference system).

To tile the imagery, pass the image file to the tiler’s tile() method, which returns the CRS of the source raster for vector tiling:

[2]:
raster_bounds_crs = raster_tiler.tile('/Users/nweir/code/cosmiq_repos/solaris/PS-RGB_mosaic_013022223133.tif')
0it [00:00, ?it/s]The following warnings were found:
- The file is greater than 512xH or 512xW, it is recommended to include internal overviews

The following errors were found:
- The offset of the main IFD should be 8 for ClassicTIFF or 16 for BigTIFF. It is 93844024 instead
- The offset of the first block of the image should be after its IFD
3it [00:00, 23.16it/s]
Beginning tiling...
Checking input data...
COG: False
[1, 2, 3]
Source CRS: EPSG:4326
Destination CRS: EPSG:4326
Inputs OK.
1600it [01:04, 24.86it/s]
Tiling complete. Cleaning up...
Done.

This should throw a few warnings/errors about the input file, which you can ignore. You’ll create 1600 files in your “rio_chips” subdirectory, one for each 500x500 tile. The filenames are in the format [src-filename]\_[longitude]\_[latitude].tif. Reprojection takes a while, so be patient.

Once that process finishes, we’ll use these auto-generated tile boundaries, which are stored in raster_tiler, to create vector tiles.

These bounds are in the format [left, bottom, right, top] in the input file CRS. The following line prints the first set of bounds (there are 1600 in the list):

[3]:
print(raster_tiler.tile_bounds[0])
(-43.681640625, -22.939453125, -43.67939668543198, -22.937209185431986)

raster_tiler.tile_bounds is passed as an argument into the VectorTiler instance.

[4]:
vector_tiler = sol.tile.vector_tile.VectorTiler(dest_dir='rio_labels',
                                                verbose=True)
vector_tiler.tile('/Users/nweir/code/cosmiq_repos/solaris/Rio_Buildings_Public_AOI_v2.geojson',
                  tile_bounds=raster_tiler.tile_bounds,
                  tile_bounds_crs=raster_bounds_crs)
0it [00:00, ?it/s]
Preparing the tiler...
Initialization done.
Num tiles: 1600
1600it [02:16, 11.74it/s]

…And you’re done! Simple as that. For more details, check out the tiling API docs.