def test_chunked_writing_gives_expected_points(file_path, backend): """ Write in chunked mode then test that the points are correct """ original_las = pylas.read(file_path) iter_size = 51 do_compress = True if backend is not None else False with io.BytesIO() as tmp_output: with pylas.open(tmp_output, mode="w", closefd=False, header=original_las.header, do_compress=do_compress, laz_backend=backend) as las: for i in range(int(math.ceil(len(original_las.points) / iter_size))): original_points = original_las.points[i * iter_size:(i + 1) * iter_size] las.write_points(original_points) tmp_output.seek(0) with pylas.open(tmp_output, closefd=False) as reader: check_chunked_reading_is_gives_expected_points( original_las, reader, iter_size)
def test_chunked_laz_reading_gives_expected_points(laz_file_path, laz_backend): """ Test LAZ reading in chunked mode with different backends """ with pylas.open(laz_file_path) as las_reader: with pylas.open(laz_file_path, laz_backend=laz_backend) as laz_reader: expected_las = las_reader.read() check_chunked_reading_is_gives_expected_points(expected_las, laz_reader, iter_size=50)
def test_chunked_las_reading_gives_expected_points(las_file_path): """ Test chunked LAS reading """ with pylas.open(las_file_path) as las_reader: with pylas.open(las_file_path) as reader: las = las_reader.read() check_chunked_reading_is_gives_expected_points(las, reader, iter_size=50)
def main(): parser = argparse.ArgumentParser( "LAS recursive splitter", description="Splits a las file bounds recursively") parser.add_argument("input_file") parser.add_argument("output_dir") parser.add_argument("size", type=tuple_size, help="eg: 50x64.17") parser.add_argument("--points-per-iter", default=10**6, type=int) args = parser.parse_args() with pylas.open(sys.argv[1]) as file: sub_bounds = recursive_split(file.header.x_min, file.header.y_min, file.header.x_max, file.header.y_max, args.size[0], args.size[1]) writers: List[Optional[pylas.LasWriter]] = [None] * len(sub_bounds) try: count = 0 for points in file.chunk_iterator(args.points_per_iter): print(f"{count / file.header.point_count * 100}%") # For performance we need to use copy # so that the underlying arrays are contiguous x, y = points.x.copy(), points.y.copy() point_piped = 0 for i, (x_min, y_min, x_max, y_max) in enumerate(sub_bounds): mask = (x >= x_min) & (x <= x_max) & (y >= y_min) & (y <= y_max) if np.any(mask): if writers[i] is None: output_path = Path(sys.argv[2]) / f"output_{i}.laz" writers[i] = pylas.open(output_path, mode='w', header=file.header) sub_points = points[mask] writers[i].write_points(sub_points) point_piped += np.sum(mask) if point_piped == len(points): break count += len(points) print(f"{count / file.header.point_count * 100}%") finally: for writer in writers: if writer is not None: writer.close()
def test_read_offset(): header = read_header(very_small_las) with pylas.open(str(very_small_las)) as f: assert list(f.header.scales) == header.scale assert list(f.header.offsets) == header.offset assert list(f.header.mins) == header.min assert list(f.header.maxs) == header.max
def __init__(self, filename): fh = pylas.open(filename) self.laz = fh.read() self.x_min = self.laz.x.min() self.x_max = self.laz.x.max() self.y_min = self.laz.y.min() self.y_max = self.laz.y.max() #self.points = list(zip(self.laz.x, self.laz.y)) self.points = self.laz.points self.dt = self.points.dtype
def read_las_with_pylas(filename): data = {} if pylas is None: raise ImportError("pylas is needed for reading .las files.") with pylas.open(filename) as las_file: las = las_file.read() data["points"] = pd.DataFrame(las.points) data["points"].columns = (x.lower() for x in data["points"].columns) # because pylas do something strange with scale data["points"].loc[:, ["x", "y", "z"]] *= las.header.scales data["las_header"] = las.header return data
def main_lidar(): #dset = SimpleGeoDataset('/data/pointCloudStuff/img/DC/2013.utm.tif') dset = SimpleGeoDataset('/data/dc_tiffs/dc.tif') dir_ = '/data/pointCloudStuff/pc/dc' ext = '.las' #app = PointRenderer(1024//2,1024//2) app = PointRenderer(1024, 1024) #app = PointRenderer(1024*2,2*1024) app.init(True) for fname in [f for f in os.listdir(dir_) if f.endswith(ext)]: fname = os.path.join(dir_, fname) print(' - Opening', fname) with pylas.open(fname) as fp: las = fp.read() stride = 1 ''' pts0 = np.stack((las.x[::stride], las.y[::stride], las.z[::stride]),-1).astype(np.float32) lo,hi = np.quantile(pts0, [.003,.997], 0) pts0 = pts0[(pts0[:,0] > lo[0]) & (pts0[:,1] > lo[1]) & (pts0[:,2] > lo[2]) & \ (pts0[:,0] < hi[0]) & (pts0[:,1] < hi[1]) & (pts0[:,2] < hi[2]) ] pts1 = ((pts0 - lo) / max(hi - lo)) * 2 - 1 #pts = torch.from_numpy(pts1).cuda() app.pts = pts1 app.colors = (pts0 - lo) / (hi - lo) ''' pts, colors, img = process_pc_get_pts(las, dset, stride) pts, density = voxelize.filterOutliers(torch.from_numpy(pts), 12) density = density.cpu().numpy() pts = pts.cpu().numpy() T = 2 pts = pts[density > T] colors = autumn(density[density > T] / 5)[..., :3].astype( np.float32) #colors[density<1.7] = (0,1,0) #app.pts,app.colors = pts,colors app.setPts(pts, colors, None) print(' - Setting', app.pts.shape[0], 'pts') while not app.q_pressed: app.startFrame() app.render() app.endFrame() #if app.endFrame(): break app.q_pressed = False
def get_points(lidarFile, num=-1, stride=1): with pylas.open(lidarFile) as fh: print('Points from Header:', fh.header.point_count) las = fh.read() print(las) print('Points from data:', len(las.points)) print(las.points_data.point_format.dimension_names) N,s = num, stride x,y,z = las.x[0:N:s],las.y[:N:s],las.z[:N:s] n = len(x) color = None ''' dset = None if dset is None: from matplotlib.cm import inferno inten = las.intensity.astype(np.float32)[0:N:s] div = min(inten.max(), inten.mean()*2.5) inten = (inten/div) color = inferno(inten).astype(np.float32) # Looks pretty cool else: x1,y1,x2,y2 = x.min(), y.min(), x.max(), y.max() xywh = xxyy = x1,y1, x2-x1, y2-y1 print('xxyy', x1,y1,x2,y2) print('xywh', xywh) pix_bb = tuple(int(a) for a in dset.xform_bbox_utm2pix(xywh)) print('pix_bb', pix_bb) img = dset.bbox(*pix_bb, int(xywh[2]), int(xywh[3])) # Sample at 1 px/m samples = np.stack((y,x),1) - (y1,x1) OFFSET_X, OFFSET_Y = 0, 10 # Flip (UTM is north up, image is up down) samples[:,0] = (img.shape[0] - 1+OFFSET_Y - samples[:,0]).clip(min=0,max=img.shape[0]-1) #samples[:,1] = img.shape[1] - samples[:,1].clip(min=0,max=img.shape[1]-1) - 1 samples[:,1] = (samples[:,1]+OFFSET_X).clip(min=0,max=img.shape[1]-1) samples = samples.astype(np.int32) print('SAMPLES',samples) color = img[samples[:,0], samples[:,1]] color = color.astype(np.float32) / 255. color = np.hstack( (color,np.ones((len(color),1),dtype=np.float32)) ) ''' pts = np.stack((x,y,z), -1).astype(np.float32) if False: pts = pts - pts.mean(0) pts = pts / np.quantile(abs(pts), .96) pts = pts - pts.mean(0) pts = pts * 50000 pts = pts - pts.mean(0) pts = pts - pts.mean(0) print('max/min',pts.max(0), pts.min(0)) return pts, color
def append_self_and_check(las_path_fixture): with open(las_path_fixture, mode="rb") as f: file = io.BytesIO(f.read()) las = pylas.read(las_path_fixture) with pylas.open(file, mode='a', closefd=False) as laz_file: laz_file.append_points(las.points) file.seek(0, io.SEEK_SET) rlas = pylas.read(file) assert rlas.header.point_count == 2 * las.header.point_count assert rlas.points[:rlas.header.point_count // 2] == las.points assert rlas.points[rlas.header.point_count // 2:] == las.points return rlas
def _get_details_pc_file(filename): try: with pylas.open(filename) as file: count = file.header.point_count mins = file.header.mins maxs = file.header.maxs scales = file.header.scales offsets = file.header.offsets return (count, mins, maxs, scales, offsets) except IOError: logger.error('failure to open {}'.format(filename)) return None
def read_las(self, fpath): """读取点云""" if fpath.strip() == '': print('File path cannot be empty.') try: with pylas.open(fpath) as fh: print('Date from Header:', fh.header.date) print('Software from Header:', fh.header.generating_software) print('Points from Header:', fh.header.point_count) las = fh.read() return las except Exception as e: logging.error('加载Las出错,出错原因:%s' % e) print('加载Las出错,出错原因:%s' % e) return []
def info(file, extended, vlrs, points): """ Prints the file information to stdout. By default only information of the header are written """ try: with pylas.open(openbin_file(file)) as fp: echo_header(fp.header, extended) if vlrs: click.echo(20 * "-") echo_vlrs(fp) if points: click.echo(20 * "-") echo_points(fp) except fs.errors.ResourceNotFound as e: click.echo(click.style("Error: {}".format(e), fg="red"))
def main(): dset = SimpleGeoDataset('/data/pointCloudStuff/img/DC/2013.utm.tif') dir_ = '/data/pointCloudStuff/pc/dc/' ext = '.las' app = PointRenderer(1024, 1024) app.init(True) for fname in [f for f in os.listdir(dir_) if f.endswith(ext)]: fname = os.path.join(dir_, fname) print(' - Opening', fname) with pylas.open(fname) as fp: las = fp.read() stride = 1 ''' pts0 = np.stack((las.x[::stride], las.y[::stride], las.z[::stride]),-1).astype(np.float32) lo,hi = np.quantile(pts0, [.003,.997], 0) pts0 = pts0[(pts0[:,0] > lo[0]) & (pts0[:,1] > lo[1]) & (pts0[:,2] > lo[2]) & \ (pts0[:,0] < hi[0]) & (pts0[:,1] < hi[1]) & (pts0[:,2] < hi[2]) ] pts1 = ((pts0 - lo) / max(hi - lo)) * 2 - 1 #pts = torch.from_numpy(pts1).cuda() app.pts = pts1 app.colors = (pts0 - lo) / (hi - lo) ''' pts, colors, img = process_pc_get_pts(las, dset, stride) #app.pts,app.colors = pts,colors app.setPts(pts, colors, None) print(' - Setting', app.pts.shape[0], 'pts') while not app.q_pressed: app.startFrame() app.render() if app.endFrame(): break app.q_pressed = False
def eightbitify(colour): import numpy as np notzero = np.where(colour > 0) colour[notzero] = (colour[notzero]/255) - 1 return colour def readPoints(reader: lasreader.LasReader): data = reader.read() v = data.header minBounds = [v.x_min, v.y_min, v.z_min] maxBounds = [v.x_max, v.y_max, v.z_max] points = zip(data.x, data.y, data.z, eightbitify(data.points['red']), eightbitify(data.points['green']), eightbitify(data.points['blue'])) exportToPnts(points) outputTileset({ 'min': minBounds, 'max': maxBounds }, len(data.points)) moveTilesAndTileset("") with pylas.open(sys.argv[1], "r") as f: readPoints(f)
def get_dc_lidar(cfg): import pylas, ctypes stride = 1 #f = '/data/lidar/USGS_LPC_VA_Fairfax_County_2018_e1617n1924.laz' f,stride = '/data/lidar/dc1.las', cfg.get('stride',8) #f,stride = '/data/lidar/PA_Statewide_S_2006-2008_002771.las', 2 #f,stride = '/data/lidar/airport.las', 4 cfg.setdefault('maxDepth', 8) st0 = time.time() with pylas.open(f) as fh: N = -1 st1 = time.time() las = fh.read() print(' - las read took {:.2f}ms ({} pts)'.format((time.time()-st1)*1000,len(las.x))) st1 = time.time() x,y,z = las.x[0:N:stride],las.y[:N:stride],las.z[:N:stride] inten,angle = las.intensity[0:N:stride], las.scan_angle_rank[:N:stride] print(' - las slice took {:.2f}ms ({} pts)'.format((time.time()-st1)*1000, len(x))) st1 = time.time() qq = cfg.get('qq',.05) qqz0, qqz1 = .0000001, .99995 # Because many high z's are outliers, reject points >quantile(qqz1) (x1,x2),(y1,y2),(z1,z2) = np.quantile(x[::2],[qq,1-qq]), np.quantile(y[::2],[qq,1-qq]), np.quantile(z[::2],[qqz0,qqz1]) print(' - las quantile took {:.2f}ms'.format((time.time()-st1)*1000)) maxEdge = max(x2-x1, y2-y1) #xx,yy,zz = (x-x1) / maxEdge, (y-y1) / maxEdge, (z-z1) / maxEdge st1 = time.time() #pts = np.stack((xx,yy,zz), -1).astype(np.float32) pts = ((np.stack((x,y,z), -1) - (x1,y1,z1)) / maxEdge).astype(np.float32) inten = inten[(pts>0).all(1) & (pts<1).all(1) & (pts[:,2]<(z2-z1)/maxEdge)] angle = angle[(pts>0).all(1) & (pts<1).all(1) & (pts[:,2]<(z2-z1)/maxEdge)] pts = pts[(pts>0).all(1) & (pts<1).all(1) & (pts[:,2]<(z2-z1)/maxEdge)] print(' - las stack took {:.2f}ms'.format((time.time()-st1)*1000)) size = 2 print(pts[::pts.shape[0]//5]) print(' - las total load took {:.2f}ms'.format((time.time()-st0)*1000)) vals = np.ones_like(pts[:,0]) M = np.eye(4, dtype=np.float32) M[:3, 3] = (x1,y1,z1) M[:3,:3] = np.diag((maxEdge,)*3) endPoints = np.array(( (0,0,0,1.), (1,1,1,1.))) @ M.T endPoints = endPoints[:, :3] / endPoints[:, 3:] utm_bbox = *endPoints[0,:2], *(endPoints[1,:2]-endPoints[0,:2]) ox,oy = -2, -8 # Tiff or point-cloud is mis-aligned! ox,oy = 0,0 utm_bbox = (utm_bbox[0]+ox,utm_bbox[1]+oy,utm_bbox[2],utm_bbox[3]) img = get_tiff_patch('/data/dc_tiffs/dc.tif', utm_bbox, 2048*2) #img = get_tiff_patch('/data/dc_tiffs/dupont1/whole.32618.tif', utm_bbox, 2048*2) return dict( pts=pts, inten=inten, angle=angle, vals=vals, grid2native=M, img=img, maxEdge=maxEdge, pix2meter=maxEdge )
parser.add_argument( '--lidarFile', default='data/USGS_LPC_MD_VA_Sandy_NCR_2014_18SUJ321308_LAS_2015.laz') parser.add_argument( '--tiff', default='/home/slee/stuff/terrapixel/terraslam/data/dc/dc.tiff') parser.add_argument('--N', default=90000000, type=int) args = parser.parse_args() if args.tiff == None or len(args.tiff) < 2: dset = None else: # TODO: Remove dependency on my code for work. from pytavio.geodata.gdal_dataset import GeoDataset dset = GeoDataset(args.tiff) with pylas.open(args.lidarFile) as fh: print('Points from Header:', fh.header.point_count) las = fh.read() print(las) print('Points from data:', len(las.points)) print(las.x) print(las.y) print(las.z) print(las.points_data.point_format.dimension_names) N = args.N s = 1 x, y, z = las.x[0:N:s], las.y[:N:s], las.z[:N:s] n = len(x) if dset is None:
validClasses = [1, 2, 5, 6, 9] with open(Paths.Aerial.pointCloudPath + 'summary.csv', 'w') as csvFile: fieldnames = ['File', 'Points'] fieldnames.extend(validClasses) writer = csv.DictWriter(csvFile, fieldnames=fieldnames) writer.writeheader() for file in tqdm(laz_files): file_name = os.path.splitext(os.path.basename(file))[0] new_file = os.path.join(directory_to_extract_to, file_name + ".npy") if (os.path.exists(new_file)): continue try: with pylas.open(file) as lazFile: lasFile = lazFile.read() xyz = np.concatenate( (np.expand_dims(lasFile.x, 1), np.expand_dims( lasFile.y, 1), np.expand_dims(lasFile.z, 1)), 1) xyz -= xyz.min(axis=0) xyz = xyz.astype(np.float32) intensity = np.expand_dims(lasFile.intensity * normalization, 1) intensity = intensity.astype(np.float32) lbl = np.expand_dims(lasFile.classification, 1) classes = {}
def get_header(): with pylas.open(simple_las) as fin: return fin.header
def testLidar(): import pylas, ctypes stride = 1 #f = '/data/lidar/USGS_LPC_VA_Fairfax_County_2018_e1617n1924.laz' f,stride = '/data/lidar/dc1.las', 2 #f,stride = '/data/lidar/PA_Statewide_S_2006-2008_002771.las', 2 #f,stride = '/data/lidar/airport.las', 4 with pylas.open(f) as fh: N = -1 las = fh.read() x,y,z = las.x[0:N:stride],las.y[:N:stride],las.z[:N:stride] #x1,y1,x2,y2,z1,z2 = x.min(), y.min(), x.max(), y.max(), z.min(), z.max() (x1,x2),(y1,y2),(z1,z2) = np.quantile(x[::4],[.1,.9]), np.quantile(y[::4],[.1,.9]), np.quantile(z[::4],[.1,.9]) #xx,yy,zz = x - (x1+x2)/2, y - (y1+y2)/2, z - (z1+z2)/2 modelScale = x2-x1 xx,yy,zz = x - x1 - modelScale/2, y - y1 - modelScale/2, z - z1 #x1,y1,x2,y2,z1,z2 = x.min(), y.min(), x.max(), y.max(), z.min(), z.max() #xq = np.quantile(abs(xx[::4]),.9) pts = np.stack((xx,yy,zz), -1).astype(np.float32) pts = pts / modelScale size = 2 print(' - size', size) offset = np.ones(3,dtype=np.float32) * -size/2 print(pts[::100000]) vals = np.ones_like(pts[:,0]) loc = np.zeros(4,dtype=np.int32) st = time.time() tree = pycmeshedup.Octree(offset, loc, size, 0, 10) id = 0 ''' pts2 = np.tile(pts.T,2).T + np.random.randn(pts.shape[0]*2,pts.shape[1]) / 30 for pt in pts2: tree.add(pt, id, 0) id += 1 ''' for (pt,val) in (zip(pts,vals)): tree.add(pt, id, val) id += 1 print(' - Octree indexing {} pts took {:.1f}ms'.format(len(pts),(time.time()-st)*1000)) iso = .0002 colors = np.ones((len(vals),4), dtype=np.float32) colors[vals<iso] = (.9,.1,.2,.5) colors[vals>iso] = (.1,.9,.2,.5) import tview dset = tview.GeoDataset('/data/dc_tiffs/dc.tif') #bbox = np.array((x.min(),y.min(), x.max()-x.min(), y.max()-y.min())).astype(np.float64) bbox = np.array((x1,y1,x2-x1,y2-y1)).astype(np.float64) aspect_wh = bbox[3] / bbox[2] print(' - Dset bbox:', bbox) tex = np.array(dset.bboxNative(bbox, 2048,int(aspect_wh*2048), True)) print(' - img shape', tex.shape) #cv2.imshow('tex',tex);cv2.waitKey(0) uvs = None st = time.time() tris = pycmeshedup.meshOctree(tree, iso) print(' - Octree meshing {} pts took {:.1f}ms'.format(len(pts),(time.time()-st)*1000)) if len(tris)>0: tris = np.concatenate(tris,0) coords = (x1,x2, y1,y2, z1,z2, modelScale) return tree, pts,vals,tris, colors, uvs,tex, coords
def test_raises_for_laszip_backend(): with pytest.raises(pylas.PylasError): with pylas.open(simple_laz, mode="a", laz_backend=pylas.LazBackend.Laszip): ...
path = "/Users/john/AI/Thesis/Data/AHN3/" filename = "C_26AZ2.LAZ" totalpath = "/Users/john/AI/Thesis/Data/AHN3/C_26AZ2.LAZ" import numpy as np import pylas # # Directly read and write las # las = pylas.read(path + filename) # las = pylas.convert(las, point_format_id=2) # las.write('converted.las') # # Open data to inspect header and then read # with pylas.open(path + filename) as f: # print(f.header.point_count) # # if f.header.point_count < 10 ** 8: # # las = f.read() # # print(las.vlrs) with pylas.open(path + filename) as fh: print('Points from Header:', fh.header.point_count) las = fh.read() print(las) print('Points from data:', len(las.points)) ground_pts = las.classification == 2 bins, counts = np.unique(las.return_number[ground_pts], return_counts=True) print('Ground Point Return Number distribution:') for r, c in zip(bins, counts): print(' {}:{}'.format(r, c))
import pylas import sys with pylas.open(sys.argv[1]) as fh: print(fh.header.x_min) print(fh.header.y_min) print(fh.header.z_min) print(fh.header.x_max) print(fh.header.y_max) print(fh.header.z_max)
def get_dc_lidar_data(cfg): import pylas, ctypes stride = 1 #f = '/data/lidar/USGS_LPC_VA_Fairfax_County_2018_e1617n1924.laz' f, stride = '/data/lidar/dc1.las', 8 #f,stride = '/data/lidar/PA_Statewide_S_2006-2008_002771.las', 2 #f,stride = '/data/lidar/airport.las', 4 cfg.setdefault('maxDepth', 12) st0 = time.time() with pylas.open(f) as fh: N = -1 st1 = time.time() las = fh.read() print(' - las read took {:.2f}ms'.format( (time.time() - st1) * 1000)) st1 = time.time() x, y, z = las.x[0:N:stride], las.y[:N:stride], las.z[:N:stride] print(' - las slice took {:.2f}ms'.format( (time.time() - st1) * 1000)) st1 = time.time() (x1, x2), (y1, y2), (z1, z2) = np.quantile(x[::4], [.1, .9]), np.quantile( y[::4], [.1, .9]), np.quantile(z[::4], [.1, .9]) print(' - las quantile took {:.2f}ms'.format( (time.time() - st1) * 1000)) maxEdge = max(x2 - x1, y2 - y1) #xx,yy,zz = (x-x1) / maxEdge, (y-y1) / maxEdge, (z-z1) / maxEdge st1 = time.time() #pts = np.stack((xx,yy,zz), -1).astype(np.float32) pts = ((np.stack( (x, y, z), -1) - (x1, y1, z1)) / maxEdge).astype(np.float32) print(' - las stack took {:.2f}ms'.format( (time.time() - st1) * 1000)) size = 2 print(pts[::pts.shape[0] // 5]) print(' - las total load took {:.2f}ms'.format((time.time() - st0) * 1000)) vals = np.ones_like(pts[:, 0]) M = np.eye(4, dtype=np.float32) M[:3, 3] = (x1, y1, z1) M[:3, :3] = np.diag((maxEdge, ) * 3) endPoints = np.array(((0, 0, 0, 1.), (1, 1, 1, 1.))) @ M.T endPoints = endPoints[:, :3] / endPoints[:, 3:] utm_bbox = *endPoints[0, :2], *(endPoints[1, :2] - endPoints[0, :2]) ox, oy = -2, -8 utm_bbox = (utm_bbox[0] + ox, utm_bbox[1] + oy, utm_bbox[2], utm_bbox[3]) img = get_tiff_patch('/data/dc_tiffs/dc.tif', utm_bbox, 2048 + 2048) return dict( pts=pts, vals=vals, grid2native=M, img=img, )
def get_number_of_points_in_LAZ_file(filename): with pylas.open(filename) as f: count = f.header.point_count return count
# Directly read and write las data_file = 'data/W2 .las' filtered_file = 'data/filtered_points.las' coopy = 'data/filtered_points_good_copy.las' # data_file = coopy las = pylas.read(data_file) print(las) # las = pylas.convert(las, point_format_id=2) # las.write('data/converted.las') # Open data to inspect header and then read with pylas.open(data_file) as f: las = f.read() median = np.median(las.points['Z']) mean = np.mean(las.points['Z']) good_idx = np.where(las.points['Z'] < mean) filtered_points = np.take(las.points, good_idx) reduced_shape_points = np.squeeze(filtered_points) print("START1 = ", reduced_shape_points.shape) print("START2 = ", las.points.shape) 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)
def get_points_from_las(fn, N=99999999, stride=1): with pylas.open(fn) as fp: las = fp.read() x, y, z = las.x[:N:stride], las.y[:N:stride], las.z[:N:stride] points = np.stack((x, y, z), -1) return points