def get_image_bounds(image_file: str) -> str: """Loads the boundaries from an image file Arguments: image_file: path to the image to load the bounds from Return: Returns the GEOJSON of the bounds if they could be loaded and converted (if necessary). None is returned if the bounds are loaded or can't be converted """ # If the file has a geo shape we store it for clipping bounds = image_get_geobounds(image_file) epsg = get_epsg(image_file) if bounds[0] != np.nan: ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(bounds[2], bounds[1]) # Upper left ring.AddPoint(bounds[3], bounds[1]) # Upper right ring.AddPoint(bounds[3], bounds[0]) # lower right ring.AddPoint(bounds[2], bounds[0]) # lower left ring.AddPoint(bounds[2], bounds[1]) # Closing the polygon poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) ref_sys = osr.SpatialReference() if ref_sys.ImportFromEPSG(int(epsg)) == ogr.OGRERR_NONE: poly.AssignSpatialReference(ref_sys) return geometry_to_geojson(poly) logging.warning("Failed to import EPSG %s for image file %s", str(epsg), image_file) return None
def clip_raster_intersection(file_path: str, file_bounds: str, plot_bounds: str, out_file: str) -> Optional[int]: """Clips the raster to the intersection of the file bounds and plot bounds Arguments: file_path: the path to the source file file_bounds: the geometric boundary of the source file as JSON plot_bounds: the geometric boundary of the plot to clip to as JSON out_file: the path to store the clipped image Return: The number of pixels in the new image, or None if no pixels were saved Notes: Assumes the boundaries are in the same coordinate system Exceptions: Raises RuntimeError if the polygons are invalid """ logging.debug( "Clip to intersect of plot boundary: File: '%s' '%s' Plot: '%s'", file_path, str(file_bounds), str(plot_bounds)) try: file_poly = ogr.CreateGeometryFromJson(str(file_bounds)) plot_poly = ogr.CreateGeometryFromJson(str(plot_bounds)) if not file_poly or not plot_poly: logging.error( "Invalid polygon specified for clip_raster_intersection: File: '%s' plot: '%s'", str(file_bounds), str(plot_bounds)) raise RuntimeError( "One or more invalid polygons specified when clipping raster" ) intersection = file_poly.Intersection(plot_poly) if not intersection or not intersection.Area(): logging.info("File does not intersect plot boundary: %s", file_path) return None # Make sure we pass a multipolygon down to the tuple converter if intersection.GetGeometryName().startswith('MULTI'): multi_polygon = intersection else: multi_polygon = ogr.Geometry(ogr.wkbMultiPolygon) multi_polygon.AddGeometry(intersection) # Proceed to clip to the intersection tuples = __internal__.geojson_to_tuples( geometry_to_geojson(multi_polygon)) return clip_raster(file_path, tuples, out_path=out_file, compress=True) except Exception as ex: logging.exception( "Exception caught while clipping image to plot intersection") raise ex
def get_image_bounds_json(file_path: str, default_epsg: int = None) -> Optional[str]: """Loads the boundaries of the image file and returns the GeoJSON representing the bounds (including EPSG code) Arguments: file_path: path to the file from which to load the bounds default_epsg: the default EPSG to assume if a file has a boundary but not a coordinate system Return: Returns the JSON representing the image boundary, or None if the bounds could not be loaded Notes: If a file doesn't have a coordinate system and a default epsg is specified, the return JSON will use the default_epsg. If a file doesn't have a coordinate system and there isn't a default epsg specified, the boundary of the image is not returned (None) and a warning is logged. """ # Get the bounds (if they exist) bounds = image_get_geobounds(file_path) if bounds[0] == np.nan: return None epsg = get_epsg(file_path) if epsg is None: if default_epsg: epsg = default_epsg else: logging.warning( "Files does not have a coordinate system defined and no default was specified: '%s'", file_path) return None ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(bounds[2], bounds[1]) # Upper left ring.AddPoint(bounds[3], bounds[1]) # Upper right ring.AddPoint(bounds[3], bounds[0]) # lower right ring.AddPoint(bounds[2], bounds[0]) # lower left ring.AddPoint(bounds[2], bounds[1]) # Closing the polygon poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) ref_sys = osr.SpatialReference() if ref_sys.ImportFromEPSG(int(epsg)) == ogr.OGRERR_NONE: poly.AssignSpatialReference(ref_sys) return geometry_to_geojson(poly) logging.error("Failed to import EPSG %s for image file %s", str(epsg), file_path) return None
def get_las_extents(file_path: str, default_epsg: int = None) -> Optional[str]: """Calculate the extent of the given las file and return as GeoJSON. Arguments: file_path: path to the file from which to load the bounds default_epsg: the default EPSG to assume if a file has a boundary but not a coordinate system Return: Returns the JSON representing the image boundary, or None if the bounds could not be loaded Notes: If a file doesn't have a coordinate system and a default epsg is specified, the return JSON will use the default_epsg. If a file doesn't have a coordinate system and there isn't a default epsg specified, the boundary of the image is not returned (None) and a warning is logged. """ # Get the bounds and the EPSG code las_info = liblas.file.File(file_path, mode='r') min_bound = las_info.header.min max_bound = las_info.header.max epsg = __internal__.get_las_epsg_from_header(las_info.header) if epsg is None: if default_epsg is not None: epsg = default_epsg else: logging.warning( "Unable to find EPSG and not default is specified for file '%s'", file_path) return None ring = ogr.Geometry(ogr.wkbLinearRing) ring.AddPoint(min_bound[1], min_bound[0]) # Upper left ring.AddPoint(min_bound[1], max_bound[0]) # Upper right ring.AddPoint(max_bound[1], max_bound[0]) # lower right ring.AddPoint(max_bound[1], min_bound[0]) # lower left ring.AddPoint(min_bound[1], min_bound[0]) # Closing the polygon poly = ogr.Geometry(ogr.wkbPolygon) poly.AddGeometry(ring) ref_sys = osr.SpatialReference() if ref_sys.ImportFromEPSG(int(epsg)) == ogr.OGRERR_NONE: poly.AssignSpatialReference(ref_sys) return geometry_to_geojson(poly) logging.error("Failed to import EPSG %s for las file %s", str(epsg), file_path) return None