imagecollection.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #!/usr/bin/env python
  2. """Representation for an Earth Engine ImageCollection."""
  3. # Using lowercase function naming to match the JavaScript names.
  4. # pylint: disable=g-bad-name
  5. from . import apifunction
  6. from . import collection
  7. from . import computedobject
  8. from . import data
  9. from . import ee_exception
  10. from . import ee_list
  11. from . import ee_types
  12. from . import image
  13. class ImageCollection(collection.Collection):
  14. """Representation for an Earth Engine ImageCollection."""
  15. _initialized = False
  16. # Tell pytype to not complain about dynamic attributes.
  17. _HAS_DYNAMIC_ATTRIBUTES = True
  18. def __init__(self, args):
  19. """ImageCollection constructor.
  20. Args:
  21. args: ImageCollections can be constructed from the following arguments:
  22. 1) A string: assumed to be the name of a collection,
  23. 2) An array of images, or anything that can be used to construct an
  24. image.
  25. 3) A single image.
  26. 5) A computed object - reinterpreted as a collection.
  27. Raises:
  28. EEException: if passed something other than the above.
  29. """
  30. self.initialize()
  31. # Wrap single images in an array.
  32. if isinstance(args, image.Image):
  33. args = [args]
  34. if ee_types.isString(args):
  35. # An ID.
  36. super(ImageCollection, self).__init__(
  37. apifunction.ApiFunction.lookup('ImageCollection.load'), {'id': args})
  38. elif isinstance(args, (list, tuple)):
  39. # A list of images.
  40. super(ImageCollection, self).__init__(
  41. apifunction.ApiFunction.lookup('ImageCollection.fromImages'), {
  42. 'images': [image.Image(i) for i in args]
  43. })
  44. elif isinstance(args, ee_list.List):
  45. # A computed list of images.
  46. super(ImageCollection, self).__init__(
  47. apifunction.ApiFunction.lookup('ImageCollection.fromImages'), {
  48. 'images': args
  49. })
  50. elif isinstance(args, computedobject.ComputedObject):
  51. # A custom object to reinterpret as an ImageCollection.
  52. super(ImageCollection, self).__init__(args.func, args.args, args.varName)
  53. else:
  54. raise ee_exception.EEException(
  55. 'Unrecognized argument type to convert to an ImageCollection: %s' %
  56. args)
  57. @classmethod
  58. def initialize(cls):
  59. """Imports API functions to this class."""
  60. if not cls._initialized:
  61. super(ImageCollection, cls).initialize()
  62. apifunction.ApiFunction.importApi(
  63. cls, 'ImageCollection', 'ImageCollection')
  64. apifunction.ApiFunction.importApi(
  65. cls, 'reduce', 'ImageCollection')
  66. cls._initialized = True
  67. @classmethod
  68. def reset(cls):
  69. """Removes imported API functions from this class."""
  70. apifunction.ApiFunction.clearApi(cls)
  71. cls._initialized = False
  72. def getMapId(self, vis_params=None):
  73. """Fetch and return a Map ID.
  74. This mosaics the collection to a single image and return a map ID suitable
  75. for building a Google Maps overlay.
  76. Args:
  77. vis_params: The visualization parameters.
  78. Returns:
  79. A map ID dictionary as described in ee.data.getMapId.
  80. """
  81. mosaic = apifunction.ApiFunction.call_('ImageCollection.mosaic', self)
  82. return mosaic.getMapId(vis_params)
  83. def select(self, selectors, opt_names=None, *args):
  84. """Select bands from each image in a collection.
  85. Args:
  86. selectors: An array of names, regexes or numeric indices specifying
  87. the bands to select.
  88. opt_names: An array of strings specifying the new names for the
  89. selected bands. If supplied, the length must match the number
  90. of bands selected.
  91. *args: Selector elements as varargs.
  92. Returns:
  93. The image collection with selected bands.
  94. """
  95. return self.map(lambda img: img.select(selectors, opt_names, *args))
  96. def first(self):
  97. """Returns the first entry from a given collection.
  98. Returns:
  99. The first entry from the collection.
  100. """
  101. return image.Image(apifunction.ApiFunction.call_('Collection.first', self))
  102. @staticmethod
  103. def name():
  104. return 'ImageCollection'
  105. @staticmethod
  106. def elementType():
  107. return image.Image
  108. def getVideoThumbURL(self, params=None):
  109. """Get the URL for an animated video thumbnail of the given collection.
  110. Note: Videos can only be created when the image visualization
  111. creates an RGB or RGBA image. This can be done by mapping a visualization
  112. onto the collection or specifying three bands in the params.
  113. Args:
  114. params: Parameters identical to getMapId, plus, optionally:
  115. dimensions -
  116. (a number or pair of numbers in format WIDTHxHEIGHT) Max dimensions of
  117. the thumbnail to render, in pixels. If only one number is passed, it is
  118. used as the maximum, and the other dimension is computed by proportional
  119. scaling.
  120. crs - a CRS string specifying the projection of the output.
  121. crs_transform - the affine transform to use for the output pixel grid.
  122. scale - a scale to determine the output pixel grid; ignored if both crs
  123. and crs_transform are specified.
  124. region - (E,S,W,N or GeoJSON) Geospatial region of the result. By default,
  125. the whole image.
  126. format - (string) The output format (only 'gif' is currently supported).
  127. framesPerSecond - Animation speed.
  128. Visualization parameters - ['bands', 'gain', 'bias', 'min', 'max',
  129. 'gamma', 'palette', 'opacity', 'forceRgbOutput'] see Earth Engine
  130. API for ee.Image.visualize for more information.
  131. Returns:
  132. A URL to download a thumbnail of the specified ImageCollection.
  133. Raises:
  134. EEException: If the region parameter is not an array or GeoJSON object.
  135. """
  136. return self._getThumbURL(['gif'], params, thumbType='video')
  137. def getFilmstripThumbURL(self, params=None):
  138. """Get the URL for a "filmstrip" thumbnail of the given collection.
  139. Args:
  140. params: Parameters identical to getMapId, plus, optionally:
  141. dimensions -
  142. (a number or pair of numbers in format WIDTHxHEIGHT) Max dimensions of
  143. the thumbnail to render, in pixels. If only one number is passed, it is
  144. used as the maximum, and the other dimension is computed by proportional
  145. scaling.
  146. crs - a CRS string specifying the projection of the output.
  147. crs_transform - the affine transform to use for the output pixel grid.
  148. scale - a scale to determine the output pixel grid; ignored if both crs
  149. and crs_transform are specified.
  150. region - (E,S,W,N or GeoJSON) Geospatial region of the result. By default,
  151. the whole image.
  152. format - (string) The output format (e.g., "png", "jpg").
  153. Visualization parameters - ['bands', 'gain', 'bias', 'min', 'max',
  154. 'gamma', 'palette', 'opacity', 'forceRgbOutput'] see Earth Engine
  155. API for ee.Image.visualize for more information.
  156. Returns:
  157. A URL to download a thumbnail of the specified ImageCollection.
  158. Raises:
  159. EEException: If the region parameter is not an array or GeoJSON object.
  160. """
  161. return self._getThumbURL(['png', 'jpg'], params, thumbType='filmstrip')
  162. def _getThumbURL(self, valid_formats, params=None, thumbType=None):
  163. """Get the URL for a thumbnail of this collection.
  164. Args:
  165. valid_formats: A list of supported formats, the first of which is used as
  166. a default if no format is supplied in 'params'.
  167. params: Parameters identical to getMapId, plus, optionally:
  168. dimensions -
  169. (a number or pair of numbers in format WIDTHxHEIGHT) Max dimensions of
  170. the thumbnail to render, in pixels. If only one number is passed, it is
  171. used as the maximum, and the other dimension is computed by proportional
  172. scaling.
  173. crs - a CRS string specifying the projection of the output.
  174. crs_transform - the affine transform to use for the output pixel grid.
  175. scale - a scale to determine the output pixel grid; ignored if both crs
  176. and crs_transform are specified.
  177. region - (E,S,W,N or GeoJSON) Geospatial region of the result. By default,
  178. the whole image.
  179. format - (string) The output format
  180. thumbType: must be either 'video' or 'filmstrip'.
  181. Returns:
  182. A URL to download a thumbnail of the specified ImageCollection.
  183. Raises:
  184. EEException: If the region parameter is not an array or GeoJSON object.
  185. """
  186. def map_function(input_image, input_params):
  187. # pylint: disable=protected-access
  188. output_image, request = input_image._apply_spatial_transformations(
  189. input_params)
  190. output_image, request = output_image._apply_visualization(request)
  191. # pylint: enable=protected-access
  192. return output_image, request
  193. clipped_collection, request = self._apply_preparation_function(
  194. map_function, params)
  195. request['format'] = params.get('format', valid_formats[0])
  196. if request['format'] not in valid_formats:
  197. raise ee_exception.EEException(
  198. 'Invalid format specified for thumbnail. ' + str(params['format']))
  199. if params and 'framesPerSecond' in params:
  200. request['framesPerSecond'] = params.get('framesPerSecond')
  201. request['image'] = clipped_collection
  202. if params and params.get('dimensions') is not None:
  203. request['dimensions'] = params.get('dimensions')
  204. if thumbType not in ['video', 'filmstrip']:
  205. raise ee_exception.EEException(
  206. 'Invalid thumbType provided to _getThumbURL only \'video\' or '
  207. '\'filmstrip\' is supported.')
  208. return data.makeThumbUrl(data.getThumbId(request, thumbType=thumbType))
  209. def _apply_preparation_function(self, preparation_function, params):
  210. """Applies a preparation function to an ImageCollection.
  211. Args:
  212. preparation_function: The preparation function. Takes an image and a
  213. parameter dict; returns the modified image and a subset of the
  214. parameter dict, with the parameters it used removed.
  215. params: The parameters to the preparation function.
  216. Returns:
  217. A tuple containing:
  218. - an ImageCollection that has had many of the parameters applied
  219. to it
  220. - any remaining parameters.
  221. """
  222. # The preparation function operates only on a single image and returns a
  223. # modified parameter set; we need to apply across all the images in this
  224. # collection via self.map, and also return a modified parameter set, which
  225. # we can't easily get out of self.map. So we invoke it in two ways: once on
  226. # a dummy Image to get a modified parameter set, and once via self.map.
  227. _, remaining_params = preparation_function(self.first(), params)
  228. if remaining_params == params:
  229. # Nothing in params affects us; omit the map.
  230. return self, params
  231. # Copy params defensively in case it's modified after we return but before
  232. # the map operation is serialised.
  233. params = params.copy()
  234. def apply_params(img):
  235. prepared_img, _ = preparation_function(img, params)
  236. return prepared_img
  237. return self.map(apply_params), remaining_params
  238. def prepare_for_export(self, params):
  239. """Applies all relevant export parameters to an ImageCollection.
  240. Args:
  241. params: The export request parameters.
  242. Returns:
  243. A tuple containing:
  244. - an ImageCollection that has had many of the request parameters applied
  245. to it
  246. - any remaining parameters.
  247. """
  248. # If the Cloud API is enabled, we can do cleaner handling of the parameters.
  249. # If it isn't enabled, we have to be bug-for-bug compatible with current
  250. # behaviour, so we do nothing.
  251. return self._apply_preparation_function(image.Image.prepare_for_export,
  252. params)