krishnab
krishnab

Reputation: 10040

How to iterate over and download each image in an image collection from the Google Earth Engine python api

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
})

Upvotes: 5

Views: 12270

Answers (4)

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'});

Upvotes: 1

csaybar
csaybar

Reputation: 179

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

Upvotes: 1

mhawke
mhawke

Reputation: 87054

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.

Upvotes: 0

Nicholas Clinton
Nicholas Clinton

Reputation: 893

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.

Upvotes: 8

Related Questions