def test_raster_bbox(self): raster_io = RasterFileIO( uri=os.path.join(testfile_path, 'satellite_test_data', 'LC81070352015218LGN00_B5.TIF')) bbox = raster_io.get_bbox() self.assertEquals(bbox, [ 307366.7298195886, 3869968.931078481, 539974.1151507461, 4107482.3190209507 ])
def __init__(self, calc=None, **kwargs): """ Initialize a RasterMathProcess object. :param calc: A text representation of the calculation to make. :param kwargs: Other keyword arguments """ self.calc = calc super(RasterMathProcess, self).__init__(**kwargs) if not self.output: self.output = RasterFileIO(name='result', uri=self.get_outpath())
def test_raster_footprint(self): raster_io = RasterFileIO( uri=os.path.join(testfile_path, 'satellite_test_data', 'LC81070352015218LGN00_B5.TIF')) footprint = raster_io.get_footprint() self.assertEquals(footprint, [(354404.6484867488, 4107482.3190209507), (307366.7298195886, 3915415.660631991), (492936.19648358587, 3869968.931078481), (539974.1151507461, 4062035.5894674407), (354404.6484867488, 4107482.3190209507)])
def test_validationInputsNoMax(self): """ Test the GaiaProcess.validate() function - pass on no max input types """ raster_io1 = RasterFileIO(uri='/fake/path1') raster_io2 = RasterFileIO(uri='/fake/path2') try: geo.RasterMathProcess(inputs=[raster_io1, raster_io2], calc='A+B') except geo.GaiaException: self.fail("Multiple inputs should have passed validation")
def __init__(self, **kwargs): """ Create a process to subset a raster by a vector polygon :param clip_io: IO object containing vector polygon data :param raster_io: IO object containing raster data :param kwargs: :return: SubsetProcess object """ super(SubsetProcess, self).__init__(**kwargs) if not self.output: self.output = RasterFileIO(name='result', uri=self.get_outpath())
def test_rastermath_add(self): """ Test adding two rasters together """ raster1_io = RasterFileIO(name='A', uri=os.path.join(testfile_path, 'globalairtemp.tif')) raster2_io = RasterFileIO(name='B', uri=os.path.join(testfile_path, 'globalprecip.tif')) calc = 'A + B' bands = [1, 1] process = geo.RasterMathProcess(inputs=[raster1_io, raster2_io], calc=calc, bands=bands) try: process.compute() self.assertTrue(os.path.exists(process.output.uri)) oraster, raster1, raster2 = [ x.read() for x in (process.output, raster1_io, raster2_io) ] # Output raster should be same dimensions as raster 1 self.assertEquals((oraster.RasterXSize, oraster.RasterYSize), (raster1.RasterXSize, raster1.RasterYSize)) orb, r1b, r2b = [ x.GetRasterBand(1) for x in (oraster, raster1, raster2) ] # Min value of output should be >= the max minimum of inputs self.assertGreaterEqual( orb.GetStatistics(False, True)[0], max( r1b.GetStatistics(False, True)[0], r2b.GetStatistics(False, True)[0])) # Max value of output >= max(minimum)+min(maximum) of inputs self.assertGreaterEqual( orb.GetStatistics(False, True)[1], max( r1b.GetStatistics(False, True)[0], r2b.GetStatistics(False, True)[0]) + min( r1b.GetStatistics(False, True)[1], r2b.GetStatistics(False, True)[1])) finally: if process: process.purge()
class SubsetProcess(GaiaProcess): """ Generates a raster dataset representing the portion of the input raster dataset that is contained within a vector polygon. """ #: Tuple of required inputs; name, type , max # of each; None = no max required_inputs = [ {'description': 'Image to subset', 'type': types.RASTER, 'max': 1 }, {'description': 'Subset area:', 'type': types.VECTOR, 'max': 1 } ] #: Default output format for the process default_output = formats.RASTER def __init__(self, **kwargs): """ Create a process to subset a raster by a vector polygon :param clip_io: IO object containing vector polygon data :param raster_io: IO object containing raster data :param kwargs: :return: SubsetProcess object """ super(SubsetProcess, self).__init__(**kwargs) if not self.output: self.output = RasterFileIO(name='result', uri=self.get_outpath()) def compute(self): """ Runs the subset computation, creating a raster dataset as output. """ raster, clip = self.inputs[0], self.inputs[1] raster_img = raster.read() clip_df = clip.read(epsg=raster.get_epsg()) # Merge all features in vector input raster_output = self.output.uri self.output.create_output_dir(raster_output) clip_json = clip_df.geometry.unary_union.__geo_interface__ self.output.data = gdal_clip(raster_img, raster_output, clip_json)
def test_validationInputsOrder(self): """ Test the GaiaProcess.validate() function - fail on incorrect order """ raster_iO = RasterFileIO(uri='/fake/path1') vector_io = VectorFileIO(uri='/fake/path2') with self.assertRaises(geo.GaiaException) as ge: geo.ZonalStatsProcess(inputs=[vector_io, raster_iO]) self.assertIn('Input #1 is of incorrect type.', str(ge.exception))
def test_validationInputsPass(self): """ Test the GaiaProcess.validate() function - pass on valid input """ raster_io = RasterFileIO(uri='/fake/path') vector_io = VectorFileIO(uri='/fake/path') try: geo.ZonalStatsProcess(inputs=[raster_io, vector_io]) except geo.GaiaException: self.fail("ZonalProcess should have passed validation but did not")
def __init__(self, **kwargs): """ Create a process to merge rasters. :param inputs: Images to merge. :param kwargs: Other keyword arguments. :return: MergeProcess object """ super(MergeProcess, self).__init__(**kwargs) if not self.output: self.output = RasterFileIO(name='result', uri=self.get_outpath())
def test_zonalstats(self): vector_io = FeatureIO(features=[{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[100.0, 0.0], [120.0, 0.0], [120.0, 30.0], [100.0, 30.0], [100.0, 0.0]]] }, "properties": { "prop0": "value1", "prop1": { "this": "that" } } }, { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[-100.0, 0.0], [-120.0, 0.0], [-120.0, -30.0], [100.0, -30.0], [100.0, 0.0]]] }, "properties": { "prop0": "value0", "prop1": { "this": "other thing" } } }]) raster_io = RasterFileIO(name='temp', uri=os.path.join(testfile_path, 'globalairtemp.tif')) process = geo.ZonalStatsProcess(inputs=[raster_io, vector_io]) try: process.compute() with open( os.path.join(testfile_path, 'zonalstats_process_results.json')) as exp: expected_json = json.load(exp) actual_json = json.loads( process.output.read(format=geo.formats.JSON)) self.assertEquals(len(expected_json['features']), len(actual_json['features'])) finally: pass if process: process.purge()
def test_rastermath_multiply_by_value(self): """ Test multiplying a raster by a value, and specifying output type (Float32) """ raster1_io = RasterFileIO(name='A', uri=os.path.join(testfile_path, 'globalprecip.tif')) calc = 'A * 2' output_type = 'Float32' process = geo.RasterMathProcess(inputs=[ raster1_io, ], calc=calc, output_type=output_type) try: process.compute() self.assertTrue(os.path.exists(process.output.uri)) oraster, raster1 = [x.read() for x in (process.output, raster1_io)] # Output raster should be same dimensions as raster 1 self.assertEquals((oraster.RasterXSize, oraster.RasterYSize), (raster1.RasterXSize, raster1.RasterYSize)) orb, r1b = [x.GetRasterBand(1) for x in (oraster, raster1)] # Maximum value of output should be 2x the max of input raster self.assertEqual( orb.GetStatistics(False, True)[1], r1b.GetStatistics(False, True)[1] * 2) # Datatype of band should be Float32 (== gdal.GDT_Float32 == 6) self.assertEquals(6, orb.DataType) self.assertEquals(1.175494351E-38, orb.GetNoDataValue()) # Each pixel of output raster should equal 2x input raster # unless it is a nodata value ora, r1a = [x.ReadAsArray() for x in (orb, r1b)] for x in range(raster1.RasterXSize): for y in range(raster1.RasterYSize): if r1a[y, x] != r1b.GetNoDataValue(): self.assertEquals(ora[y, x], r1a[y, x] * 2) finally: if process: process.purge()
def test_rastermath_logical_operators(self): """ Test creation of a masked raster based on logical operators """ raster1_io = RasterFileIO(name='A', uri=os.path.join(testfile_path, 'globalairtemp.tif')) calc = 'logical_or(logical_and(A >= 27000, A <= 28000), ' \ 'logical_and(A >= 30000, A <= 31000))' process = geo.RasterMathProcess(inputs=[ raster1_io, ], calc=calc) try: process.compute() self.assertTrue(os.path.exists(process.output.uri)) oraster, raster1 = [x.read() for x in (process.output, raster1_io)] # Output raster should be same dimensions as raster 1 self.assertEquals((oraster.RasterXSize, oraster.RasterYSize), (raster1.RasterXSize, raster1.RasterYSize)) orb, r1b = [x.GetRasterBand(1) for x in (oraster, raster1)] # Maximum value of output should be 1 self.assertEqual(orb.GetStatistics(False, True)[1], 1) # Minimum value of output should be 0 self.assertEqual(orb.GetStatistics(False, True)[0], 0) # Pixels should be 1 where source is between 27K-28K or 30-31K ora, r1a = [x.ReadAsArray() for x in (orb, r1b)] self.assertTrue(ora[90, 10] == 1 and r1a[90, 10] == 30083) self.assertTrue(ora[160, 10] == 1 and r1a[160, 10] == 27074) # Pixels should be 0 where source is not between 27K-28K or 30-31K ora, r1a = [x.ReadAsArray() for x in (orb, r1b)] self.assertTrue(ora[120, 10] == 0 and r1a[120, 10] == 29623) self.assertTrue(ora[175, 10] == 0 and r1a[175, 10] == 23928) finally: if process: process.purge()
def test_subset_raster(self): """ Test SubsetProcess for vector & raster inputs """ zipfile = ZipFile(os.path.join(testfile_path, '2states.zip'), 'r') zipfile.extract('2states.geojson', testfile_path) vector_io = VectorFileIO( uri=os.path.join(testfile_path, '2states.geojson')) raster_io = RasterFileIO( uri=os.path.join(testfile_path, 'globalairtemp.tif')) process = geo.SubsetProcess(inputs=[raster_io, vector_io]) try: process.compute() self.assertEquals(type(process.output.data).__name__, 'Dataset') self.assertTrue(os.path.exists(process.output.uri)) self.assertIsNotNone(process.id) self.assertIn(process.id, process.output.uri) finally: testfile = os.path.join(testfile_path, '2states.geojson') if os.path.exists(testfile): os.remove(testfile) if process: process.purge()
class RasterMathProcess(GaiaProcess): """ Performs raster math/algebra based on supplied arguments. Inputs should consist of at least one raster IO object. Required arg is 'calc', an equation for the input rasters. Example: "A + B / (C * 2.4)". The letters in the equation should correspond to the names of the inputs. """ #: Tuple of required inputs; name, type , max # of each; None = no max required_inputs = [{ 'description': 'Image', 'type': types.RASTER, 'max': None }] #: Required arguments for the process required_args = [{ 'name': 'calc', 'title': 'Calculation', 'description': 'Equation to apply to rasters (ex: "(A+B)/2"', 'type': str }] #: Default output format for the process default_output = formats.RASTER #: Default input raster bands to process bands = None #: Default NODATA value for raster input nodata = None #: Use all bands in raster input (default: False) all_bands = False #: Default data type for raster (UInt32, Float, etc) output_type = None #: Image output format (default='GTiff') output_format = 'GTiff' def __init__(self, calc=None, **kwargs): """ Initialize a RasterMathProcess object. :param calc: A text representation of the calculation to make. :param kwargs: Other keyword arguments """ self.calc = calc super(RasterMathProcess, self).__init__(**kwargs) if not self.output: self.output = RasterFileIO(name='result', uri=self.get_outpath()) def compute(self): """ Run the RasterMath process, generating a raster output dataset. """ first = self.inputs[0] epsg = first.get_epsg() rasters = [x.read(epsg=epsg) for x in self.inputs] bands = self.bands nodata = self.nodata all_bands = self.all_bands otype = self.output_type self.output.create_output_dir(self.output.uri) self.output.data = gdal_calc(self.calc, self.output.uri, rasters, bands=bands, nodata=nodata, allBands=all_bands, output_type=otype, format=self.output_format)