Exemple #1
2
    def test_6s_example1(self):
        # Implements Example_In_1.txt from the 6S distribution in Py6S
        # Tests against manual run of that file

        s = SixS()
        s.geometry = Geometry.User()
        s.geometry.solar_z = 40
        s.geometry.solar_a = 100
        s.geometry.view_z = 45
        s.geometry.view_a = 50
        s.geometry.month = 7
        s.geometry.day = 23

        s.atmos_profile = AtmosProfile.UserWaterAndOzone(3.0, 3.5)
        s.aero_profile = AeroProfile.User(dust=0.25,
                                          water=0.25,
                                          oceanic=0.25,
                                          soot=0.25)

        s.aot550 = 0.5
        s.altitudes.set_target_custom_altitude(0.2)
        s.altitudes.set_sensor_custom_altitude(3.3, aot=0.25)
        s.wavelength = Wavelength(PredefinedWavelengths.AVHRR_NOAA9_B1)

        s.ground_reflectance = GroundReflectance.HeterogeneousLambertian(
            0.5, GroundReflectance.ClearWater,
            GroundReflectance.GreenVegetation)

        s.atmos_corr = AtmosCorr.AtmosCorrBRDFFromReflectance(0.1)
        s.run()
        self.assertAlmostEqual(s.outputs.apparent_radiance,
                               12.749,
                               delta=0.002)
Exemple #2
0
    def test_atmos_profile(self):
        aps = [
            AtmosProfile.Tropical,
            AtmosProfile.NoGaseousAbsorption,
            AtmosProfile.UserWaterAndOzone(0.9, 3),
        ]
        results = [0.2723143, 0.2747224, 0.2476101]

        for i in range(len(aps)):
            s = SixS()
            s.atmos_profile = aps[i]
            s.run()

            self.assertAlmostEqual(
                s.outputs.apparent_reflectance,
                results[i],
                msg="Error in atmos profile with ID %s. Got %f, expected %f." %
                (str(aps[i]), s.outputs.apparent_reflectance, results[i]),
                delta=0.002,
            )
Exemple #3
0
    def test_6s_example4(self):
        s = SixS()

        s.geometry = Geometry.User()
        s.geometry.solar_z = 61.23
        s.geometry.solar_a = 18.78
        s.geometry.solar_a = 0
        s.geometry.view_z = 18.78
        s.geometry.view_a = 159.2
        s.geometry.month = 4
        s.geometry.day = 30

        s.atmos_profile = AtmosProfile.UserWaterAndOzone(0.29, 0.41)
        s.aero_profile = AeroProfile.PredefinedType(AeroProfile.Continental)

        s.aot550 = 0.14

        s.altitudes.set_target_sea_level()
        s.altitudes.set_sensor_satellite_level()

        s.wavelength = Wavelength(PredefinedWavelengths.AVHRR_NOAA11_B1)

        s.ground_reflectance = GroundReflectance.HomogeneousLambertian([
            0.827,
            0.828,
            0.828,
            0.827,
            0.827,
            0.827,
            0.827,
            0.826,
            0.826,
            0.826,
            0.826,
            0.825,
            0.826,
            0.826,
            0.827,
            0.827,
            0.827,
            0.827,
            0.828,
            0.828,
            0.828,
            0.829,
            0.829,
            0.828,
            0.826,
            0.826,
            0.825,
            0.826,
            0.826,
            0.826,
            0.827,
            0.827,
            0.827,
            0.826,
            0.825,
            0.826,
            0.828,
            0.829,
            0.830,
            0.831,
            0.833,
            0.834,
            0.835,
            0.836,
            0.836,
            0.837,
            0.838,
            0.838,
            0.837,
            0.836,
            0.837,
            0.837,
            0.837,
            0.840,
            0.839,
            0.840,
            0.840,
            0.841,
            0.841,
            0.841,
            0.841,
            0.842,
            0.842,
            0.842,
            0.842,
            0.843,
            0.842,
            0.843,
            0.843,
            0.843,
            0.843,
            0.843,
            0.843,
            0.841,
            0.841,
            0.842,
            0.842,
            0.842,
            0.842,
            0.842,
            0.841,
            0.840,
            0.841,
            0.838,
            0.839,
            0.837,
            0.837,
            0.836,
            0.832,
            0.832,
            0.830,
            0.829,
            0.826,
            0.826,
            0.824,
            0.821,
            0.821,
            0.818,
            0.815,
            0.813,
            0.812,
            0.811,
            0.810,
            0.808,
            0.807,
            0.807,
            0.812,
            0.808,
            0.806,
            0.807,
            0.807,
            0.807,
            0.807,
        ])

        s.run()

        self.assertAlmostEqual(s.outputs.apparent_radiance,
                               170.771,
                               delta=0.002)
Exemple #4
0
    def run_py6s(self, geom, acqui_date, option=1):
        """
        runs the 6S algorithm for atmospheric correction on a user-defined
        geometry and date on Sentinel-2 imagery
        Requires Google Earth-Engine Python API client

        Parameters
        ----------
        geom : EE-Geometry
            Google EE geometry specify the geographic extent to be processed
        acqui_date : String
            date (YYYY-MM-dd) of the desired scene to be processed
        option : Integer
            for computing the cloud mask the user can decide whether the
            ESA delivered quality layer should be used for cloud masking
            (option=1) or an alternative approach originally developed for
            Landsat TM (option=2) should be used (Def=1)

        Returns
        -------
        s2_surf : ee.image.Image
            Google EE image instance with surface reflectance values
            and two additional bands containing Clouds ('CloudMask') and
            detected cloud shadows ('CloudShadows')
        """
        date = ee.Date(acqui_date)
        # get the Sentinel-2 image at or immediately after the specified date
        self.S2 = ee.Image(
                ee.ImageCollection('COPERNICUS/S2')
                .filterBounds(geom)
                .filterDate(date,date.advance(3,'month'))
                .sort('system:time_start')
                .first()
                )
        # extract the relevant metadata for carrying out the atmospheric correction
        self.info = self.S2.getInfo()['properties']
        # get the solar zenith angle an the scene data
        self.scene_date = datetime.datetime.utcfromtimestamp(
                    self.info['system:time_start']/1000)
        self.solar_z = self.info['MEAN_SOLAR_ZENITH_ANGLE']
        # log the identifier of the processed scene
        scene_id = self.info.get('DATASTRIP_ID')
        self.__logger.info("Starting Processing scene '{}' using GEE and Py6S".format(
                scene_id))
        # get the atmospheric constituents
        # i.e water vapor (h2o), ozone (o3), aerosol optical thickness (aot)
        h2o = Atmospheric.water(geom, date).getInfo()
        o3 = Atmospheric.ozone(geom, date).getInfo()
        aot = Atmospheric.aerosol(geom, date).getInfo()
        # add this information to the info dictionary as this metadata could
        # be of interest afterwards
        self.info['WATER_VAPOUR'] = h2o
        self.info['OZONE'] = o3
        self.info['AOT'] = aot
        # get the average altitude of the region to be processed
        # for the Digital Elevation Model (DEM) the Shuttle Radar Topography
        # Mission (SRTM) is used (Version 4) as it covers most parts of the
        # Earth (90 arc-sec data is used)
        SRTM = ee.Image('CGIAR/SRTM90_V4')
        alt = SRTM.reduceRegion(reducer = ee.Reducer.mean(),
                                geometry = geom.centroid()).get('elevation').getInfo()
        message = "Atcorr-Metadata: Water-Vapor = {0}, Ozone = {1}, AOT = {2}, "\
                    " Average Altitude (m) = {3}".format(
                            h2o, o3, aot, alt)
        self.__logger.info(message)
        # Py6S uses units of kilometers
        km = alt/1000
        # mask out clouds and cirrus from the imagery using the cloud score
        # optionally
        # algorithm provided by Sam Murhpy under Apache 2.0 licence
        # see: https://github.com/samsammurphy/cloud-masking-sentinel2/blob/master/cloud-masking-sentinel2.ipynb
        # also converts the image values to top-of-atmosphere reflectance
        self.__logger.info('Calculating cloud and shadow mask')
        self.S2 = mask_clouds(self.S2, option=1)
        self.__logger.info('Finished calculating cloud and shadow mask')
        # create a 6S object from the Py6S class
        # Instantiate (use the explizit path to installation directory of the
        # 6S binary as otherwise there might be an error)
        s = SixS()
        # Atmospheric constituents
        s.atmos_profile = AtmosProfile.UserWaterAndOzone(h2o,o3)
        s.aero_profile = AeroProfile.Continental
        s.aot550 = aot
        # Earth-Sun-satellite geometry
        s.geometry = Geometry.User()
        s.geometry.view_z = 0                       # always NADIR (simplification!)
        s.geometry.solar_z = self.solar_z         # solar zenith angle
        s.geometry.month = self.scene_date.month  # month and day used for Earth-Sun distance
        s.geometry.day = self.scene_date.day      # month and day used for Earth-Sun distance
        s.altitudes.set_sensor_satellite_level()
        s.altitudes.set_target_custom_altitude(km)
        self.__logger.info('6S: Starting processing of Sentinel-2 scene!')
        # now iterate over the nine relevant Sentinel-2 bands to perform the
        # atmospheric correction and get the surface reflectance
        # go through the spectral bands
        B2_surf = self.surface_reflectance(s, 'B2')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 2!')
        B3_surf = self.surface_reflectance(s, 'B3')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 3!')
        B4_surf = self.surface_reflectance(s, 'B4')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 4!')
        B5_surf = self.surface_reflectance(s, 'B5')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 5!')
        B6_surf = self.surface_reflectance(s, 'B6')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 6!')
        B7_surf = self.surface_reflectance(s, 'B7')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 7!')
        B8A_surf = self.surface_reflectance(s, 'B8A')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 8A!')
        B11_surf = self.surface_reflectance(s, 'B11')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 11!')
        B12_surf = self.surface_reflectance(s, 'B12')
        self.__logger.info('6S: Finished processing Sentinel-2 Band 12!')
        self.__logger.info('6S: Finished processing of Sentinel-2 scene!')
        # make a stack of the spectral bands
        # also add the computed cloud and shadow mask
        cm = self.S2.select('CloudMask')
        sm = self.S2.select('ShadowMask')
        S2_surf = B2_surf.addBands(B3_surf).addBands(B4_surf).addBands(B5_surf).addBands(B6_surf).addBands(B7_surf).addBands(B8A_surf).addBands(B11_surf).addBands(B12_surf).addBands(cm).addBands(sm)

        # return the surface reflectance image
        close_logger(self.__logger)
        return S2_surf