def create_footprints(csv_row): """Extract footprint from a Landsat 8 csv row Args: csv_row (dict): dictionary representation of a row in scene list csv Returns: Footprint """ src_proj = Proj(init='epsg:4326') ll = (csv_row['lowerLeftCornerLongitude'], csv_row['lowerLeftCornerLatitude']) lr = (csv_row['lowerRightCornerLongitude'], csv_row['lowerRightCornerLatitude']) ul = (csv_row['upperLeftCornerLongitude'], csv_row['upperLeftCornerLatitude']) ur = (csv_row['upperRightCornerLongitude'], csv_row['upperRightCornerLatitude']) src_coords = [ll, lr, ur, ul] min_x = min([coord[0] for coord in src_coords]) min_y = min([coord[1] for coord in src_coords]) max_x = max([coord[0] for coord in src_coords]) max_y = max([coord[1] for coord in src_coords]) transformed_coords = [[[ transform(src_proj, target_proj, coord[0], coord[1]) for coord in src_coords ]]] data_geojson = {'type': 'MultiPolygon', 'coordinates': transformed_coords} data_footprint = Footprint(organization, data_geojson) transformed_tile_coords = [[[ transform(src_proj, target_proj, coord[0], coord[1]) for coord in [(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_x, max_y)] ]]] tile_geojson = { 'type': 'MultiPolygon', 'coordinates': transformed_tile_coords } tile_footprint = Footprint(organization, tile_geojson) return tile_footprint, data_footprint
def footprint_from_key(tileinfo, key): geom = tileinfo[key] coords = geom['coordinates'][0] src_proj = get_src_proj(geom['crs']['properties']['name']) transformed_coords = [[[ transform(src_proj, target_proj, coord[0], coord[1]) for coord in coords ]]] return Footprint(organization, transformed_coords)
def extract_footprints(organization_id, tif_path): """Performs all actions to extract polygon from a kayak scene Args: organization_id (str): organization footprints belong to tif_path (str): path to tif to extract polygons from Returns: tuple """ logger.info('Beginning process to extract footprint for image:%s', tif_path) with get_tempdir() as temp_dir: _, resampled_tif_path = tempfile.mkstemp(suffix='.TIF', dir=temp_dir) with rasterio.open(tif_path) as src: y, x = src.shape aspect = y / float(x) x_size = 512 y_size = int(512 * aspect) # Resample to a max width of 512 cmd = [ 'gdal_translate', tif_path, resampled_tif_path, '-outsize', str(x_size), str(y_size), ] logger.info('Running GDAL command: %s', ' '.join(cmd)) subprocess.check_call(cmd) tile_mask_tif_path, data_mask_tif_path = create_tif_mask( temp_dir, resampled_tif_path) data_footprint = extract_polygon(data_mask_tif_path) tile_footprint = extract_polygon(tile_mask_tif_path) return (Footprint(organization_id, tile_footprint), Footprint(organization_id, data_footprint))
def footprint_from_key(tileinfo, key): geom = tileinfo[key] coords = geom['coordinates'][0] src_proj = get_src_proj(geom['crs']['properties']['name']) transformed_coords = [[[ transform(src_proj, target_proj, coord[0], coord[1]) for coord in coords ]]] geojson = {"type": "MultiPolygon", "coordinates": transformed_coords} return Footprint(organization, geojson)
def extract_footprints(organization_id, tif_path): """Performs all actions to extract polygon from a kayak scene Args: organization_id (str): organization footprints belong to tif_path (str): path to tif to extract polygons from Returns: tuple """ logger.info('Beginning process to extract footprint for image:%s', tif_path) with get_tempdir() as temp_dir: tile_mask_tif_path, data_mask_tif_path = create_tif_mask( temp_dir, tif_path) data_footprint = extract_polygon(data_mask_tif_path) tile_footprint = extract_polygon(tile_mask_tif_path) return (Footprint(organization_id, tile_footprint), Footprint(organization_id, data_footprint))
def extract_footprints(tif_path): """Performs all actions to extract polygon from a kayak scene Args: tif_path (str): path to tif to extract polygons from Returns: tuple """ logger.info('Beginning process to extract footprint for image:%s', tif_path) with get_tempdir() as temp_dir: _, resampled_tif_path = tempfile.mkstemp(suffix='.TIF', dir=temp_dir) _, warped_path = tempfile.mkstemp(suffix='.TIF', dir=temp_dir) _, geojson_path = tempfile.mkstemp(suffix='.GEOJSON', dir=temp_dir) with rasterio.open(tif_path) as src: y, x = src.shape aspect = y / float(x) x_size = 512 y_size = int(512 * aspect) resample_cmd = [ 'gdal_translate', tif_path, resampled_tif_path, '-outsize', str(x_size), str(y_size) ] warp_cmd = [ 'gdalwarp', '-co', 'compress=LZW', '-dstnodata', '0', '-dstalpha', '-t_srs', 'epsg:4326', resampled_tif_path, warped_path ] polygonize_cmd = [ 'gdal_polygonize.py', '-b', 'mask', warped_path, '-f', 'GEOJSON', geojson_path ] subprocess.check_call(resample_cmd) subprocess.check_call(warp_cmd) subprocess.check_call(polygonize_cmd) with open(geojson_path, 'r+') as fh: geojson = json.load(fh) data_footprint = [ feature['geometry']['coordinates'] for feature in geojson['features'] if feature['properties']['DN'] == 255 ] xs = [] ys = [] for area in data_footprint: xst, yst = zip(*area[0]) xs += xst ys += yst xmin = min(xs) xmax = max(xs) ymin = min(ys) ymax = max(ys) tile_footprint = [[[[xmin, ymin], [xmax, ymin], [xmax, ymax], [xmin, ymax], [xmin, ymin]]]] return (Footprint(tile_footprint), Footprint(data_footprint))
def create_planet_scene(planet_feature, datasource, organization_id, planet_key, ingest_status=IngestStatus.TOBEINGESTED, visibility=Visibility.PRIVATE, tags=[], owner=None, sceneType="AVRO"): """Create a Raster Foundry scene from Planet scenes Args: planet_key (str): API auth key for planet API planet_feature (dict): json response from planet API client datasource (str): UUID of the datasource this scene belongs to organization_id (str): UUID of the organization that owns the scene visibility (Visibility): visibility for created scene tags (str[]): list of tags to attach to the created scene owner (str): user ID of the user who owns the scene Returns: Scene """ props = planet_feature['properties'] datasource = datasource name = planet_feature['id'] acquisitionDate = props['acquired'] cloudCover = props['cloud_cover'] ingestSizeBytes = 0 # TODO visibility = visibility tags = tags dataFootprint = planet_feature['geometry']['coordinates'] scene_kwargs = { 'sunAzimuth': props['sun_azimuth'], 'sunElevation': props['sun_elevation'], 'cloudCover': cloudCover, 'acquisitionDate': acquisitionDate, 'id': str(uuid.uuid4()), 'thumbnails': None, 'tileFootprint': Footprint(organization_id, bbox_from_planet_feature(planet_feature)), 'dataFootprint': Footprint(organization_id, [planet_feature['geometry']['coordinates']]) } images = [ create_geotiff_image(organization_id, planet_feature['added_props']['localPath'], planet_feature['added_props']['s3Location'], scene=scene_kwargs['id'], visibility=visibility, owner=owner) ] scene = Scene(organization_id, ingestSizeBytes, visibility, tags, datasource, props, name, JobStatus.QUEUED, JobStatus.QUEUED, ingest_status, [], owner=owner, images=images, sceneType=sceneType, **scene_kwargs) thumbnail_url = planet_feature['_links']['thumbnail'] scene.thumbnails = [ get_planet_thumbnail(organization_id, thumbnail_url, planet_key, scene.id) ] return scene
def create_geotiff_scene(tif_path, datasource, acquisitionDate=None, cloudCover=0, visibility=Visibility.PRIVATE, tags=[], sceneMetadata=None, name=None, thumbnailStatus=JobStatus.QUEUED, boundaryStatus=JobStatus.QUEUED, ingestStatus=IngestStatus.TOBEINGESTED, metadataFiles=[], owner=None, sceneType="COG", **kwargs): """Returns scenes that can be created via API given a local path to a geotiff. Does not create Images because those require a Source URI, which this doesn't know about. Use create_geotiff_scene from a higher level of code that knows about where things are located remotely and then add those Images to the Scene that this function returns. Tries to extract metadata from the GeoTIFF where possible, but can also accept parameter overrides. Order of preference is as follows: 1) Kwargs 2) GeoTiff Value / Dynamic value (e.g. azimuth calculated from capture location / time) 3) Default values Args: tif_path (str): Local path to GeoTIFF file to use. datasource (str): Name describing the source of the data **kwargs: Any remaining keyword arguments will override the values being passed to the Scene constructor. If Returns: List[Scene] """ logger.info("Generating Scene from %s", tif_path) # Start with default values sceneMetadata = sceneMetadata if sceneMetadata else get_geotiff_metadata( tif_path) name = name if name else get_geotiff_name(tif_path) sceneKwargs = { "sunAzimuth": None, # TODO: Calculate from acquisitionDate and tif center. "sunElevation": None, # TODO: Same "cloudCover": cloudCover, "acquisitionDate": acquisitionDate, "id": str(uuid.uuid4()), "thumbnails": None, } # Override defaults with kwargs sceneKwargs.update(kwargs) data_footprint = complex_footprint(tif_path) tile_footprint = MultiPolygon( [Polygon.from_bounds(*data_footprint.bounds)]) # Construct Scene scene = Scene( visibility, tags, datasource, sceneMetadata, name, thumbnailStatus, boundaryStatus, ingestStatus, metadataFiles, owner=owner, sceneType=sceneType, dataFootprint=Footprint(mapping(data_footprint)["coordinates"]), tileFootprint=Footprint(mapping(tile_footprint)["coordinates"]), **sceneKwargs) return scene