Skip to content

Commit

Permalink
image.py: Add clipToBoundsAndScale static method.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 658155557
  • Loading branch information
schwehr authored and Google Earth Engine Authors committed Jul 31, 2024
1 parent 82a71a3 commit 530e80d
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 11 deletions.
44 changes: 43 additions & 1 deletion python/ee/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,49 @@ def clip(self, clip_geometry: Any) -> Image:
self.name() + '.clip', self, clip_geometry
)

# TODO: clipToBoundsAndScale
def clipToBoundsAndScale(
self,
# pylint: disable-next=redefined-outer-name
geometry: Optional[_GeometryType] = None,
width: Optional[_IntegerType] = None,
height: Optional[_IntegerType] = None,
# pylint: disable-next=invalid-name
maxDimension: Optional[_IntegerType] = None,
scale: Optional[_NumberType] = None,
) -> Image:
"""Returns an image clipped to a geometry and scaled.
Clips an image to the bounds of a Geometry, and scales the clipped image to
a particular size or scale.
Caution: providing a large or complex collection as the `geometry` argument
can result in poor performance. Collating the geometry of collections does
not scale well; use the smallest collection (or geometry) that is required
to achieve the desired outcome.
Args:
geometry: The Geometry to clip the image to. The image will be clipped to
the bounding box, in the image's projection, of this geometry.
width: The width to scale the image to, in pixels. Must be provided along
with "height". Exclusive with "maxDimension" and "scale".
height: The height to scale the image to, in pixels. Must be provided
along with "width". Exclusive with "maxDimension" and "scale".
maxDimension: The maximum dimension to scale the image to, in pixels.
Exclusive with "width", "height" and "scale".
scale: If scale is specified, then the projection is scaled by dividing
the specified scale value by the nominal size of a meter in the image's
projection. Exclusive with "width", "height" and "maxDimension".
"""

return apifunction.ApiFunction.call_(
self.name() + '.clipToBoundsAndScale',
self,
geometry,
width,
height,
maxDimension,
scale,
)

def clipToCollection(self, collection: _FeatureCollectionType) -> Image:
"""Clips an image to a FeatureCollection.
Expand Down
9 changes: 8 additions & 1 deletion python/ee/tests/batch_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Test for the ee.batch module."""

import json
from typing import Any, Optional
import unittest
from unittest import mock
Expand Down Expand Up @@ -237,9 +238,15 @@ def testExportImageTrivialRegionCloudApi(self):
self.assertIsNone(task.name)
self.assertEqual('EXPORT_IMAGE', task.task_type)
self.assertEqual('UNSUBMITTED', task.state)

self.assertEqual(
json.loads(task.config['expression'].serialize()),
json.loads(expected_expression.serialize()),
)

task.config.pop('expression')
self.assertEqual(
{
'expression': expected_expression,
'assetExportOptions': {
'earthEngineDestination': {
'name': (
Expand Down
29 changes: 20 additions & 9 deletions python/ee/tests/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,18 +694,24 @@ def test_prepare_for_export_with_dimensions_crs_and_transform(self):
'dimensions': [3, 2],
'something': 'else'
})
self.assertEqual({'something': 'else'}, params)

reprojected_image = self._base_image.reproject(
crs='ABCD', crsTransform=[1, 2, 3, 4, 5, 6]
)

expected_expression = reprojected_image.clipToBoundsAndScale(
geometry=ee.Geometry.Rectangle(
coords=[0, 0, 3, 2],
proj=reprojected_image.projection(),
geodesic=False,
evenOdd=True,
)
)
self.assertEqual(
reprojected_image.clipToBoundsAndScale(
geometry=ee.Geometry.Rectangle(
coords=[0, 0, 3, 2],
proj=reprojected_image.projection(),
geodesic=False,
evenOdd=True)), image)
self.assertEqual({'something': 'else'}, params)
json.loads(image.serialize()),
json.loads(expected_expression.serialize()),
)

def test_prepare_for_export_with_only_region(self):
with apitestcase.UsingCloudApi():
Expand All @@ -724,12 +730,17 @@ def test_prepare_for_export_with_crs_no_transform(self):
image, params = self._base_image.prepare_for_export(
{'crs': 'ABCD', 'dimensions': [3, 2], 'something': 'else'}
)
self.assertEqual({'something': 'else'}, params)

projected = self._base_image.setDefaultProjection(
crs='ABCD', crsTransform=[1, 0, 0, 0, -1, 0]
)

self.assertEqual(projected.clipToBoundsAndScale(width=3, height=2), image)
self.assertEqual({'something': 'else'}, params)
expected_expression = projected.clipToBoundsAndScale(width=3, height=2)
self.assertEqual(
json.loads(image.serialize()),
json.loads(expected_expression.serialize()),
)

def test_morphological_operators(self):
"""Verifies the focal operators are installed with aliases."""
Expand Down

0 comments on commit 530e80d

Please sign in to comment.