def save(cloud, path, format=None, binary=False, las_header=None): """Save a pointcloud to file. Supports LAS and CSV files, and lets PCD and PLY files be saved by python-pcl. Arguments: cloud : pcl.PointCloud or pcl.PointCloudXYZRGB Pointcloud to save. path : string Filename. format : string File format: "PLY", "PCD", "LAS", "CSV", or None to detect the format from the file extension. binary : boolean Whether PLY and PCD files are saved in binary format. las_header: liblas.header.Header LAS header to use. When none, a default header is created by make_las_header(). Default: None """ if format == 'las' or format is None and path.endswith('.las'): _save_las(path, cloud, header=las_header) elif format == 'csv' or format is None and path.endswith('.csv'): _save_csv(path, cloud) else: _check_writable(path) if is_registered(cloud) and cloud.offset != np.zeros(3): cloud_array = np.asarray(cloud) cloud_array += cloud.offset pcl.save(cloud, path, format=format, binary=binary)
def test_force_srs(): """Test the force_srs() function""" rdnew = osr.SpatialReference() rdnew.SetFromUserInput( "EPSG:28992" ) latlon = osr.SpatialReference() latlon.SetFromUserInput( "EPSG:4326" ) # using offset and srs (text) pcA = pcl.PointCloud( [[1,2,3]] ) force_srs( pcA, offset=[0,0,0], srs="EPSG:28992" ) assert_true( is_registered( pcA ) ) assert_array_almost_equal( pcA.offset, np.zeros(3, dtype=np.float64), 15, "Offset not zero to 15 decimals" ) assert_true( pcA.srs.IsSame( rdnew ) ) # using same_as pcB = pcl.PointCloud( [[1,2,3]] ) force_srs( pcB, same_as=pcA ) assert_true( is_registered( pcB ) ) assert_array_almost_equal( pcB.offset, np.zeros(3, dtype=np.float64), 15, "Offset not zero to 15 decimals" ) assert_true( pcB.srs.IsSame( rdnew ) ) # using no offset and osr.SpatialReference() pcC = pcl.PointCloud( [[1,2,3]] ) force_srs( pcC, srs=rdnew ) assert_true( pcC.srs.IsSame( rdnew ) ) assert_false( hasattr( pcC, "offset" ) ) # testing if no actual transform occurs on the points force_srs(pcC, srs=latlon ) assert_false( pcC.srs.IsSame( pcA.srs ) ) assert_array_almost_equal( np.asarray(pcA), np.asarray(pcC), 8, "force_srs() should not alter points" )
def test_force_srs(): """Test the force_srs() function""" rdnew = osr.SpatialReference() rdnew.SetFromUserInput("EPSG:28992") latlon = osr.SpatialReference() latlon.SetFromUserInput("EPSG:4326") # using offset and srs (text) pcA = pcl.PointCloud([[1, 2, 3]]) force_srs(pcA, offset=[0, 0, 0], srs="EPSG:28992") assert_true(is_registered(pcA)) assert_array_almost_equal(pcA.offset, np.zeros(3, dtype=np.float64), 15, "Offset not zero to 15 decimals") assert_true(pcA.srs.IsSame(rdnew)) # using same_as pcB = pcl.PointCloud([[1, 2, 3]]) force_srs(pcB, same_as=pcA) assert_true(is_registered(pcB)) assert_array_almost_equal(pcB.offset, np.zeros(3, dtype=np.float64), 15, "Offset not zero to 15 decimals") assert_true(pcB.srs.IsSame(rdnew)) # using no offset and osr.SpatialReference() pcC = pcl.PointCloud([[1, 2, 3]]) force_srs(pcC, srs=rdnew) assert_true(pcC.srs.IsSame(rdnew)) assert_false(hasattr(pcC, "offset")) # testing if no actual transform occurs on the points force_srs(pcC, srs=latlon) assert_false(pcC.srs.IsSame(pcA.srs)) assert_array_almost_equal(np.asarray(pcA), np.asarray(pcC), 8, "force_srs() should not alter points")
def make_las_header(pointcloud): """Make a LAS header for given pointcloud. If the pointcloud is registered, this is taken into account for the header metadata. LAS rounds the coordinates on writing; this is controlled via the 'precision' attribute of the input pointcloud. By default this is 0.01 in units of the projection. Arguments: pointcloud : pcl.PointCloud Input pointcloud. Returns: header : liblas.header.Header Header for writing the pointcloud to a LAS file. """ schema = liblas.schema.Schema() schema.time = False schema.color = True # FIXME: this format version assumes color is present head = liblas.header.Header() head.schema = schema head.dataformat_id = 3 head.major_version = 1 head.minor_version = 2 if is_registered(pointcloud): try: lsrs = liblas.srs.SRS() lsrs.set_wkt(pointcloud.srs.ExportToWkt()) head.set_srs(lsrs) except liblas.core.LASException: pass if hasattr(pointcloud, 'offset'): head.offset = pointcloud.offset else: head.offset = np.zeros(3) # FIXME: need extra precision to reduce floating point errors. We don't # know exactly why this works. It might reduce precision on the top of # the float, but reduces an error of one bit for the last digit. if not hasattr(pointcloud, 'precision'): precision = np.array([0.01, 0.01, 0.01], dtype=np.float64) else: precision = np.array(pointcloud.precision, dtype=np.float64) head.scale = precision * 0.5 pc_array = np.asarray(pointcloud) head.min = pc_array.min(axis=0) + head.offset head.max = pc_array.max(axis=0) + head.offset return head
def extract_mask(pointcloud, mask): """Extract all points in a mask into a new pointcloud. Arguments: pointcloud : pcl.PointCloud Input pointcloud. mask : numpy.ndarray of bool mask for which points from the pointcloud to include. Returns: pointcloud with the same registration (if any) as the original one.""" pointcloud_new = pointcloud.extract(np.where(mask)[0]) if is_registered(pointcloud): force_srs(pointcloud_new, same_as=pointcloud) return pointcloud_new
def clone(pc): """ Return a copy of a pointcloud, including registration metadata Arguments: pc: pcl.PointCloud() Returns: cp: pcl.PointCloud() """ cp = pcl.PointCloud(np.asarray(pc)) if is_registered(pc): force_srs(cp, same_as=pc) return cp