Beispiel #1
0
def main():

    try:
        import pysptools.eea as eea
    except ImportError:
        gs.fatal(_("Cannot import pysptools \
                      (https://pypi.python.org/pypi/pysptools) library."
                      " Please install it (pip install pysptools)"
                      " or ensure that it is on path"
                      " (use PYTHONPATH variable)."))

    try:
        # sklearn is a dependency of used pysptools functionality
        import sklearn
    except ImportError:
        gs.fatal(_("Cannot import sklearn \
                      (https://pypi.python.org/pypi/scikit-learn) library."
                      " Please install it (pip install scikit-learn)"
                      " or ensure that it is on path"
                      " (use PYTHONPATH variable)."))

    try:
        from cvxopt import solvers, matrix
    except ImportError:
        gs.fatal(_("Cannot import cvxopt \
                      (https://pypi.python.org/pypi/cvxopt) library."
                      " Please install it (pip install cvxopt)"
                      " or ensure that it is on path"
                      " (use PYTHONPATH variable)."))

    # Parse input options
    input = options['input']
    output = options['output']
    prefix = options['prefix']
    endmember_n = int(options['endmember_n'])
    endmembers = options['endmembers']
    if options['maxit']:
        maxit = options['maxit']
    else:
        maxit = 0
    extraction_method = options['extraction_method']
    unmixing_method = options['unmixing_method']
    atgp_init = True if not flags['n'] else False

    # List maps in imagery group
    try:
        maps = gs.read_command('i.group', flags='g', group=input,
                               quiet=True).rstrip('\n').split('\n')
    except:
        pass

    # Validate input
    # q and maxit can be None according to manual, but does not work in current pysptools version
    if endmember_n <= 0:
        gs.fatal('Number of endmembers has to be > 0')
        """if (extraction_method == 'PPI' or
            extraction_method == 'NFINDR'):
            gs.fatal('Extraction methods PPI and NFINDR require endmember_n >= 2')
        endmember_n = None"""

    if maxit <= 0:
        maxit = 3 * len(maps)

    if endmember_n > len(maps) + 1:
        gs.warning('More endmembers ({}) requested than bands in \
                   input imagery group ({})'.format(endmember_n, len(maps)))
        if extraction_method != 'PPI':
            gs.fatal('Only PPI method can extract more endmembers than number \
                     of bands in the imagery group')

    if not atgp_init and extraction_method != 'NFINDR':
        gs.verbose('ATGP is only taken into account in \
                   NFINDR extraction method...')

    # Get metainformation from input bands
    band_types = {}
    img = None
    n = 0
    gs.verbose('Reading imagery group...')
    for m in maps:
        map = m.split('@')

        # Build numpy stack from imagery group
        raster = r.raster2numpy(map[0], mapset=map[1])
        if raster == np.float64:
            raster = float32(raster)
            gs.warning('{} is of type Float64.\
                        Float64 is currently not supported.\
                        Reducing precision to Float32'.format(raster))

        # Determine map type
        band_types[map[0]] = get_rastertype(raster)

        # Create cube and mask from GRASS internal NoData value
        if n == 0:
            img = raster
            # Create mask from GRASS internal NoData value
            mask = mask_rasternd(raster)
        else:
            img = np.dstack((img, raster))
            mask = np.logical_and((mask_rasternd(raster)), mask)

        n = n + 1

    # Read a mask if present and give waringing if not
    # Note that otherwise NoData is read as values
    gs.verbose('Checking for MASK...')
    try:
        MASK = r.raster2numpy('MASK', mapset=getenv('MAPSET')) == 1
        mask = np.logical_and(MASK, mask)
        MASK = None
    except:
        pass

    if extraction_method == 'NFINDR':
    # Extract endmembers from valid pixels using NFINDR function from pysptools
        gs.verbose('Extracting endmembers using NFINDR...')
        nfindr = eea.NFINDR()
        E = nfindr.extract(img, endmember_n, maxit=maxit, normalize=False,
                           ATGP_init=atgp_init, mask=mask)
    elif extraction_method == 'PPI':
    # Extract endmembers from valid pixels using PPI function from pysptools
        gs.verbose('Extracting endmembers using PPI...')
        ppi = eea.PPI()
        E = ppi.extract(img, endmember_n, numSkewers=10000, normalize=False,
                        mask=mask)
    elif extraction_method == 'FIPPI':
    # Extract endmembers from valid pixels using FIPPI function from pysptools
        gs.verbose('Extracting endmembers using FIPPI...')
        fippi = eea.FIPPI()
        # q and maxit can be None according to manual, but does not work
        """if not maxit and not endmember_n:
            E = fippi.extract(img, q=None, normalize=False, mask=mask)
        if not maxit:
            E = fippi.extract(img, q=endmember_n, normalize=False, mask=mask)
        if not endmember_n:
            E = fippi.extract(img, q=int(), maxit=maxit, normalize=False,
                              mask=mask)
        else:
            E = fippi.extract(img, q=endmember_n, maxit=maxit, normalize=False,
                              mask=mask)"""
        E = fippi.extract(img, q=endmember_n, maxit=maxit, normalize=False,
                          mask=mask)

    # Write output file in format required for i.spec.unmix addon
    if output:
        gs.verbose('Writing spectra file...')
        n = 0
        with open(output, 'w') as o:
            o.write('# Channels: {}\n'.format('\t'.join(band_types.keys())))
            o.write('# Wrote {} spectra line wise.\n#\n'.format(endmember_n))
            o.write('Matrix: {0} by {1}\n'.format(endmember_n, len(maps)))
            for e in E:
                o.write('row{0}: {1}\n'.format(n, '\t'.join([str(i) for i in  e])))
                n = n + 1

    # Write vector map with endmember information if requested
    if endmembers:
        gs.verbose('Writing vector map with endmembers...')
        from grass.pygrass import utils as u
        from grass.pygrass.gis.region import Region
        from grass.pygrass.vector import Vector
        from grass.pygrass.vector import VectorTopo
        from grass.pygrass.vector.geometry import Point

        # Build attribute table
        # Deinfe columns for attribute table
        cols = [(u'cat',       'INTEGER PRIMARY KEY')]
        for b in band_types.keys():
            cols.append((b.replace('.','_'), band_types[b]))
        
        # Get region information
        reg = Region()

        # Create vector map
        new = Vector(endmembers)
        new.open('w', tab_name=endmembers, tab_cols=cols)

        cat = 1
        for e in E:
            # Get indices
            idx = np.where((img[:,:]==e).all(-1))

            # Numpy array is ordered rows, columns (y,x)
            if len(idx[0]) == 0 or len(idx[1]) == 0:
                gs.warning('Could not compute coordinated for endmember {}. \
                            Please consider rescaling your data to integer'.format(cat))
                cat = cat + 1
                continue

            coords = u.pixel2coor((idx[1][0], idx[0][0]), reg)
            point = Point(coords[1] + reg.ewres / 2.0,
                          coords[0] - reg.nsres / 2.0)

            # Get attributes
            n = 0
            attr = []
            for b in band_types.keys():
                if band_types[b] == u'INTEGER':
                    attr.append(int(e[n]))
                else:
                    attr.append(float(e[n]))
                n = n + 1

            # Write geometry with attributes
            new.write(point, cat=cat,
                      attrs=tuple(attr))
            cat = cat + 1

        # Close vector map
        new.table.conn.commit()
        new.close(build=True)

    if prefix:
        # Run spectral unmixing
        import pysptools.abundance_maps as amaps
        if unmixing_method == 'FCLS':
            fcls = amaps.FCLS()
            result = fcls.map(img, E, normalize=False, mask=mask)
        elif unmixing_method == 'NNLS':
            nnls = amaps.NNLS()
            result = nnls.map(img, E, normalize=False, mask=mask)
        elif unmixing_method == 'UCLS':
            ucls = amaps.UCLS()
            result = ucls.map(img, E, normalize=False, mask=mask)

        # Write results
        for l in range(endmember_n):
            rastname = '{0}_{1}'.format(prefix, l + 1)
            r.numpy2raster(result[:,:,l], 'FCELL', rastname)
Beispiel #2
0
def calcPhotoPol(row, col, reg, max_distance, elevation, lights,
                 obs_elevation):
    y, x = pixel2coor(
        (col, row), reg
    )  # (col, row) = pixel, https://grass.osgeo.org/grass70/manuals/libpython/_modules/pygrass/utils.html#pixel2coor

    try:

        y = y - float(
            Region().nsres
        ) / 2  #pixel2coor returns upper left px coordinates, reposition observer at the centre of pixel
        x = x + float(Region().ewres) / 2

        script.use_temp_region()
        script.run_command('g.region',
                           n=y + max_distance,
                           s=y - max_distance,
                           e=x + max_distance,
                           w=x - max_distance,
                           align=elevation)

        script.run_command('r.viewshed',
                           input=elevation,
                           output=tmp_rviewshed,
                           coordinates=(x, y),
                           max_distance=max_distance,
                           observer_elevation=obs_elevation,
                           overwrite=True,
                           flags='b')

        script.del_temp_region()

        # set region to viewshed
        script.run_command("r.null", map=tmp_rviewshed, setnull=0)
        script.use_temp_region()
        script.run_command("g.region",
                           raster=tmp_rviewshed,
                           zoom=tmp_rviewshed)

        # generate a new raster with NA in observer cell
        script.write_command(
            "v.in.ascii",
            input="-",
            output=tmp_observer,
            stdin="{}|{}".format(x, y),
            overwrite=True
        )  #https://grass.osgeo.org/grass70/manuals/libpython/script.html#script.core.write_command

        script.run_command("v.to.rast",
                           input=tmp_observer,
                           output=tmp_robserver,
                           use="cat",
                           overwrite=True)

        script.run_command(
            "r.mapcalc",
            expression="\"{}\" = if(isnull (\"{}\"), 1, null ())".format(
                tmp_rcalc, tmp_robserver),
            overwrite=True)

        #use tmp_rcalc raster as input in r.grow.distance to calculate distance from observer to other cells
        script.run_command("r.grow.distance",
                           flags="n",
                           input=tmp_rcalc,
                           distance=tmp_rdist_dis,
                           value="rdist.value",
                           overwrite=True)

        # keep only cells that match viewshed analysis
        script.run_command("r.mask",
                           raster=tmp_rviewshed,
                           maskcats="1",
                           overwrite=True)

        # calculate DN/distance
        script.run_command("r.mapcalc",
                           expression="\"{}\" = \"{}\" / \"{}\"".format(
                               tmp_photopol, tmp_res_lights, tmp_rdist_dis),
                           overwrite=True)

        process = script.parse_command("r.univar", map=tmp_photopol, flags='g')

        index_for_pixel = float(process[u'sum'])
        lights_DN = float(lights.get_value(Point(x, y),
                                           reg))  #get night lights value

    except:
        #in case of error, set pixel value to -999
        index_for_pixel = -999
        lights_DN = 0
        script.warning("Calculation failed for row:{},col:{}".format(row, col))

    finally:
        script.run_command("r.mask", flags="r")  # remove any mask
        result = index_for_pixel + lights_DN
        script.del_temp_region()
        return (result)
def vect(stream_in_name, stream_out_name,
         direction_in_name, accumulation_in_name, distance_in_name):
    '''Builds vector map from stream raster map.'''

    # Instantiate maps
    print "Fetching maps..."
    stream_in       = RasterRowIO(stream_in_name)
    direction_in    = RasterSegment(direction_in_name)
    accumulation_in = RasterSegment(accumulation_in_name)
    distance_in     = RasterSegment(distance_in_name)

    # Initialize output
    stream_out      = VectorTopo(stream_out_name)
    # Define the new vector map attribute table columns
    columns = [(u"cat", "INTEGER PRIMARY KEY"),
               (u"fid", "INTEGER"),
               (u"accum", "DOUBLE"),
               (u"dist", "DOUBLE"),
               (u"source_i", "INTEGER"),
               (u"source_j", "INTEGER"),
               (u"target_i", "INTEGER"),
               (u"target_j", "INTEGER")]
    print "Opening output..."
    stream_out.open('w', tab_name = stream_out_name, tab_cols = columns)

    # Open maps
    print "Loading maps..."
    stream_in.open('r')
    direction_in.open(mode = 'r')
    accumulation_in.open(mode = 'r')
    distance_in.open(mode = 'r')

    # Get the current region to compute coordinates
    region = Region()
    x_shift = region.ewres*.5
    y_shift = region.nsres*.5*(-1.0)


    print "Processing..."
    # For each stream cell...
    i = 0
    for row in stream_in:

        j = 0
        for cell in row:

            if cell < 0:
                j += 1
                continue

            # Retrieve data (direction, accumulation and distance)
            direction    = direction_in[i, j]
            accumulation = accumulation_in[i, j]
            distance     = distance_in[i, j]

            # Get i and j shifts from direction
            (di, dj) = shift[direction]

            # Compute unit vector start and end geo coordinates
            (source_y, source_x) = pixel2coor((j,      i),      region)
            (target_y, target_x) = pixel2coor((j + dj, i + di), region)

            # Build unit vector
            stream_out.write(Line([(source_x + x_shift, source_y + y_shift),
                                   (target_x + x_shift, target_y + y_shift)]),
                             (cell, accumulation, distance, i, j, i + di, j + dj)
                             )

            j += 1

        i += 1

    # Commit database changes
    stream_out.table.conn.commit()

    # Close maps
    stream_in.close()
    direction_in.close()
    accumulation_in.close()
    stream_out.close()