def mod_ndwi_learned(domain, b):
    if domain.unflooded_domain == None:
        print "No unflooded training domain provided."
        return None
    unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
    water_mask = modis_utilities.get_permanent_water_mask()
    threshold = modis_utilities.compute_binary_threshold(get_mod_ndwi(unflooded_b), water_mask, domain.bounds)
    return mod_ndwi(domain, b, threshold)
예제 #2
0
def mod_ndwi_learned(domain, b):
    if domain.unflooded_domain == None:
        print 'No unflooded training domain provided.'
        return None
    unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
    water_mask  = modis_utilities.get_permanent_water_mask()
    threshold   = modis_utilities.compute_binary_threshold(get_mod_ndwi(unflooded_b), water_mask, domain.bounds)
    return mod_ndwi(domain, b, threshold)
def dart_learned(domain, b):
    """The dartmouth method but with threshold calculation included (training image required)"""
    if domain.unflooded_domain == None:
        print "No unflooded training domain provided."
        return None
    unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
    water_mask = modis_utilities.get_permanent_water_mask()
    threshold = modis_utilities.compute_binary_threshold(get_dartmouth(unflooded_b), water_mask, domain.bounds)
    return dartmouth(domain, b, threshold)
예제 #4
0
def dart_learned(domain, b):
    '''The dartmouth method but with threshold calculation included (training image required)'''
    if domain.unflooded_domain == None:
        print 'No unflooded training domain provided.'
        return None
    unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
    water_mask  = modis_utilities.get_permanent_water_mask()
    threshold   = modis_utilities.compute_binary_threshold(get_dartmouth(unflooded_b), water_mask, domain.bounds)
    return dartmouth(domain, b, threshold)
def diff_learned(domain, b):
    '''modis_diff but with the threshold calculation included (training image required)'''
    if domain.unflooded_domain == None:
        print 'No unflooded training domain provided.'
        return None
    unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
    water_mask  = modis_utilities.get_permanent_water_mask()
    
    threshold = modis_utilities.compute_binary_threshold(get_diff(unflooded_b), water_mask, domain.bounds)
    return modis_diff(domain, b, threshold)
예제 #6
0
def dnns(domain, b, use_modis_diff=False):
    '''Dynamic Nearest Neighbor Search adapted from the paper:
        "Li, Sun, Yu, et. al. "A new short-wave infrared (SWIR) method for
        quantitative water fraction derivation and evaluation with EOS/MODIS
        and Landsat/TM data." IEEE Transactions on Geoscience and Remote Sensing, 2013."
        
        The core idea of this algorithm is to compute local estimates of a "pure water"
        and "pure land" pixel and compute each pixel's water percentage as a mixed
        composition of those two pure spectral types.
    '''
    
    # This algorithm has some differences from the original paper implementation.
    #  The most signficant of these is that it does not make use of land/water/partial
    #  preclassifications like the original paper does.  The search range is also
    #  much smaller in order to make the algorithm run faster in Earth Engine.
    # - Running this with a tiny kernel (effectively treating the entire region
    #    as part of the kernel) might get the best results!

    # Parameters
    KERNEL_SIZE = 40 # The original paper used a 100x100 pixel box = 25,000 meters!
    
    AVERAGE_SCALE_METERS = 250 # This scale is used to compute averages over the entire region
    
    # Set up two square kernels of the same size
    # - These kernels define the search range for nearby pure water and land pixels
    kernel            = ee.Kernel.square(KERNEL_SIZE, 'pixels', False)
    kernel_normalized = ee.Kernel.square(KERNEL_SIZE, 'pixels', True)
    
    # Compute b1/b6 and b2/b6
    composite_image = b['b1'].addBands(b['b2']).addBands(b['b6'])
    
    # Use CART classifier to divide pixels up into water, land, and mixed.
    # - Mixed pixels are just low probability water/land pixels.
    if use_modis_diff:
        unflooded_b = modis_utilities.compute_modis_indices(domain.unflooded_domain)
        water_mask = get_permanent_water_mask()
        thresholds = modis_utilities.compute_binary_threshold(simple_modis_algorithms.get_diff(unflooded_b), water_mask, domain.bounds, True)

        pureWater  = simple_modis_algorithms.modis_diff(domain, b, thresholds[0])
        pureLand   = simple_modis_algorithms.modis_diff(domain, b, thresholds[1]).Not()
        mixed = pureWater.Or(pureLand).Not()
    else:
        classes   = ee_classifiers.earth_engine_classifier(domain, b, 'Pegasos', {'classifier_mode' : 'probability'})
        pureWater = classes.gte(0.95)
        pureLand  = classes.lte(0.05)
        #addToMap(classes, {'min': -1, 'max': 1}, 'CLASSES')
        #raise Exception('DEBUG')
        mixed     = pureWater.Not().And(pureLand.Not())
    averageWater      = safe_get_info(pureWater.mask(pureWater).multiply(composite_image).reduceRegion(ee.Reducer.mean(), domain.bounds, AVERAGE_SCALE_METERS))
    averageWaterImage = ee.Image([averageWater['sur_refl_b01'], averageWater['sur_refl_b02'], averageWater['sur_refl_b06']])
    
    # For each pixel, compute the number of nearby pure water pixels
    pureWaterCount = pureWater.convolve(kernel)
    # Get mean of nearby pure water (b1,b2,b6) values for each pixel with enough pure water nearby
    MIN_PUREWATER_NEARBY = 1
    pureWaterRef = pureWater.multiply(composite_image).convolve(kernel).multiply(pureWaterCount.gte(MIN_PUREWATER_NEARBY)).divide(pureWaterCount)
    # For pixels that did not have enough pure water nearby, just use the global average water value
    pureWaterRef = pureWaterRef.add(averageWaterImage.multiply(pureWaterRef.Not()))

   
    # Compute a backup, global pure land value to use when pixels have none nearby.
    averagePureLand      = safe_get_info(pureLand.mask(pureLand).multiply(composite_image).reduceRegion(ee.Reducer.mean(), domain.bounds, AVERAGE_SCALE_METERS))
    #averagePureLand      = composite_image.mask(pureLand).reduceRegion(ee.Reducer.mean(), domain.bounds, AVERAGE_SCALE_METERS)
    
    averagePureLandImage = ee.Image([averagePureLand['sur_refl_b01'], averagePureLand['sur_refl_b02'], averagePureLand['sur_refl_b06']])
    
    # Implement equations 10 and 11 from the paper --> It takes many lines of code to compute the local land pixels!
    oneOverSix   = b['b1'].divide(b['b6'])
    twoOverSix   = b['b2'].divide(b['b6'])
    eqTenLeft    = oneOverSix.subtract( pureWaterRef.select('sur_refl_b01').divide(b['b6']) )
    eqElevenLeft = twoOverSix.subtract( pureWaterRef.select('sur_refl_b02').divide(b['b6']) )
    
    # For each pixel, grab all the ratios from nearby pixels
    nearbyPixelsOneOverSix = oneOverSix.neighborhoodToBands(kernel) # Each of these images has one band per nearby pixel
    nearbyPixelsTwoOverSix = twoOverSix.neighborhoodToBands(kernel)
    nearbyPixelsOne        = b['b1'].neighborhoodToBands(kernel)
    nearbyPixelsTwo        = b['b2'].neighborhoodToBands(kernel)
    nearbyPixelsSix        = b['b6'].neighborhoodToBands(kernel)
    
    # Find which nearby pixels meet the EQ 10 and 11 criteria
    eqTenMatches        = ( nearbyPixelsOneOverSix.gt(eqTenLeft   ) ).And( nearbyPixelsOneOverSix.lt(oneOverSix) )
    eqElevenMatches     = ( nearbyPixelsTwoOverSix.gt(eqElevenLeft) ).And( nearbyPixelsTwoOverSix.lt(twoOverSix) )
    nearbyLandPixels    = eqTenMatches.And(eqElevenMatches)
    
    # Find the average of the nearby matching pixels
    numNearbyLandPixels = nearbyLandPixels.reduce(ee.Reducer.sum())
    meanNearbyBandOne   = nearbyPixelsOne.multiply(nearbyLandPixels).reduce(ee.Reducer.sum()).divide(numNearbyLandPixels)
    meanNearbyBandTwo   = nearbyPixelsTwo.multiply(nearbyLandPixels).reduce(ee.Reducer.sum()).divide(numNearbyLandPixels)
    meanNearbyBandSix   = nearbyPixelsSix.multiply(nearbyLandPixels).reduce(ee.Reducer.sum()).divide(numNearbyLandPixels)

    # Pack the results into a three channel image for the whole region
    # - Use the global pure land calculation to fill in if there are no nearby equation matching pixels
    MIN_PURE_NEARBY = 1
    meanPureLand = meanNearbyBandOne.addBands(meanNearbyBandTwo).addBands(meanNearbyBandSix)
    meanPureLand = meanPureLand.multiply(numNearbyLandPixels.gte(MIN_PURE_NEARBY)).add( averagePureLandImage.multiply(numNearbyLandPixels.lt(MIN_PURE_NEARBY)) )

    # Compute the water fraction: (land[b6] - b6) / (land[b6] - water[b6])
    # - Ultimately, relying solely on band 6 for the final classification may not be a good idea!
    meanPureLandSix = meanPureLand.select('sum_2')
    water_fraction = (meanPureLandSix.subtract(b['b6'])).divide(meanPureLandSix.subtract(pureWaterRef.select('sur_refl_b06'))).clamp(0, 1)
       
    # Set pure water to 1, pure land to 0
    water_fraction = water_fraction.add(pureWater).subtract(pureLand).clamp(0, 1)
    
    #addToMap(fraction, {'min': 0, 'max': 1},   'fraction', False)
    #addToMap(pureWater,      {'min': 0, 'max': 1},   'pure water', False)
    #addToMap(pureLand,       {'min': 0, 'max': 1},   'pure land', False)
    #addToMap(mixed,          {'min': 0, 'max': 1},   'mixed', False)
    #addToMap(pureWaterCount, {'min': 0, 'max': 300}, 'pure water count', False)
    #addToMap(water_fraction, {'min': 0, 'max': 5},   'water_fractionDNNS', False)
    #addToMap(pureWaterRef,   {'min': 0, 'max': 3000, 'bands': ['sur_refl_b01', 'sur_refl_b02', 'sur_refl_b06']}, 'pureWaterRef', False)

    return water_fraction.select(['sum_2'], ['b1']) # Rename sum_2 to b1