0

I have a function that I would like to map across an ee.List, and map it over an ee.ImageCollection of raw DN images.

So far it is looking like (using wrapper functions):

def perturb_image(pert_matrix):
    #'''
    #pert_matrix is fed as an ee.List()
    #'''
  
  def toa_reflectance(image):
      #'''
      #:params
      #  - ee.Image (raw)
      #  - list of  mult coefficients (regular list)
      #  -  bias list (ee.List)
      #    returns TOA image
      #''' 

        band1 = image.select("B1")   ... etc.    
        toa_1 = band1.multiply(ee.Number(mult_list.get(0)).multiply(row[0])).add(ee.Number(add_list.get(0))).multiply(ee.Number(constant)) ... etc.
        toa = ee.Image.cat([toa_1, toa_2, toa_3, toa_4, toa_5, toa_6, toa_7, toa_9, bqa])

        return toa
return toa_reflectance

I tried implementing them in the following way:

images = ee.ImageCollection
mat = ee.List([ * insert list of perturbed gain factors * ])

images_new = images.map(mat.map(perturb_image)) #ee.ImageCollection    
      

I receive errors such as "AttributeError: 'ComputedObject' object has no attribute 'get'"

I have also tried to instead map the function only over the ee.List, and applied to a single image. mat.map(perturb_image())(image)

, but that has only yielded: TypeError: perturb_image() missing 1 required positional argument: 'pert_matrix'.

Wondering if it is a casting issue?

(Edited after Kevin Reid's answer):

def perturb_image(pert_matrix):
  pert_matrix = ee.List(pert_matrix)
  
  def row_perturb(row): #this should be mapped to pert_matrix 
    row = ee.List(row)

    def toa_reflectance(image): #should be innermost
        #'''
        #:params
        #  - ee.Image (raw)
        #  - list of  mult coefficients (regular list)
        #  -  bias list (ee.List)
        #returns TOA image
        #'''
        #ee.Array(refmult_list).multiply(ee.Array(pert_array)).toList()
        mult_list = ee.List(image.get('REF_MULTS_BANDS[1,2,3,4,5,6,7,9]'))
        add_list = ee.List(image.get('REF_ADDS_BANDS[1,2,3,4,5,6,7,9]'))
        sun_ang = ee.Number(image.get('SUN_ELEVATION'))
        sine_val = ee.Number(sun_ang.multiply(math.pi).divide(180).sin())#radians
        constant = ee.Number(1).divide(sine_val)
        #now for the bands
        band1 = image.select("B1")
        band2 = image.select("B2")
        band3 = image.select("B3")
        band4 = image.select("B4")
        band5 = image.select("B5")
        band6 = image.select("B6")
        band7 = image.select("B7")
        band9 = image.select("B9")
        bqa   = image.select("BQA")
      
        band_list = ee.List([band1, band2, band3, band4, band5, band6, band7, band9])
        
        toa_1 = band1.multiply(ee.Number(mult_list.get(0)).multiply(row.get(0))).add(ee.Number(add_list.get(0))).multiply(ee.Number(constant))  
        toa_2 = band2.multiply(ee.Number(mult_list.get(1)).multiply(row.get(1))).add(ee.Number(add_list.get(1))).multiply(ee.Number(constant))
        toa_3 = band3.multiply(ee.Number(mult_list.get(2)).multiply(row.get(2))).add(ee.Number(add_list.get(2))).multiply(ee.Number(constant))
        toa_4 = band4.multiply(ee.Number(mult_list.get(3)).multiply(row.get(3))).add(ee.Number(add_list.get(3))).multiply(ee.Number(constant))      
        toa_5 = band5.multiply(ee.Number(mult_list.get(4)).multiply(row.get(4))).add(ee.Number(add_list.get(4))).multiply(ee.Number(constant))
        toa_6 = band6.multiply(ee.Number(mult_list.get(5)).multiply(row.get(5))).add(ee.Number(add_list.get(5))).multiply(ee.Number(constant))
        toa_7 = band7.multiply(ee.Number(mult_list.get(6)).multiply(row.get(6))).add(ee.Number(add_list.get(6))).multiply(ee.Number(constant))
        toa_9 = band9.multiply(ee.Number(mult_list.get(7)).multiply(row.get(7))).add(ee.Number(add_list.get(7))).multiply(ee.Number(constant))

        toa = ee.Image.cat([toa_1, toa_2, toa_3, toa_4, toa_5, toa_6, toa_7, toa_9, bqa])
        
        return toa
    return toa_reflectance
  return pert_matrix.map(row_perturb) #this returns a... function?

mat = ee.List([[0.99, 1, 1, 1, 1, 1, 1, 1], [0.991, 1, 1, 1, 1, 1, 1, 1], [0.992, 1, 1, 1, 1, 1, 1, 1], [0.993, 1, 1, 1, 1, 1, 1, 1], [0.994, 1, 1, 1, 1, 1, 1, 1], [0.995, 1, 1, 1, 1, 1, 1, 1], [0.996, 1, 1, 1, 1, 1, 1, 1], [0.997, 1, 1, 1, 1, 1, 1, 1], [0.998, 1, 1, 1, 1, 1, 1, 1], [0.999, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1], [1.001, 1, 1, 1, 1, 1, 1, 1], [1.0019999999999998, 1, 1, 1, 1, 1, 1, 1], [1.0029999999999997, 1, 1, 1, 1, 1, 1, 1], [1.0039999999999996, 1, 1, 1, 1, 1, 1, 1], [1.0049999999999994, 1, 1, 1, 1, 1, 1, 1], [1.0059999999999993, 1, 1, 1, 1, 1, 1, 1], [1.0069999999999992, 1, 1, 1, 1, 1, 1, 1], [1.0079999999999991, 1, 1, 1, 1, 1, 1, 1], [1.008999999999999, 1, 1, 1, 1, 1, 1, 1], [1.009999999999999, 1, 1, 1, 1, 1, 1, 1]])



#toa_thing = ee.ImageCollection(*list of images*)

images_new = toa_thing.map(perturb_image(mat))
print(images_new.getInfo())

When I call the function as above, I receive the following error: EEException: Can't encode object: <function perturb_image.<locals>.row_perturb.<locals>.toa_reflectance at 0x7fd56557b268>

0
2

In general, yes, if you have a missing method like 'get', you likely need to write a cast inside the mapped function. However, there are bigger problems here.

  • mat.map(perturb_image): given that mat is an ee.List, this will produce another ee.List. But the return value of perturb_image is a Python function, which can't be stored by itself in an ee.List.

  • images.map(mat.map(perturb_image)): Now you're taking that ee.List (if it could exist) and passing it as the mapping function to ImageCollection.map. This will not work, because a list is not a function.

  • mat.map(perturb_image())(image): This fails straightforwardly because you're immediately calling perturb_image with zero arguments, when it expects one.

Based on the comment that perturb_image takes a matrix, I suspect that what you're actually trying to do is just apply perturb_image to get a mapping function. In that case, to do it with the collection is:

images_new = images.map(perturb_image(mat))

Or for one image:

image_new = perturb_image(mat)(image)

When you're just calling a function you defined, once, there is no map in it — you write it just like you would in plain Python.

2
  • Thank you so much Kevin! I wanted to clarify— if perturb_matrix is a list of lists (ex: ee.List([[1, 2, 3], [4, 5, 6], [7, 8, 9]) and I wanted to do a procedure for each row of this list, should I still need to map the function across perturb_matrix somewhere in the nested function? – sbab Nov 22 '20 at 21:36
  • @sbab Yes, that's correct. – Kevin Reid Nov 22 '20 at 22:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.