5

I am new to google earth engine and was trying to understand how to use the Google Earth Engine python api. I can create an image collection, but apparently the getdownloadurl() method operates only on individual images. So I am trying to understand how to iterate over and download all of the images in the collection.

Here is my basic code. I broke it out in great detail for some other work I am doing.

import ee
ee.Initialize()
col = ee.ImageCollection('LANDSAT/LC08/C01/T1')
col.filterDate('1/1/2015', '4/30/2015')
pt = ee.Geometry.Point([-2.40986111110000012, 26.76033333330000019])
buff = pt.buffer(300)
region = ee.Feature.bounds(buff)
col.filterBounds(region)

So I pulled the Landsat collection, filtered by date and a buffer geometry. So I should have something like 7-8 images in the collection (with all bands).

However, I could not seem to get iteration to work over the collection.

for example:

for i in col:
    print(i)

The error indicates TypeError: 'ImageCollection' object is not iterable

So if the collection is not iterable, how can I access the individual images?

Once I have an image, I should be able to use the usual

path = col[i].getDownloadUrl({
    'scale': 30,
    'crs': 'EPSG:4326',
    'region': region
})
krishnab
  • 9,270
  • 12
  • 66
  • 123

4 Answers4

8

It's a good idea to use ee.batch.Export for this. Also, it's good practice to avoid mixing client and server functions (reference). For that reason, a for-loop can be used, since Export is a client function. Here's a simple example to get you started:

import ee
ee.Initialize()

rectangle = ee.Geometry.Rectangle([-1, -1, 1, 1])
sillyCollection = ee.ImageCollection([ee.Image(1), ee.Image(2), ee.Image(3)])

# This is OK for small collections
collectionList = sillyCollection.toList(sillyCollection.size())
collectionSize = collectionList.size().getInfo()
for i in xrange(collectionSize):
    ee.batch.Export.image.toDrive(
        image = ee.Image(collectionList.get(i)).clip(rectangle), 
        fileNamePrefix = 'foo' + str(i + 1), 
        dimensions = '128x128').start()

Note that converting a collection to a list in this manner is also dangerous for large collections (reference). However, this is probably the most scalable method if you really need to download.

1

Here is my solution:

import ee
ee.Initialize()
pt = ee.Geometry.Point([-2.40986111110000012, 26.76033333330000019])
region = pt.buffer(10)

col = ee.ImageCollection('LANDSAT/LC08/C01/T1')\
        .filterDate('2015-01-01','2015-04-30')\
        .filterBounds(region)

bands = ['B4','B5'] #Change it!

def accumulate(image,img):
  name_image = image.get('system:index')
  image = image.select([0],[name_image])
  cumm = ee.Image(img).addBands(image)
  return cumm

for band in bands:
  col_band = col.map(lambda img: img.select(band)\
                               .set('system:time_start', img.get('system:time_start'))\
                               .set('system:index', img.get('system:index')))
  #  ImageCollection to List           
  col_list = col_band.toList(col_band.size())

  #  Define the initial value for iterate.
  base = ee.Image(col_list.get(0))
  base_name = base.get('system:index')
  base = base.select([0], [base_name])

  #  Eliminate the image 'base'.
  new_col = ee.ImageCollection(col_list.splice(0,1))

  img_cummulative = ee.Image(new_col.iterate(accumulate,base))

  task = ee.batch.Export.image.toDrive(
      image = img_cummulative.clip(region),
      folder = 'landsat',
      fileNamePrefix = band,
      scale = 30).start()  

  print('Export Image '+ band+ ' was submitted, please wait ...')

img_cummulative.bandNames().getInfo()

A reproducible example can you found it here: https://colab.research.google.com/drive/1Nv8-l20l82nIQ946WR1iOkr-4b_QhISu

csaybar
  • 179
  • 1
  • 5
0

You could possibly use ee.ImageCollection.iterate() with a function that gets the image and adds it to a list.

import ee

def accumluate_images(image, images):
    images.append(image)
    return images

for img in col.iterate(accumulate_images, []):
    url = img.getDownloadURL(dict(scale=30, crs='EPSG:4326', region=region))

Unfortunately I am not able to test this code as I do not have access to the API, but it might help you arrive at a solution.

mhawke
  • 84,695
  • 9
  • 117
  • 138
  • Yeah, I saw a mention about the `iterate` method. I will give that a shot. Thanks so much for the suggestion. – krishnab Oct 26 '17 at 03:29
  • You should avoid this method for two reasons. One, it's good practice to avoid mixing client (`getDownloadURL()` ) and server (`iterate()`) functions ([reference](https://developers.google.com/earth-engine/debugging#avoid-mixing-client-functions-and-objects-with-server-functions-and-objects)). Two, `getDownloadURL()` is flaky and sometimes results in corrupted downloads. – Nicholas Clinton Oct 26 '17 at 18:14
  • @NicholasClinton: thanks. According to your reference `getDownloadURL()` is a _server_ function as it is a method on an `ee.Image()` object. Did you mean the Python list that is being passed to `iterate()` and the call to `list.append()`? – mhawke Oct 27 '17 at 02:18
  • @NicholasClinton: regarding your second point, the API and its functionality is experimental and subject to change. Can we assume that the flakiness of that method might be due to that? – mhawke Oct 27 '17 at 02:21
  • 1
    The best explanation of `getDownloadURL()` flakiness is [here](https://groups.google.com/d/msg/google-earth-engine-developers/zoAViiTCrGk/Qo9yovkRCAAJ). Note that `getDownloadURL()` [sends a request to the server](https://github.com/google/earthengine-api/blob/e89ddd5382d81971c8f1ddfbbfce9a4552cd5953/python/ee/image.py#L133) while 'iterate()` [runs on the server](https://github.com/google/earthengine-api/blob/645969797a997dc87591752b8b12d89b958b171f/python/ee/collection.py#L224) – Nicholas Clinton Oct 27 '17 at 19:29
0

I have a similar problem and was not able o solve with presented solutions. Then I have elaborated a sample code for this purpose. It iterates over an image collection in client side, then it is not affected by limitations (server side only) of .map() or .iterate().

It is possible to download the code and see its explanation here

It basically transform the ImageCollection into a list (ic.toList()). Then it performs a standard loop, and for each individual image it is possible to convert it back to ee.Image(list.get(i)), and then process one by one taking all images in the collection.

In your particular case, to download each image, the function to be called within the loop could be: getDOwnloadURL() or getThumbURL():

var url = imgNew.getDownloadURL({
    region: geometry,
  });

var thumbURL = imgNew.getThumbURL({region: geometry,dimensions: 512, format: 'png'});
Sagar Darekar
  • 982
  • 9
  • 14