Skip to content

Commit

Permalink
Merge pull request #120 from developmentseed/fix_out_of_bound
Browse files Browse the repository at this point in the history
Handles out of bound clipping requests
  • Loading branch information
Scisco committed Oct 23, 2015
2 parents c13d95f + c6b0a8e commit 82be313
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 25 deletions.
4 changes: 2 additions & 2 deletions landsat/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from polyline.codec import PolylineCodec

from mixins import VerbosityMixin
from utils import get_file, check_create_folder, exit
from utils import get_file, check_create_folder, exit, adjust_bounding_box
from decorators import rasterio_decorator


Expand Down Expand Up @@ -359,7 +359,7 @@ def clip(self):
)

if disjoint_bounds(bounds, src.bounds):
raise BoundsDoNotOverlap('Bounds must overlap with the image')
bounds = adjust_bounding_box(src.bounds, bounds)

window = src.window(*bounds)

Expand Down
38 changes: 38 additions & 0 deletions landsat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,41 @@ def convert_to_float_list(value):
except ValueError:
pass
return s


def adjust_bounding_box(bounds1, bounds2):
""" If the bounds 2 corners are outside of bounds1, they will be adjusted to bounds1 corners
@params
bounds1 - The source bounding box
bounds2 - The target bounding box that has to be within bounds1
@return
A bounding box tuple in (y1, x1, y2, x2) format
"""

# out of bound check
# If it is completely outside of target bounds, return target bounds
if ((bounds2[0] > bounds1[0] and bounds2[2] > bounds1[0]) or
(bounds2[2] < bounds1[2] and bounds2[2] < bounds1[0])):
return bounds1

if ((bounds2[1] < bounds1[1] and bounds2[3] < bounds1[1]) or
(bounds2[3] > bounds1[3] and bounds2[1] > bounds1[3])):
return bounds1

new_bounds = list(bounds2)

# Adjust Y axis (Longitude)
if (bounds2[0] > bounds1[0] or bounds2[0] < bounds1[3]):
new_bounds[0] = bounds1[0]
if (bounds2[2] < bounds1[2] or bounds2[2] > bounds1[0]):
new_bounds[2] = bounds1[2]

# Adjust X axis (Latitude)
if (bounds2[1] < bounds1[1] or bounds2[1] > bounds1[3]):
new_bounds[1] = bounds1[1]
if (bounds2[3] > bounds1[3] or bounds2[3] < bounds1[1]):
new_bounds[3] = bounds1[3]

return tuple(new_bounds)
78 changes: 55 additions & 23 deletions tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,25 @@
import shutil
import unittest
from tempfile import mkdtemp
import rasterio
from rasterio.warp import transform_bounds

from landsat.image import Simple, PanSharpen
from landsat.ndvi import NDVI, NDVIWithManualColorMap


def get_bounds(path):
""" Retrun bounds in WGS84 system """

with rasterio.drivers():
src = rasterio.open(path)

return transform_bounds(
src.crs,
{'init': 'EPSG:4326'},
*src.bounds)


class TestProcess(unittest.TestCase):

@classmethod
Expand All @@ -34,61 +48,79 @@ def tearDownClass(cls):
def test_simple_no_bands(self):

p = Simple(path=self.landsat_image, dst_path=self.temp_folder)
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_432.TIF')))
self.assertTrue(exists(p.run()))

def test_simple_with_bands(self):

p = Simple(path=self.landsat_image, bands=[1, 2, 3], dst_path=self.temp_folder)
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_123.TIF')))
self.assertTrue(exists(p.run()))

def test_simple_with_clip(self):

bounds = [-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485]
p = Simple(path=self.landsat_image, bands=[1, 2, 3], dst_path=self.temp_folder,
bounds=[-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485])
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_123.TIF')))
bounds=bounds)
path = p.run()
self.assertTrue(exists(path))
self.assertEqual(map('{0:.2f}'.format, get_bounds(path)), map('{0:.2f}'.format, bounds))

def test_simple_with_intersecting_bounds_clip(self):

bounds = [-87.520515832683923, 30.700515832683923, -87.43331909179688, 30.739475058679485]
expected_bounds = [-87.49691403528307, 30.700515832683923, -87.43331909179688, 30.739475058679485]
p = Simple(path=self.landsat_image, bands=[1, 2, 3], dst_path=self.temp_folder,
bounds=bounds)
path = p.run()
self.assertTrue(exists(path))
self.assertEqual(map('{0:.2f}'.format, get_bounds(path)), map('{0:.2f}'.format, expected_bounds))

def test_simple_with_out_of_bounds_clip(self):

bounds = [-87.66197204589844, 30.732392734006083, -87.57545471191406, 30.806731169315675]
expected_bounds = [-87.49691403528307, 30.646646570857722, -87.29976764207227, 30.810617911193567]
p = Simple(path=self.landsat_image, bands=[1, 2, 3], dst_path=self.temp_folder,
bounds=bounds)
path = p.run()
self.assertTrue(exists(path))
self.assertEqual(map('{0:.2f}'.format, get_bounds(path)), map('{0:.2f}'.format, expected_bounds))

def test_simple_with_zip_file(self):

p = Simple(path=self.landsat_image, dst_path=self.temp_folder)

# test from an unzip file
self.path = join(self.base_dir, 'samples', 'test')
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_432.TIF')))
self.assertTrue(exists(p.run()))

def test_pansharpen(self):
# test with pansharpen

p = PanSharpen(path=self.landsat_image, bands=[4, 3, 2], dst_path=self.temp_folder)
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_432_pan.TIF')))
self.assertTrue(exists(p.run()))

def test_pansharpen_with_clip(self):
""" test with pansharpen and clipping """

bounds = [-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485]
p = PanSharpen(path=self.landsat_image, bands=[4, 3, 2], dst_path=self.temp_folder,
bounds=[-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485])
p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_bands_432_pan.TIF')))
bounds=bounds)
path = p.run()
self.assertTrue(exists(path))
self.assertEqual(map('{0:.2f}'.format, get_bounds(path)), map('{0:.2f}'.format, bounds))

def test_ndvi(self):

p = NDVI(path=self.landsat_image, dst_path=self.temp_folder)
print p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_NDVI.TIF')))
self.assertTrue(exists(p.run()))

def test_ndvi_with_clip(self):

bounds = [-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485]
p = NDVI(path=self.landsat_image, dst_path=self.temp_folder,
bounds=[-87.48138427734375, 30.700515832683923, -87.43331909179688, 30.739475058679485])
print p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_NDVI.TIF')))
bounds=bounds)
path = p.run()
self.assertTrue(exists(path))
self.assertEqual(map('{0:.2f}'.format, get_bounds(path)), map('{0:.2f}'.format, bounds))

def test_ndvi_with_manual_colormap(self):

p = NDVIWithManualColorMap(path=self.landsat_image, dst_path=self.temp_folder)
print p.run()
self.assertTrue(exists(join(self.temp_folder, 'test', 'test_NDVI.TIF')))
self.assertTrue(exists(p.run()))
42 changes: 42 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,48 @@ def test_convert_to_float_list(self):
r = utils.convert_to_float_list('1,11,10')
self.assertEqual([1.0, 11.0, 10.0], r)

def test_adjust_bounding_box(self):

# Test target bounds with origin bounds
# should return the target bounds
origin = (100, 10, 80, 20)
target = (90, 15, 91, 15)

self.assertEqual(utils.adjust_bounding_box(origin, target), target)

# Test target bounds intersects with origin bounds
# should return the expected bounds
origin = (100, 10, 80, 20)
target = (120, -5, 99, 15)
expected = (100, 10, 99, 15)

self.assertEqual(utils.adjust_bounding_box(origin, target), expected)

# Test target bounds do not intersect with origin bounds at all
# Target bounds are above origin bounds
# should return the origin bounds
origin = (100, 10, 80, 20)
target = (120, -5, 110, 9)

self.assertEqual(utils.adjust_bounding_box(origin, target), origin)

# Target bounds are on the right side of origin bounds
origin = (100, 10, 80, 20)
target = (82, 23, 91, 26)

self.assertEqual(utils.adjust_bounding_box(origin, target), origin)

# Target bounds are below of origin bounds
origin = (100, 10, 80, 20)
target = (70, 11, 60, 18)

self.assertEqual(utils.adjust_bounding_box(origin, target), origin)

# Target bounds are on the left side of origin bounds
origin = (100, 10, 80, 20)
target = (80, -20, 79, -19)

self.assertEqual(utils.adjust_bounding_box(origin, target), origin)

if __name__ == '__main__':
unittest.main()

0 comments on commit 82be313

Please sign in to comment.