Пример #1
0
 def reflectance(self):
     """
     Reflectance (0 .. 1) derived from DN and metadata, as numpy array
     """
     if not self.meta:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata for band. " +
             "No reflectance calculation possible.")
     if self.spacecraft == 'L8':
         self.gain = self.meta['RADIOMETRIC_RESCALING'][
             'REFLECTANCE_MULT_BAND_%s' % self.band]
         self.bias = self.meta['RADIOMETRIC_RESCALING'][
             'REFLECTANCE_ADD_BAND_%s' % self.band]
         sedeg = self.meta['IMAGE_ATTRIBUTES']['SUN_ELEVATION']
         rawrad = ir.dn2rad(self.data, self.gain, self.bias)
         return rawrad / (np.sin(sedeg * np.pi / 180))
     elif self.spacecraft in ['L5', 'L7']:
         if self.newmetaformat:
             sedeg = self.meta['IMAGE_ATTRIBUTES']['SUN_ELEVATION']
             dac = self.meta['PRODUCT_METADATA']['DATE_ACQUIRED']
         else:
             sedeg = self.meta['PRODUCT_PARAMETERS']['SUN_ELEVATION']
             dac = self.meta['PRODUCT_METADATA']['ACQUISITION_DATE']
         juliandac = int(datetime.date.strftime(dac, '%j'))
         d = lu.getd(juliandac)
         esun = lu.getesun(self.spacecraft, self.band)
         rad = self.radiance
         return (np.pi * d * d * rad) / (esun * np.sin(sedeg * np.pi / 180))
     else:
         return None
Пример #2
0
    def xy2ij(self, x, y, precise=False):
        """
        Convert easting/northing coordinate pair(s) to array coordinate
        pairs(s).

        NOTE: see note at ij2xy()

        Arguments:
            x (float): scalar or array of easting coordinates
            y (float): scalar or array of northing coordinates
            precise (bool): if true, return fractional array coordinates

        Returns:
            i (int, or float): scalar or array of row coordinate index
            j (int, or float): scalar or array of column coordinate index
        """
        if (rh._test_outside(x, self.easting[0], self.easting[-1])
                or rh._test_outside(y, self.northing[0], self.northing[-1])):
            raise PygaarstRasterError("Coordinates out of bounds")
        i = (1 - (y - self.northing[0]) /
             (self.northing[-1] - self.northing[0])) * self.nrow
        j = ((x - self.easting[0]) /
             (self.easting[-1] - self.easting[0])) * self.ncol
        if precise:
            return i, j
        else:
            return int(np.floor(i)), int(np.floor(j))
Пример #3
0
    def ij2xy(self, i, j):
        """
        Converts array index pair(s) to easting/northing coordinate pairs(s).

        NOTE: array coordinate origin is in the top left corner whereas
        easting/northing origin is in the bottom left corner. Easting and
        northing are floating point numbers, and refer to the top-left corner
        coordinate of the pixel. i runs from 0 to nrow-1, j from 0 to ncol-1.
        For i=nrow and j=ncol, the bottom-right corner coordinate of the
        bottom-right pixel will be returned. This is identical to the bottom-
        right corner.

        Arguments:
            i (int): scalar or array of row coordinate index
            j (int): scalar or array of column coordinate index

        Returns:
            x (float): scalar or array of easting coordinates
            y (float): scalar or array of northing coordinates
        """
        if (rh._test_outside(i, 0, self.nrow)
                or rh._test_outside(j, 0, self.ncol)):
            raise PygaarstRasterError("Coordinates %d, %d out of bounds" %
                                      (i, j))
        x = self.easting[0] + j * self.delx
        y = self.northing[-1] + i * self.dely
        return x, y
Пример #4
0
    def __getattr__(self, bandname):
        """
        Override _gettattr__() for bandnames of the form bandN with N in the
        bands permissible for Ali.

        (See https://eo1.usgs.gov/sensors/hyperioncoverage).
        Warn if band is non-calibrated.
        Allows for infixing the filename just before the .TIF extension for
        pre-processed bands.
        """
        # see https://eo1.usgs.gov/sensors/hyperioncoverage
        isband = False
        head, _, tail = bandname.lower().partition('band')
        try:
            band = tail.upper()
            if head == '':
                if band in self.permissiblebandid:
                    isband = True
                else:
                    raise PygaarstRasterError(
                        "EO-1 ALI does not have a band %s. " +
                        "Permissible band labels are between 1 and 10.")
        except ValueError:
            pass
        if isband:
            # Note: Landsat 7 has low and high gain bands 6,
            # with different label names
            keyname = "BAND%s_FILE_NAME" % band
            bandfn = self.meta['PRODUCT_METADATA'][keyname]
            base, ext = os.path.splitext(bandfn)
            postprocessfn = base + self.infix + ext
            bandpath = os.path.join(self.dirname, postprocessfn)
            self.bands[band] = ALIband(bandpath, band=band, scene=self)
            return self.bands[band]
        return object.__getattribute__(self, bandname)
Пример #5
0
 def geodata(self):
     """Object representing the georeference data, in its entirety"""
     if self.geofilepath:
         geodat = h5py.File(self.geofilepath, "r")
         if not geodat:
             raise PygaarstRasterError(
                 "Unable to open georeference file %s." % self.geofilepath)
         self.geogroupkey = geodat['All_Data'].keys()[0]
         return geodat['All_Data/%s' % self.geogroupkey]
     elif self.GEO:
         # It could be an aggregated multi-band VIIRS file
         # with embedded georeferences
         return self.GEO
     else:
         raise PygaarstRasterError(
             "Unable to find georeference information for %s." %
             self.filepath)
     return geodat
Пример #6
0
 def radiance(self):
     """Radiance in W / um / m^2 / sr derived from digital number
     and metadata, as numpy array"""
     if not self.meta:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata for band. " +
             "No radiance calculation possible.")
     self.gain = self.meta[
         'RADIANCE_SCALING']['BAND%s_SCALING_FACTOR' % self.band]
     self.bias = self.meta['RADIANCE_SCALING']['BAND%s_OFFSET' % self.band]
     return ir.dn2rad(self.data, self.gain, self.bias)
Пример #7
0
 def geodata(self):
     """Object representing the georeference data, in its entirety"""
     geodat = None
     if self.geofilepath:
         # TODO
         pass
     else:
         raise PygaarstRasterError(
             "Unable to find georeference information for %s." %
             self.filepath)
     return geodat
Пример #8
0
def _latlonmetric(latarray, latref, lonarray, lonref):
    """Takes two numpy arrays of longitudes and latitudes and returns an
    array of the same shape of metrics representing distance for short distances"""
    if latarray.shape != latarray.shape:
        #arrays aren't the same shape
        raise PygaarstRasterError(
            "Latitude and longitude arrays have to be the same shape for " +
            "distance comparisons.")
    return np.sqrt(
        np.square(latarray - latref) +
        np.cos(np.radians(latarray)) * np.square(lonarray - lonref))
Пример #9
0
 def reflectance(self):
     """
     Reflectance (0 .. 1) derived from DN and metadata, as numpy array
     """
     if not self.meta:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata for band. " +
             "No reflectance calculation possible.")
     elif self.sensor == 'HYPERION':
         dac = dt.datetime.strptime(
             self.meta['PRODUCT_METADATA']['START_TIME'], '%Y %j %H:%M:%S')
         sedeg = self.meta['PRODUCT_PARAMETERS']['SUN_ELEVATION']
         juliandac = int(dt.date.strftime(dac, '%j'))
         d = lu.getd(juliandac)
         esun = hyp.getesun(self.band)
         rad = self.radiance
         return ((np.pi * d * d * rad) /
                 (esun * np.sin(sedeg * np.pi / 180)))
     else:
         raise PygaarstRasterError(
             "Unkown sensor {} on spacecraft {}.".format(
                 self.sensor, self.spacecraft))
Пример #10
0
 def __init__(self, dirname):
     self.dirname = dirname
     self.infix = ''
     metadata = mtl.parsemeta(dirname)
     try:
         self.meta = metadata['L1_METADATA_FILE']
     except KeyError:
         raise PygaarstRasterError("Metadata from %s could not be read. " %
                                   dirname + " Please check your dataset.")
     self.spacecraft = _get_spacecraftid(
         self.meta['PRODUCT_METADATA']['SPACECRAFT_ID'])
     self.sensor = self.meta['PRODUCT_METADATA']['SENSOR_ID']
     self.bands = {}
Пример #11
0
 def __init__(self, filepath):
     try:
         #LOGGER.info("Opening %s" % filepath)
         self.dataobj = pyhdf.SD.SD(filepath)
         self.filepath = filepath
         self.dirname = os.path.dirname(filepath)
         self.rawmetadata = self.dataobj.attributes()
     except IOError as err:
         LOGGER.error("Could not open %s: %s" % (filepath, err.message))
         raise
     if not self.dataobj:
         raise PygaarstRasterError(
             "Could not read data from %s as HDF4 file." % filepath)
Пример #12
0
 def radiance(self):
     """Radiance in W / um / m^2 / sr derived from digital number and
     metadata, as numpy array"""
     if not self.meta:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata " +
             "for band. No radiance calculation possible.")
     if int(self.band) <= 70:
         rad = self.data / self.meta['RADIANCE_SCALING'][
             'SCALING_FACTOR_VNIR']
     else:
         rad = self.data / self.meta['RADIANCE_SCALING'][
             'SCALING_FACTOR_SWIR']
     return rad.astype('float32')
Пример #13
0
 def __init__(self, filepath):
     try:
         self.filepath = filepath
         self.dirname = os.path.dirname(filepath)
         # We'll want, possibly, metadata from the user block, for which
         # the HDF5 obj needs to be closed, but we first need the
         # userblock length. Thus some odd rigamarole...
         self.dataobj = h5py.File(filepath, "r")
         if self.dataobj.userblock_size != 0:
             self.userblock_size = self.dataobj.userblock_size
             self.dataobj.close()
             with open(self.filepath, 'rb') as source:
                 self.userblock = source.read(self.userblock_size)
             self.dataobj = h5py.File(filepath, "r")
     except IOError as err:
         LOGGER.error("Could not open %s: %s" % (filepath, err.message))
         raise
     if not self.dataobj:
         raise PygaarstRasterError(
             "Could not read data from %s as HDF5 file." % filepath)
Пример #14
0
 def tKelvin(self):
     """Radiant (brightness) temperature at the sensor in K,
     implemented for Landsat thermal infrared bands."""
     if not self.scene:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata for band. " +
             "No radiance calculation possible.")
     if ((self.spacecraft == 'L8' and self.band not in ['10', '11']) or
         (self.spacecraft != 'L8' and not self.band.startswith('6'))):
         LOGGER.warning("Automatic brightness Temp not implemented. " +
                        "Cannot calculate temperature. Sorry.")
         return None
     elif self.spacecraft == 'L8':
         self.k1 = self.meta['TIRS_THERMAL_CONSTANTS']['K1_CONSTANT_BAND_%s'
                                                       % self.band]
         self.k2 = self.meta['TIRS_THERMAL_CONSTANTS']['K2_CONSTANT_BAND_%s'
                                                       % self.band]
     elif self.spacecraft in ['L4', 'L5', 'L7']:
         self.k1, self.k2 = lu.getKconstants(self.spacecraft)
     return ir.rad2kelvin(self.radiance, self.k1, self.k2)
Пример #15
0
 def __getattr__(self, bandname):
     """
     Overrides _gettattr__() for bandnames bandN with N in l.LANDSATBANDS.
     Allows for infixing the filename just before the .TIF extension for
     pre-processed bands.
     """
     isband = False
     head, sep, tail = bandname.lower().partition('band')
     try:
         band = tail.upper()
         if head == '':
             if band in self.permissiblebandid:
                 isband = True
             else:
                 raise PygaarstRasterError(
                     "Spacecraft %s " % self.spacecraft +
                     "does not have a band %s. " % band +
                     "Permissible band labels are %s." %
                     ', '.join(self.permissiblebandid))
     except ValueError:
         pass
     if isband:
         # Note: Landsat 7 has low and high gain bands 6,
         # with different label names
         if self.newmetaformat:
             bandstr = band.replace('L', '_VCID_1').replace('H', '_VCID_2')
             keyname = "FILE_NAME_BAND_%s" % bandstr
         else:
             bandstr = band.replace('L', '1').replace('H', '2')
             keyname = "BAND%s_FILE_NAME" % bandstr
         bandfn = self.meta['PRODUCT_METADATA'][keyname]
         base, ext = os.path.splitext(bandfn)
         postprocessfn = base + self.infix + ext
         bandpath = os.path.join(self.dirname, postprocessfn)
         self.bands[band] = Landsatband(bandpath, band=band, scene=self)
         return self.bands[band]
     else:
         return object.__getattribute__(self, bandname)
Пример #16
0
    def __getattr__(self, bandname):
        """
        Override _gettattr__() for bandnames bandN with N in the bands
        permissible for Hyperion

        (See https://eo1.usgs.gov/sensors/hyperioncoverage).
        Warn if band is a non-calibrated one.
        Allows for infixing the filename just before the .TIF extension for
        pre-processed bands.
        """
        # see https://eo1.usgs.gov/sensors/hyperioncoverage
        isband = False
        head, sep, tail = bandname.lower().partition('band')
        try:
            band = tail.upper()
            if head == '':
                if band in self.permissiblebandid:
                    isband = True
                    if band not in self.calibratedbandid:
                        LOGGER.warning('Hyperion band %s is not calibrated.' %
                                       band)
                else:
                    raise PygaarstRasterError(
                        "EO-1 Hyperion does not have a band %s. " % band +
                        "Permissible band labels are between 1 and 242.")
        except ValueError:
            pass
        if isband:
            keyname = "BAND%s_FILE_NAME" % band
            bandfn = self.meta['PRODUCT_METADATA'][keyname]
            base, ext = os.path.splitext(bandfn)
            postprocessfn = base + self.infix + ext
            bandpath = os.path.join(self.dirname, postprocessfn)
            self.bands[band] = Hyperionband(bandpath, band=band, scene=self)
            return self.bands[band]
        else:
            return object.__getattribute__(self, bandname)
Пример #17
0
 def radiance(self):
     """
     Radiance in W/um/m^2/sr derived from DN and metadata, as numpy array
     """
     if not self.meta:
         raise PygaarstRasterError(
             "Impossible to retrieve metadata for band. " +
             "No radiance calculation possible.")
     if self.spacecraft == 'L8':
         self.gain = self.meta['RADIOMETRIC_RESCALING'][
             'RADIANCE_MULT_BAND_%s' % self.band]
         self.bias = self.meta['RADIOMETRIC_RESCALING'][
             'RADIANCE_ADD_BAND_%s' % self.band]
         return ir.dn2rad(self.data, self.gain, self.bias)
     elif self.newmetaformat:
         bandstr = self.band.replace('L', '_VCID_1').replace('H', '_VCID_2')
         lmax = self.meta['MIN_MAX_RADIANCE']['RADIANCE_MAXIMUM_BAND_%s' %
                                              bandstr]
         lmin = self.meta['MIN_MAX_RADIANCE']['RADIANCE_MINIMUM_BAND_%s' %
                                              bandstr]
         qcalmax = self.meta['MIN_MAX_PIXEL_VALUE'][
             'QUANTIZE_CAL_MAX_BAND_%s' % bandstr]
         qcalmin = self.meta['MIN_MAX_PIXEL_VALUE'][
             'QUANTIZE_CAL_MIN_BAND_%s' % bandstr]
         gain, bias = ir.gainbias(lmax, lmin, qcalmax, qcalmin)
         return ir.dn2rad(self.data, gain, bias)
     else:
         bandstr = self.band.replace('L', '1').replace('H', '2')
         lmax = self.meta['MIN_MAX_RADIANCE']['LMAX_BAND%s' % bandstr]
         lmin = self.meta['MIN_MAX_RADIANCE']['LMIN_BAND%s' % bandstr]
         qcalmax = self.meta['MIN_MAX_PIXEL_VALUE']['QCALMAX_BAND%s' %
                                                    bandstr]
         qcalmin = self.meta['MIN_MAX_PIXEL_VALUE']['QCALMIN_BAND%s' %
                                                    bandstr]
         gain, bias = ir.gainbias(lmax, lmin, qcalmax, qcalmin)
         return ir.dn2rad(self.data, gain, bias)
     return None
Пример #18
0
    def spectrum(self, i_idx, j_idx, bands='calibrated', bdsel=[]):
        """
        Calculates the radiance spectrum for one pixel.

        Arguments:
          i_idx (int): first coordinate index of the pixel
          j_idx (int): second coordinate index of the pixel
          bands (str): indicates the bands that are used
            'calibrated' (default): only use calibrated bands
            'high': use uncalibrated bands 225-242
            'low': use uncalibrated bands 1-7
            'all': use all available bands
            'selected': use bdsel attribute or argument
          bdsel: sequence data type containing band indices to select
        """
        rads = []
        if bands == 'calibrated':
            bnd = self.hyperionbands[self.band_is_calibrated]
        elif bands == 'selected':
            bnd = self.hyperionbands[bdsel]
            if bnd.size == 0 and self.bandselection:
                bnd = self.hyperionbands[self.bandselection]
        elif bands == 'all':
            bnd = self.hyperionbands
        elif bands == 'high':
            bnd = self.hyperionbands[224:]
        elif bands == 'low':
            bnd = self.hyperionbands[:7]
        else:
            raise PygaarstRasterError("Unrecognized argument %s for bands " %
                                      bands + "in raser.HyperionScene.")
        for band in bnd:
            rad = self.__getattr__(band).radiance
            rads.append(rad[i_idx, j_idx])
        del rad
        return rads
Пример #19
0
    def clone(self, newpath, newdata):
        """
        Creates new GeoTIFF object from existing: new data, same georeference.

        Arguments:
            newpath: valid file path
            newdata: numpy array, 2 or 3-dim

        Returns:
            A raster.GeoTIFF object
        """
        # convert Numpy dtype objects to GDAL type codes
        # see https://gist.github.com/chryss/8366492

        NPDTYPE2GDALTYPECODE = {
            "uint8": 1,
            "int8": 1,
            "uint16": 2,
            "int16": 3,
            "uint32": 4,
            "int32": 5,
            "float32": 6,
            "float64": 7,
            "complex64": 10,
            "complex128": 11,
        }
        # check if newpath is potentially a valid file path to save data
        dirname, fname = os.path.split(newpath)
        if dirname:
            if not os.path.isdir(dirname):
                raise PygaarstRasterError(
                    "%s is not a valid directory to save file to " % dirname)
        if os.path.isdir(newpath):
            LOGGER.warning("%s is a directory." % dirname + " Choose a name " +
                           "that is suitable for writing a dataset to.")
        if (newdata.shape != self.data.shape
                and newdata.shape != self.data[0, ...].shape):
            raise PygaarstRasterError(
                "New and cloned GeoTIFF dataset must be the same shape.")
        dims = newdata.ndim
        if dims == 2:
            bands = 1
        elif dims > 2:
            bands = newdata.shape[0]
        else:
            raise PygaarstRasterError(
                "New data array has only %s dimensions." % dims)
        try:
            LOGGER.info(newdata.dtype.name)
            LOGGER.info(NPDTYPE2GDALTYPECODE)
            LOGGER.info(NPDTYPE2GDALTYPECODE[newdata.dtype.name])
            gdaltype = NPDTYPE2GDALTYPECODE[newdata.dtype.name]
        except KeyError as err:
            raise PygaarstRasterError(
                "Data type in array %s " % newdata.dtype.name +
                "cannot be converted to GDAL data type: \n%s" % err.message)
        proj = self.projection
        geotrans = self._gtr
        gtiffdr = gdal.GetDriverByName('GTiff')
        gtiff = gtiffdr.Create(newpath, self.ncol, self.nrow, bands, gdaltype)
        gtiff.SetProjection(proj)
        gtiff.SetGeoTransform(geotrans)
        if dims == 2:
            gtiff.GetRasterBand(1).WriteArray(newdata)
        else:
            for idx in range(dims):
                gtiff.GetRasterBand(idx + 1).WriteArray(newdata[idx, :, :])
        gtiff = None
        return GeoTIFF(newpath)