Esempio n. 1
0
def loadCloudLAS(path):
    """
    Loads a LAS file from the specified path.
    """

    try:
        import laspy
    except:
        assert False, "Please install laspy (pip install laspy) to load LAS."

    # look for/load header file if one exists
    header, data = matchHeader(path)
    if not header is None:
        header = loadHeader(header) # load header file

    f = laspy.file.File(data, mode='r')

    # get data
    xyz = np.array([f.x, f.y, f.z], dtype=f.x.dtype).T

    # try to get colour info
    try:
        rgb = np.array([f.get_red(), f.get_green(), f.get_blue()], dtype=f.get_blue().dtype)
    except:
        rgb = None

    # construct cloud
    return HyCloud(xyz, rgb=rgb, header=header)
Esempio n. 2
0
def _merge(chunks, shape):
    """
    Merge a list of HyData objects into a combined one (aka. do the opposite of split(...)).

    *Arguments*:
     - chunks = a list of HyData chunks to merge.
     - shape = the output data shape.
    *Returns*: a single merged HyData instance (of the same type as the input).
               The header of this instance will be a copy of chunks[0].header.
    """

    # merge data
    X = np.vstack([c.data for c in chunks])
    X = X.reshape((*shape, -1))

    if not isinstance(chunks[0], HyCloud):  # easy!
        # make copy
        out = chunks[0].copy(data=False)
        out.data = X
        out.header = chunks[0].header.copy()
        return out
    else:  # less easy
        xyz = np.vstack([c.xyz for c in chunks])
        rgb = None
        if chunks[0].has_rgb():
            rgb = np.vstack([c.rgb for c in chunks])
        normals = None
        if chunks[0].has_normals():
            normals = np.vstack([c.normals for c in chunks])
        return HyCloud(xyz,
                       rgb=rgb,
                       normals=normals,
                       bands=X,
                       header=chunks[0].header.copy())
Esempio n. 3
0
def _split(data, nchunks):
    """
    Split the specified HyCloud instance into a number of chunks.

    *Arguments*:
     - data = the complete HyData object to copy and split.
     - nchunks = the number of chunks to split into.
    *Returns*:
     - a list of split
    """

    if isinstance(
            data, HyCloud
    ):  # special case for hyperclouds - split xyz, rgb and normals too
        chunksize = int(np.floor(data.point_count() / nchunks))
        chunks = [(i * chunksize, (i + 1) * chunksize) for i in range(nchunks)]
        chunks[-1] = (chunks[-1][0], data.point_count()
                      )  # expand last chunk to include remainder

        # split points
        xyz = [data.xyz[c[0]:c[1], :].copy() for c in chunks]

        # split data
        bands = [None for c in chunks]
        if data.has_bands():
            X = data.get_raveled().copy()
            bands = [X[c[0]:c[1], :] for c in chunks]

        # split rgb
        rgb = [None for c in chunks]
        if data.has_rgb():
            rgb = [data.rgb[c[0]:c[1], :].copy() for c in chunks]

        # split normals
        normals = [None for c in chunks]
        if data.has_normals():
            normals = [data.normals[c[0]:c[1], :].copy() for c in chunks]

        return [
            HyCloud(xyz[i],
                    rgb=rgb[i],
                    normals=normals[i],
                    bands=bands[i],
                    header=data.header.copy()) for i in range(len(chunks))
        ]

    else:  # just split data (for HyImage and other types)
        X = data.get_raveled().copy()
        chunksize = int(np.floor(X.shape[0] / nchunks))
        chunks = [(i * chunksize, (i + 1) * chunksize) for i in range(nchunks)]
        chunks[-1] = (chunks[-1][0], X.shape[0]
                      )  # expand last chunk to include remainder

        out = []
        for c in chunks:
            _o = data.copy(data=False)  # create copy
            _o.data = X[c[0]:c[1], :][:, None, :]
            out.append(_o)

        return out
Esempio n. 4
0
def genCloud(npoints=1000, nbands=10, data=True, normals=True, rgb=True):
    header = genHeader()

    xyz = np.random.rand(npoints, 3)
    if rgb:
        rgb = np.random.rand(npoints, 3)
    if normals:
        normals = np.random.rand(npoints, 3)
        normals = normals / np.linalg.norm(normals, axis=1)[:, None]
    if data:
        data = np.random.rand(npoints, nbands)  # point cloud

    cloud = HyCloud(xyz, rgb=rgb, normals=normals, bands=data, header=header)
    cloud.set_wavelengths(np.linspace(500.0, 1000.0, nbands))
    cloud.set_band_names(["Band %d" % (i + 1) for i in range(nbands)])
    cloud.set_fwhm([1.0 for i in range(nbands)])
    cloud.push_to_header()  # push info on dims

    return cloud
Esempio n. 5
0
def loadCloudDEM(pathDEM, pathRGB=None):
    """
    Combines a DEM file and an Orthophoto from the specified path to a cloud.
    """

    # load files
    DEMdata = loadWithGDAL(pathDEM)
    if not pathRGB is None:
        RGBdata = loadWithGDAL(pathRGB)

    # create list of pixel coordinates
    pixgrid = np.meshgrid(np.arange(0,DEMdata.xdim(),1),np.arange(0,DEMdata.ydim(),1))
    pixlist = np.vstack(((pixgrid[0]).flatten(),(pixgrid[1]).flatten()))

    # transform pixel coordinates to world xy coordinates
    fx=[]
    fy=[]
    for i in range(pixlist.shape[1]):
        tx,ty= DEMdata.pix_to_world(int(pixlist[0,i]),int(pixlist[1,i]))
        fx.append(tx)
        fy.append(ty)

    # add DEM data as z information and create xyz cloud list
    fz = DEMdata.data.flatten()
    xyz = np.array([fx, fy, fz]).T

    # if orthophoto is specified, extract RGB values for each DEM point and colorize cloud
    if not pathRGB is None:
        rgb=[]
        for i in range(len(xyz)):
            wx,wy = RGBdata.world_to_pix(xyz[i,0],xyz[i,1])
            rgb.append(RGBdata.data[wx,wy,:])

    # otherwise fill rgb info with zeros
    else:
        rgb = np.zeros((len(xyz),3))

    # return HyCloud
    return HyCloud(xyz, rgb=rgb)
Esempio n. 6
0
def loadCloudCSV(path, delimiter=' ', order='xyzrgbklm'):

    """
    Loads a point cloud from a csv (or other formatted text) file.

    *Arguments*:
     - path = the file path
     - delimeter = the delimeter used (e.g. ' ', ',', ';'). Default is ' '.
     - order = A string defining the order of data in the csv. Each character maps to the following:
                -'x' = point x coordinate
                -'y' = point y coordinate
                -'z' = point z coordinate
                -'r' = point r coordinate
                -'g' = point g coordinate
                -'b' = point b coordinate
                -'k' = point normal (x)
                -'l' = point normal (y)
                -'m' = point normal (z).

              Default is 'xyzrgbklm'.
    """

    # look for/load header file if one exists
    header, data = matchHeader(path)
    if not header is None:
        header = loadHeader(header) # load header file

    # load points
    points = np.genfromtxt(data, delimiter=delimiter, skip_header=1)
    assert points.shape[1] >= 3, "Error - dataset must at-least contain x,y,z point coordinates."

    # parse order string
    order = order.lower()
    xyz = [order.find('x'), order.find('y'), order.find('z')]
    assert not -1 in xyz, "Error - order must include x,y,z data."
    rgb = [order.find('r'), order.find('g'), order.find('b')]
    norm = [order.find('k'), order.find('l'), order.find('m')]
    notS = []  # columns that have already been parsed (so are not scalar fields)

    # get xyz
    notS += xyz
    xyz = points[:, xyz]

    # try get rgb and normals
    if max(rgb) < points.shape[1] and not -1 in rgb:
        notS += rgb
        rgb = points[:, rgb]

        # if RGB is 0-255 store as uint8 to minimise memory usage
        if (rgb > 1.0).any():
            rgb = rgb.astype(np.uint8)
    else:
        rgb = None
    if max(norm) < points.shape[1] and not -1 in norm:
        notS += norm
        norm = points[:, norm].astype(np.float32) #store norm as float32 rather than float64 (default)
    else:
        norm = None

        # get remaining data as scalar field
    scal = [i for i in range(points.shape[1]) if i not in notS]
    if len(scal) > 0:
        scal = points[:, scal]
    else:
        scal = None

    # return point cloud
    return HyCloud(xyz, rgb=rgb, normals=norm, bands=scal, header=header)
Esempio n. 7
0
def loadCloudPLY(path):
    """
    Loads a PLY file from the specified path.
    """

    try:
        from plyfile import PlyData, PlyElement
    except:
        assert False, "Please install plyfile (pip install plyfile) to load PLY."

    # look for/load header file if one exists
    header, data = matchHeader(path)
    if not header is None:
        header = loadHeader(header) # load header file

    # load file
    data = PlyData.read(data)

    # extract data
    xyz = None
    rgb = None
    norm = None
    scalar = []
    scalar_names = []
    for e in data.elements:
        if 'vert' in e.name.lower():  # vertex data
            xyz = np.array([e['x'], e['y'], e['z']]).T

            if len(e.properties) > 3:  # vertices have more than just position
                names = e.data.dtype.names

                # colour?
                if 'red' in names and 'green' in names and 'blue' in names:
                    rgb = np.array([e['red'], e['green'], e['blue']], dtype=e['red'].dtype).T

                # normals?
                if 'nx' in names and 'ny' in names and 'nz' in names:
                    norm = np.array([e['nx'], e['ny'], e['nz']], dtype=e['nx'].dtype).T

                # load others as scalar
                mask = ['red', 'green', 'blue', 'nx', 'ny', 'nz', 'x', 'y', 'z']
                for n in names:
                    if not n in mask:
                        scalar_names.append(n)
                        scalar.append(e[n])

        elif 'color' in e.name.lower():  # rgb data
            rgb = np.array([e['r'], e['g'], e['b']], dtype=e['r'].dtype).T
        elif 'normal' in e.name.lower():  # normal data
            norm = np.array([e['x'], e['y'], e['z']], dtype=e['z'].dtype).T
        else:  # scalar data
            scalar_names.append(e.properties[0].name)
            scalar.append(np.array(e[e.properties[0].name], dtype=e[e.properties[0].name].dtype))

    if len(scalar) == 0:
        scalar = None
        scalar_names = None
    else:
        scalar = np.vstack(scalar).T

    assert (not xyz is None) and (xyz.shape[0] > 0), "Error - cloud has not points?"

    # return HyCloud
    return HyCloud(xyz, rgb=rgb, normals=norm, bands=scalar, band_names=scalar_names, header=header)