def test_xyz(): las = pylas.create() shape = (150, ) las.X = np.zeros(shape, dtype=np.int32) las.Y = np.ones(shape, dtype=np.int32) las.Z = np.zeros(shape, dtype=np.int32) las.Z[:] = -152 las = write_then_read_again(las) assert np.alltrue(las.X == 0) assert np.alltrue(las.Y == 1) assert np.alltrue(las.Z == -152)
def test_coords_when_setting_offsets_and_scales(las): new_las = pylas.create() new_las.header.offsets = las.header.offsets new_las.header.scales = las.header.scales new_las.x = las.x new_las.y = las.y new_las.z = las.z assert np.allclose(las.x, new_las.x) assert np.allclose(las.y, new_las.y) assert np.allclose(las.z, new_las.z)
def test_create_fmt_0(): new = pylas.create(point_format=0) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) with pytest.raises(ValueError): new.gps_time = np.zeros(len(new.points), np.float64)
def test_extraction(file): new = pylas.create(point_format_id=0) assert file.points_data.point_format_id == 3 # automatic promotion of point format new.points = file.points[file.classification == 2] assert new.points_data.point_format_id == 3 assert new.header.point_format_id == 3 assert len(new.points) == sum(file.classification == 2) assert np.alltrue(new.classification == 2) file = write_then_read_again(new) assert np.alltrue(file.classification == 2)
def test_cant_create_scaled_extra_bytes_with_scales_array_smaller(num_elements): las = pylas.create() with pytest.raises(ValueError) as error: las.add_extra_dim( pylas.ExtraBytesParams( "must fail", f"{num_elements}int64", scales=np.array([0.1] * (num_elements - 1)), offsets=np.array([0.0] * num_elements), ) ) assert ( str(error.value) == f"len(scales) ({num_elements - 1}) is not the same as the number of elements ({num_elements})" )
def test_create_fmt_1(file): new = pylas.create(point_format_id=1) with pytest.raises(ValueError): new.red = file.red with pytest.raises(ValueError): new.red = file.green with pytest.raises(ValueError): new.red = file.blue new.gps_time = file.gps_time assert np.allclose(new.gps_time, file.gps_time) new = write_then_read_again(new) assert np.allclose(new.gps_time, file.gps_time)
def test_create_fmt_6(file1_4): new = pylas.create(point_format_id=6) assert new.header.version == "1.4" dim_names_fmt_6 = pylas.point.dims.get_dtype_of_format_id(6).names for dim_name in dim_names_fmt_6: new[dim_name] = file1_4[dim_name] for dim_name in dim_names_fmt_6: assert np.allclose(new[dim_name], file1_4[dim_name]), "{} not equal".format(dim_name) new = write_then_read_again(new) for dim_name in dim_names_fmt_6: assert np.allclose(new[dim_name], file1_4[dim_name]), "{} not equal".format(dim_name)
def test_create_fmt_6(file1_4): new = pylas.create(point_format=6) assert str(new.header.version) == "1.4" dim_names_fmt_6 = PointFormat(6).dtype().names for dim_name in dim_names_fmt_6: new[dim_name] = file1_4[dim_name] for dim_name in dim_names_fmt_6: assert np.allclose(new[dim_name], file1_4[dim_name]), "{} not equal".format(dim_name) new = write_then_read_again(new) for dim_name in dim_names_fmt_6: assert np.allclose(new[dim_name], file1_4[dim_name]), "{} not equal".format(dim_name)
def test_create_fmt_3(file): new = pylas.create(point_format=3) new.red = file.red new.green = file.green new.blue = file.blue new.gps_time = file.gps_time assert np.allclose(new.red, file.red) assert np.allclose(new.green, file.green) assert np.allclose(new.blue, file.blue) assert np.allclose(new.gps_time, file.gps_time) new = write_then_read_again(new) assert np.allclose(new.red, file.red) assert np.allclose(new.green, file.green) assert np.allclose(new.blue, file.blue) assert np.allclose(new.gps_time, file.gps_time)
def test_create_fmt_2(file): new = pylas.create(point_format=2) with pytest.raises(ValueError): new.gps_time = file.gps_time new.red = file.red new.green = file.green new.blue = file.blue assert np.allclose(new.red, file.red) assert np.allclose(new.green, file.green) assert np.allclose(new.blue, file.blue) new = write_then_read_again(new) assert np.allclose(new.red, file.red) assert np.allclose(new.green, file.green) assert np.allclose(new.blue, file.blue)
def test_create_fmt_1(): new = pylas.create(point_format=1) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) with pytest.raises(ValueError): new.red = np.zeros(len(new.points), np.uint16) gps_time = np.random.uniform(0, 25641, len(new.points)) new.gps_time = gps_time assert np.allclose(new.gps_time, gps_time) new = write_then_read_again(new) assert np.allclose(new.gps_time, gps_time)
def write(self, point_cloud, attributes='all', file_version='1.2', point_format_id=3): """ Write point cloud to a LAS(LAZ) file. :param point_cloud: :param attributes: list of attributes to write ('all' for all attributes in point_cloud) :param file_version: :param point_format_id: :return: """ file = pylas.create(point_format_id=point_format_id, file_version=file_version) points = point_cloud[keys.point] attributes = select_valid_attributes([attr for attr in points.keys()], attributes) # NOTE: adding extra dims and assignment should be done in two steps, # some fields (e.g. raw_classification) are otherwise overwritten for attribute in attributes: data, type = _get_data_and_type(points[attribute]) type_short = convert_to_short_type(type) if attribute not in 'xyz': # x,y,z are not there but file methods can be used to convert coords to int4 if attribute not in file.points.dtype.names: file.add_extra_dim(name=attribute, type=type_short) file_type_short = convert_to_short_type(getattr(file, attribute).dtype.name) if not file_type_short == type_short: raise TypeError('Data type in file does not match the one in point cloud: ' 'for {}, {} vs {}'.format(attribute, file_type_short, type_short)) for attribute in attributes: data, _ = _get_data_and_type(points[attribute]) if data.size == 0: raise ValueError('Cannot write empty point-cloud!') else: setattr(file, attribute, data) try: file.write(self.path) except ValueError as err: raise ValueError('Error in writing LAS file (file_version {}, point_format_id {}). ' 'pylas error below:\n{}'.format(file_version, point_format_id, err))
def write( point_data, output_path: Union[Path, str], *, crs: Optional[int] = None, xyz_offset: Tuple[float] = None, point_format: Optional[int] = None, scale: Tuple[float] = None, data_min_max: Optional[Dict[str, Tuple]] = None, ): """Write point cloud data to an output path. Look in point_formats.py to see the type of each destination field. Args: point_data (dict-like): Any object that implements the __getitem__ method. So a dictionnary, a pandas DataFrame, or a numpy structured array will all work. output_path (Union[Path, str]): The output path to write the las file. The output directory is created if it doesn't exist. xyz_offset (Tuple[float], optional): Apply this xyz offset before writing the coordinates. This can be useful for large coordinates loaded as float32 with an offset. The offset is applied by adding it to the coordinate. Defaults to (0, 0, 0). crs (int, optional): The EPSG code to write in the las header. point_format (int, optional): The las point format type identifier Only formats 0, 1, 2, 3, 6 and 7 are accepted. If None is given, the best point format will be guessed based on the provided fields. scale (Tuple[float], optional): The coordinate precision. Coordinates in the las file are stored in int32. This means that there is always a slight loss in precision. Most real world use cases are not affected if the scale is set correctly. So this should be set to the smallest error you can afford to have in the final file. Setting this to a number too small could lead to errors when using large coordinates. The default computes the scale based on the maximum range of a 32 bits signed integer. data_min_max (dict): Scale some dimensions according to these minimum and maximum values. Only these fields can be scaled: intensity, red, green, blue For example: the red channel is stored as uint16 inside a las file. If the red data in the source point_data is uint8, you can set data_min_max = {'red': (0, 255)} and the data will be scaled to the uint16 range 0-65536. """ Path(output_path).parent.mkdir(parents=True, exist_ok=True) if data_min_max is None: data_min_max = {} standard_dimensions = point_formats.standard_dimensions | {"xyz", "XYZ"} extra_dimensions = sorted(set(point_data) - standard_dimensions) if not point_format: point_format = point_formats.best_point_format(point_data, extra_dimensions) if point_format not in point_formats.supported_point_formats: raise ValueError( f"Unsupported point format {point_format} " f"(not in {point_formats.supported_point_formats})" ) point_format_type = point_formats.point_formats[point_format] xyz = None for coords in ["xyz", "XYZ"]: if coords in point_data: # expects an array of the shape (n_points, 3) xyz = [ point_data[coords][:, 0], point_data[coords][:, 1], point_data[coords][:, 2], ] break if all(c in point_data for c in coords): xyz = [point_data[c] for c in coords] break if not xyz: raise ValueError("Could not find xyz coordinates from input data.") las = pylas.create(file_version="1.4", point_format_id=point_format) if crs is not None: wkt = pyproj.CRS.from_epsg(crs).to_wkt() las.vlrs.append(WktCoordinateSystemVlr(wkt)) las.header.global_encoding.wkt = 1 for dim in extra_dimensions: dtype = point_data[dim].dtype las.add_extra_dim(name=dim, type=f"{dtype.kind}{dtype.itemsize}") min_, max_, offset = _min_max_offset(xyz) offset = offset if xyz_offset is None else xyz_offset if xyz_offset is None: xyz_offset = (0, 0, 0) min_ += xyz_offset max_ += xyz_offset las.header.mins, las.header.maxs, las.header.offsets = min_, max_, offset las.header.scales = scale if scale else _get_scale(min_, max_, offset) las.x = xyz[0].astype("d") + xyz_offset[0] las.y = xyz[1].astype("d") + xyz_offset[1] las.z = xyz[2].astype("d") + xyz_offset[2] if "gps_time" in point_format_type and "gps_time" in point_data: las.gps_time = point_data["gps_time"] if "intensity" in point_format_type and "intensity" in point_data: las.intensity = scale_data( "intensity", point_data["intensity"], data_min_max.get("intensity") ) if "classification" in point_format_type and "classification" in point_data: # convert pd.Series to numpy array, if applicable las.classification = np.array(point_data["classification"]) colors = ["red", "green", "blue"] if all(c in point_format_type and c in point_data for c in colors): for c in colors: setattr(las, c, scale_data(c, point_data[c], data_min_max.get(c))) for dim in extra_dimensions: setattr(las, dim, point_data[dim]) las.write(str(output_path))
if equation[0] < 0 and equation[1] < 0 and equation[2] < 0: dist_ind = np.where(distances < 0) else: dist_ind = np.where(distances > 0) # for x in range(10): # print(distances[dist_ind[0][x]]) # Check for no high points if not dist_ind: print("There are no points above the plane " + name) continue # Gather data for output las file out_x = las_x[dist_ind[0]] out_y = las_y[dist_ind[0]] out_z = las_z[dist_ind[0]] las_out = pylas.create() las_out.x = out_x las_out.y = out_y las_out.z = out_z # Write .las file las_out.write(name + ".las") print("done") # Close CSV file csvfile.close()
def test_good_version_is_used(): for i in range(6, 8): las = pylas.create(point_format=i) assert las.header.version.major == 1 assert las.header.version.minor == 4
def test_wrong_version(): for i in range(6, 8): with pytest.raises(pylas.errors.PylasError): _ = pylas.create(point_format=i, file_version="1.2")
print("==== ", las.points) bad_idx = np.where(las.points['Z'] >= mean * 1.05) bad_ffp = np.take(las.points, bad_idx) reduced_bad_ffp = np.squeeze(bad_ffp) colors = reduced_bad_ffp[["red", "green", 'blue']] vf = np.vectorize(convert_color) converted = vf(colors[:10]) filered_colors = 150 < converted[0] < 250 #todo funkcja, ktora sprawdzi czy kolor jest powyzej czy ponizej import pdb pdb.set_trace() # for color in colors: # converted = convert_color(color) # import pdb;pdb.set_trace() # filtered_points.write('data/filtered_points.las') new_test1 = pylas.create(point_format_id=2) new_test1.points = reduced_bad_ffp new_test1.vlrs = las.vlrs new_test1.header = las.header new_test1.write('data/filtered_points_experiments.las') print(11111251552, las.points_data)