def envelope(self): dataset = self.getDataset() xform = dataset.GetGeoTransform() xScale = xform[1] yScale = xform[5] width = dataset.RasterXSize height = dataset.RasterYSize ulx = xform[0] uly = xform[3] lrx = ulx + width * xScale lry = uly + height * yScale envelope = Envelope() # --- # If this file is in 4326, we must swap the x-y to conform with GDAL # 3's strict conformity to the 4326 definition. # --- srs4326 = SpatialReference() srs4326.ImportFromEPSG(4326) if srs4326.IsSame(self._dataset.GetSpatialRef()): envelope.addPoint(uly, ulx, 0, self._dataset.GetSpatialRef()) envelope.addPoint(lry, lrx, 0, self._dataset.GetSpatialRef()) else: envelope.addPoint(ulx, uly, 0, self._dataset.GetSpatialRef()) envelope.addPoint(lrx, lry, 0, self._dataset.GetSpatialRef()) return envelope
def testClipReproject(self): # Build the test file. imageFile = self._createTestFile() # Build the envelope. ulx = 367080 uly = 4209230 lrx = 509200 lry = 4095100 srs = SpatialReference() srs.ImportFromEPSG(32612) env = Envelope() env.addPoint(ulx, uly, 0, srs) env.addPoint(lrx, lry, 0, srs) # Reprojection parameter targetSRS = SpatialReference() targetSRS.ImportFromEPSG(4326) # Clip, reproject and resample. imageFile.clipReproject(env, targetSRS,) # Check the results. dataset = gdal.Open(imageFile.fileName(), gdalconst.GA_ReadOnly) if not dataset: raise RuntimeError('Unable to read ' + imageFile.fileName() + '.') xform = dataset.GetGeoTransform() xScale = xform[1] yScale = xform[5] width = dataset.RasterXSize height = dataset.RasterYSize clippedUlx = xform[0] clippedUly = xform[3] clippedLrx = clippedUlx + width * xScale clippedLry = clippedUly + height * yScale self.assertAlmostEqual(clippedUlx, -112.49369402670872, places=12) self.assertAlmostEqual(clippedUly, 38.03073206024332, places=11) self.assertAlmostEqual(clippedLrx, -110.89516946364738, places=12) self.assertAlmostEqual(clippedLry, 36.99265291293727, places=11) outSRS = SpatialReference() outSRS.ImportFromWkt(dataset.GetProjection()) self.assertTrue(outSRS.IsSame(targetSRS)) # Delete the test file. os.remove(imageFile.fileName())
def testReproject(self): # Build the test file. imageFile = self._createTestFile() # Reproject. targetSRS = SpatialReference() targetSRS.ImportFromEPSG(4326) imageFile.clipReproject(outputSRS=targetSRS) # Check the SRS. dataset = gdal.Open(imageFile.fileName(), gdalconst.GA_ReadOnly) if not dataset: raise RuntimeError('Unable to read ' + imageFile.fileName() + '.') outSRS = SpatialReference() outSRS.ImportFromWkt(dataset.GetProjection()) self.assertTrue(outSRS.IsSame(targetSRS)) # Delete the test file. os.remove(imageFile.fileName())
def convert_geometry( geometry: ogr.Geometry, new_spatialreference: osr.SpatialReference) -> ogr.Geometry: """Converts the geometry to the new spatial reference if possible Arguments: geometry - The geometry to transform new_spatialreference - The spatial reference to change to Returns: The transformed geometry or the original geometry. If either the new Spatial Reference parameter is None, or the geometry doesn't have a spatial reference, then the original geometry is returned. """ if not new_spatialreference or not geometry: return geometry return_geometry = geometry try: geom_sr = geometry.GetSpatialReference() if int(osgeo.__version__[0]) >= 3: # GDAL 3 changes axis order: https://github.com/OSGeo/gdal/issues/1546 # pylint: disable=no-member geom_sr.SetAxisMappingStrategy( osgeo.osr.OAMS_TRADITIONAL_GIS_ORDER) if geom_sr and not new_spatialreference.IsSame(geom_sr): transform = osr.CreateCoordinateTransformation( geom_sr, new_spatialreference) new_geom = geometry.Clone() if new_geom: new_geom.Transform(transform) return_geometry = new_geom except Exception as ex: logging.warning("Exception caught while transforming geometries: %s", str(ex)) logging.warning(" Returning original geometry") return return_geometry
def main(): args = docopt(__doc__, version=VERSION) logparams = {} if args['--debug']: logparams.update(level=logging.DEBUG) elif args['--info']: logparams.update(level=logging.INFO) else: logparams.update(level=logging.CRITICAL) if args['--logfile'] != '': logparams.update(filename=args['--logfile']) logging.basicConfig(**logparams) logger = logging.getLogger('extract_patches') logger.debug('input \n {}'.format(args)) assert isinstance(logger, logging.Logger) shapefiles = collect_filenames(args['-i']) if len(shapefiles) == 0: logger.error('No matching shapefiles for inoput `{}`'.format( args['-i'])) return raster = args['-r'] try: size = [int(x) for x in args['--size'].split(',')] patch_width, patch_height = size logger.debug("Set patch size to {} x {}".format( patch_width, patch_height)) except: logger.error("Unable to parse option '--size'") return try: scale = float(args['--scale']) assert scale > 0 logger.debug("Set scale to {}".format(scale)) except: logger.error("Unable to parse option '--scale'") return silent = args['--noprogress'] output_folder = args['--odir'] try: if not os.path.isdir(output_folder): os.makedirs(output_folder) logger.debug("Created output folder '{}'".format(output_folder)) else: logger.debug( "Found existing output folder '{}'".format(output_folder)) except: logger.error("Unable to find or create output directory `{}`".format( output_folder)) return if args['--ojpg']: fmt = '.jpg' else: # args['--otif'] (default) fmt = '.tif' logger.debug("Output format set to {}".format(fmt)) clip = args['--vclip'] is not None if clip: clipmin, clipmax = [float(x) for x in args['--vclip'].split(',')] logger.debug("Clipping output to [{}, {}]".format(clipmin, clipmax)) else: clipmin, clipmax = 0, 1 logger.debug( "Not clipping output -- assuming range of value is [{},{}]".format( clipmin, clipmax)) stretch = args['--vstretch'] is not None if stretch: stretchmin, stretchmax = [ float(x) for x in args['--vstretch'].split(',') ] logger.debug("Output value range will be stretched to [{},{}]".format( stretchmin, stretchmax)) else: logger.debug("Output values will not be stretched") if args['--csv']: csv_file_name = args['--csv'] if os.path.isfile(csv_file_name): logger.error( "CSV File already exists; please remove or rename it first.") logger.debug("Writing to CSV File '{}'".format(csv_file_name)) return else: csv_file_name = None logger.debug("No CSV output") # Estimate number of shape features count = 0 if not silent: pbar = ProgressBar( len(shapefiles), ['Counting Features:', Percentage(), ' ', Bar(), ' ', ETA()]) pbar.start() for i, s in enumerate(shapefiles): vector = ogr.Open(s) layer = vector.GetLayer() count += layer.GetFeatureCount() if not silent: pbar.update(i) if not silent: pbar.finish() logger.debug("Counted {} features in {} shapefiles".format( count, len(shapefiles))) # Write header for CSV file if csv_file_name is not None: with open(os.path.join(output_folder, csv_file_name), 'w') as csvf: csvf.write( 'gx, gy, r1, r2, theta, patch_width, patch_height, image_namei\n' ) with rasterio.open(raster) as rf: assert isinstance(rf, RasterReader) srs = SpatialReference(str(rf.crs_wkt)) affine = rf.affine geo_to_pixels = ~affine logging.debug("Output CRS will be '''{}'''".format( srs.ExportToPrettyWkt())) if not silent: pbar = ProgressBar( count, ['Exporting Patches:', Percentage(), ' ', Bar(), ' ', ETA()]) pbar.start() for sf in shapefiles: logger.info("Processing input '{}'".format(sf)) vector = ogr.Open(sf) assert isinstance(vector, ogr.DataSource) layer = vector.GetLayer() assert isinstance(layer, ogr.Layer) if not srs.IsSame(layer.GetSpatialRef()): logger.warning( "Coordinate system mismatch (its ok, I will reproject)") for f in layer: if not silent: pbar.update(pbar.currval + 1) geom = f.GetGeometryRef() assert isinstance(geom, ogr.Geometry) geom = geom.TransformTo(srs) points = geom.GetPoints() source = points[0] target = points[-1] sx, sy = geo_to_pixels * source tx, ty = geo_to_pixels * target if len(points) == 2: cx, cy = (sx + tx) / 2, (sy + ty) / 2 else: cx, cy = geo_to_pixels * points[1] dx, dy = (tx - sx), (ty - sy) theta = degrees( atan2(dy, dx) ) # In PIXELS, CCW from +x. Not necessarily CCW from E (or CW from N) r1 = hypot(tx - cx, ty - cy) r2 = hypot(cx - sx, cy - sy) r1, r2 = max(r1, r2), min( r1, r2 ) # For 3 points, we assume two radii. Else these are duplicates. gx, gy = affine * ( cx, cy ) # Geographic coordinates (e.g. lat lon) of the center. # We read a square slightly larger than the scaled version of our patch, so that # we can safely rotate the raster without missing pixels in the corners. box_radius = hypot(patch_width, patch_height) / (2.0 * scale) x0, x1 = int(floor(cx - box_radius)), int(ceil(cx + box_radius)) y0, y1 = int(floor(cy - box_radius)), int(ceil(cy + box_radius)) # save patch... kwargs = rf.meta patch_affine = ( affine * Affine.translation(cx, cy) * Affine.rotation(angle=-theta) * Affine.translation(-patch_width / 2., -patch_height / 2.)) if fmt == '.tif': kwargs.update(driver='GTiff', compress='lzw', dtype=numpy.float32) elif fmt == '.jpg': kwargs.update(driver='JPEG', quality=90, dtype=numpy.uint8) kwargs.update(transform=patch_affine, width=patch_width, height=patch_height) box_radius *= scale name = hashlib.md5(str(patch_affine) + raster).hexdigest() image_name = os.path.join(output_folder, name + fmt) if csv_file_name is not None: with open(os.path.join(output_folder, csv_file_name), 'a+') as csvf: fields = gx, gy, r1, r2, theta, patch_width, patch_height, image_name csvf.write(','.join([str(_) for _ in fields]) + '\n') with rasterio.open(image_name, 'w', **kwargs) as pf: assert isinstance(pf, RasterUpdater) for band in range(rf.count): patch = rf.read( band + 1, window=((y0, y1), (x0, x1)), boundless=True, ) patch = patch.astype(numpy.float32) patch_rotated = rotate(patch, theta, reshape=False) patch_scaled = zoom(patch_rotated, scale) i0 = int(round(box_radius - patch_height / 2.)) i1 = i0 + patch_height j0 = int(round(box_radius - patch_width / 2.)) j1 = j0 + patch_width patch_cropped = patch_scaled[i0:i1, j0:j1] if clip: patch_cropped = numpy.clip(patch_cropped, clipmin, clipmax) if stretch: patch_cropped = (patch_cropped - clipmin) / (clipmax - clipmin) patch_cropped = patch_cropped * ( stretchmax - stretchmin) + stretchmin if fmt == '.jpg': # JPEG does not support floating point output. All we can do is 8 bit # (python has not 12bit array type) patch_cropped = img_as_ubyte( patch_cropped.clip(-1, 1)) pf.write(patch_cropped, band + 1) if not silent: pbar.finish() logger.debug("Finished.")