Source code for lidario.translator


import numpy as np
from lidario.io import InputHandler, OutputHandler


[docs]class Translator: """ Instantiate a Translator object which will handle the translation between given input and desired output type. :param input_type: Type of raster data provided: "**geotiff**" or "**mask**". - "geotiff": a .tif raster file. - "mask", a *rasterio.mask.mask()* result. :param output_type: Type of point cloud data to return: "**csv**", "**numpy**", "**pandas**", "**dictionary**", "**list**", "**tuple**". - "csv": a CSV file. - "ply": a .ply file. - "numpy": a Numpy array. Alternatives: "np", "array". - "dataframe": A Pandas dataframe: Alternatives: "pandas", "pd", "df". - "dictionary": A pure Python dictionary: Alternative: "dict". - "list" a pure Python list. - "tuple": a pure Python tuple. :param affine_transform: If True (default), apply an affine geo-transformation to the translated coordinates. :param metadata: If True, the "translate" method will return a tuple with the point cloud and the metadata. If False (default), it will only return the point cloud. :type input_type: str :type output_type: str :type affine_transform: bool, optional :type metadata: bool, optional """ def __init__(self, input_type, output_type, affine_transform=True, metadata=False): # Handle the input and output files/objects self.input_handler = InputHandler(input_type) self.output_handler = OutputHandler(output_type) # True point cloud has to be geo-transformed self.affine_transform = affine_transform self.return_metadata = metadata
[docs] def translate(self, input_values, out_file="output1.csv", out_format="binary", no_data=None, decimal=None, transpose=False, band=1): """ Translate a given "input_values" into a X, Y, Z point cloud. :param input_values: Data values to translate. Depend on the Translator's "input_type" parameter: - For a "**geotiff**": Takes the path to your .tif file (string). - For a "**mask**": Takes the np.array returned by a rasterio.mask.mask() method. :param out_file: Name of the file to save the point cloud. Used only if the Translator's "output_type" is a file type: "csv", "ply". Optional, default: "output.csv". :param out_format: Data format to save the file: "**binary**" (default) or "**ascii**" (not recommended, may be slow). Used only when "ply" is specified as "output_type". Optional. :param no_data: Value to exclude from the translation. - For a "**geotiff**": By default, use the nodata value stored in the tif file. If this value is missing, use -9999. - For a "**mask**": By default, use -9999. :param band: Band of the raster to translate. Used only if Translator's "input_values" is "geotiff". Default: 1. :param decimal: Round the coordinate numbers to the given decimal. Default: None. :param transpose: If True, transpose the coordinates. Default: False. :type input_values: str or np.array :type out_file: str, optional :param out_format: str, optional :type no_data: int, optional :type decimal: int, optional :type transpose: bool, optional :type band: bool, optional :return: The translated point cloud, typed as specified. If Translator's "output_type" is set to "csv", return None instead and save the CSV file. If Translator's "metadata" is set to True, return a tuple with the point cloud and the metadata. """ # Load the raster and metadata raster, metadata = self.input_handler.load(True, input_values, band) if no_data is None: no_data = metadata['nodata'] # Create a (x, y, z) point cloud from raster data x, y, z = self.__create_xyz_points(raster, no_data) # Geo-transform the coordinates if self.affine_transform: x, y = self.__affine_geo_transformation(x, y, metadata['transform']) # Round the numbers if decimal is not None: x, y, z = self.__round(x, y, z, decimal) # Save the point cloud point_cloud = self.output_handler.save(x, y, z, out_file, out_format, transpose) # If self.return_metadata is True, return the metadata if self.return_metadata: return point_cloud, metadata # If not, return only the point cloud return point_cloud
@staticmethod def __create_xyz_points(raster, no_data=-9999): """ Infer x, y, z points from raster data. :param raster: Raster data as numpy array. :param no_data: No data value of the raster. :type raster: np.array :type no_data: int :return: Tuple of np.array containing the point cloud: (x, y, z). :rtype tuple """ y, x = np.where(raster != no_data) z = np.extract(raster != no_data, raster) return x, y, z @staticmethod def __affine_geo_transformation(x, y, gtr): """ Create affine geo-transformed x and y. An affine transformation preserves collinearity and ratios of distances. It replace the point cloud into their original space of coordinates. :param x: X-array of coordinates. :param y: Y-array of coordinates. :param gtr: Affine geo-transformation data. :return: gtr_x, gtr_y, the geo-transformed x and y, as np.array. :rtype tuple """ # https://gdal.org/user/raster_data_model.html#affine-geotransform # Affine transformation rewritten for rasterio: gtr_x = gtr[2] + (x + 0.5) * gtr[0] + (y + 0.5) * gtr[1] gtr_y = gtr[5] + (x + 0.5) * gtr[3] + (y + 0.5) * gtr[4] return gtr_x, gtr_y @staticmethod def __round(x, y, z, decimal): return np.around(x, decimal),\ np.around(y, decimal),\ np.around(z, decimal)