def clip_raster(rast, gt, points): # from http://geospatialpython.com/ minX, minY, maxX, maxY = get_shape_extent(points) # Convert the layer extent to image pixel coordinate ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = rast[:, ulY:lrY, ulX:lrX] #print [x for x in clip.shape] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. pixels = [] for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) print pixels raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes mask = np.array(list(raster_poly.getdata())).reshape(clip.shape[1:]) # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint8) return clip
def clip_raster(rastarray, geotransform, poly): # from http://geospatialpython.com/ rast = rastarray#rast.ReadAsArray() gt = geotransform#rast.GetGeoTransform() minX, minY, maxX, maxY = poly.bbox # Convert the layer extent to image pixel coordinates #minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = rast[:, ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. pixels = [] points = poly.points for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes mask = image_to_array(raster_poly) # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, np.nan)).astype(gdalnumeric.uint8) return clip
def clip(poly, gt, data): minX, maxX = min(poly.envelope.exterior.coords.xy[0]), max( poly.envelope.exterior.coords.xy[0]) minY, maxY = min(poly.envelope.exterior.coords.xy[1]), max( poly.envelope.exterior.coords.xy[1]) uper_left_X, uper_left_Y = geo2pixel((minX, maxY), gt) lower_right_X, lower_right_Y = geo2pixel((maxX, minY), gt) pxWidth = int(lower_right_X - uper_left_X) pxHeight = int(lower_right_Y - uper_left_Y) #根据外接矩形裁剪 clip = data.ReadAsArray(int(uper_left_X), int(uper_left_Y), int(pxWidth), int(pxHeight)) gt2 = list(gt) gt2[0] = minX gt2[3] = maxY ext_pix = np.array( [geo2pixel(points, gt2) for points in poly.exterior.coords]) ext_pix = np.expand_dims(ext_pix, axis=0) mask = np.ones([pxHeight, pxWidth], np.uint8) mask = cv2.fillPoly(mask, ext_pix, 0) #介绍CV2.fillploy() clip = gdalnumeric.choose(mask, (clip, 0)) return clip
def clip_raster(rastarray, geotransform, poly): # from http://geospatialpython.com/ rast = rastarray #rast.ReadAsArray() gt = geotransform #rast.GetGeoTransform() minX, minY, maxX, maxY = poly.bbox # Convert the layer extent to image pixel coordinates #minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = rast[:, ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. pixels = [] points = poly.points for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes mask = image_to_array(raster_poly) # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, np.nan)).astype(gdalnumeric.uint8) return clip
def main(shapefile_path, raster_path, fileName): # 读取栅格影像路径 srcArray = gdalnumeric.LoadFile(raster_path) # 读取栅格据 srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # 读取矢量图形数据路径 shapef = ogr.Open(shapefile_path) lyr = shapef.GetLayer( os.path.split(os.path.splitext(shapefile_path)[0])[1]) poly = lyr.GetNextFeature() # 矢量图形坐标换算 minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # 计算新生成图像大小 pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[:, ulY:lrY, ulX:lrX] xoffset = ulX yoffset = ulY print("Xoffset, Yoffset = ( %f, %f )" % (xoffset, yoffset)) # 创建geomatrix geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # 创建一张黑白遮罩图像,将矢量点集映射到像素上 points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # 裁剪遮罩 clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.int16) clip = clip.astype(gdalnumeric.int16) #加载GTiff驱动,存储结果为tiff图像 gtiffDriver = gdal.GetDriverByName('GTiff') if gtiffDriver is None: raise ValueError("Can't load GeoTiff Driver") print(type(clip)) gdalnumeric.SaveArray(clip, fileName, format="GTiff") print("裁剪完毕") gdal.ErrorReset()
def clip_as_array(self, shape): ul, lr = self.clipbounds(shape) #upper left, lower right ulx, uly = ul lrx, lry = lr width = int(lrx - ulx) height = int(lry - uly) # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. pixels = [] shape_geom = shape.polygon.GetGeometryRef() shape_points = shape_geom.GetGeometryRef(0) for p in range(shape_points.GetPointCount()): p = (shape_points.GetX(p), shape_points.GetY(p)) pxx, pxy = self.coord2pixel(p) if pxx < ulx and pxy < uly: pixels.append((ulx, uly)) elif pxx < ulx and pxy >= uly: pixels.append((ulx, pxy)) elif pxx >= ulx and pxy < uly: pixels.append((pxx, uly)) elif pxx > lrx and pxy > lry: pixels.append((lrx, uly)) elif pxx > lrx and pxy <= lry: pixels.append((lrx, pxy)) elif pxx <= lrx and pxy > lry: pixels.append((pxx, lry)) else: pixels.append((pxx, pxy)) image = Image.new("L", (width, height), 1) rasterize = ImageDraw.Draw(image) rasterize.polygon(pixels, 0) mask = imageToArray(image) data = gdalnumeric.LoadFile(self.filepath) clipped_data = data[uly:lry, ulx:lrx] gdal.ErrorReset() return gdalnumeric.choose(mask, (clipped_data, 255)).astype(gdalnumeric.uint8)
def main(delete): source=r"D:\Program Files\Python学习文档\samples\NDVI\farm.tif" target=r"D:\Program Files\Python学习文档\samples\NDVI\Clip_farm.tif" shp=r"D:\Program Files\Python学习文档\samples\NDVI\field.shp" output=r"D:\Program Files\Python学习文档\samples\NDVI\clip_ndvi.tif" compute_band(source,target) srcArray = gdalnumeric.LoadFile(target) srcImage = gdal.Open(target) geoTrans = srcImage.GetGeoTransform() shapef = ogr.Open(shp) lyr = shapef.GetLayer(os.path.split(os.path.splitext(shp)[0] )[1] ) poly = lyr.GetNextFeature() minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = World2Pixel(geoTrans, minX, maxY) lrX, lrY = World2Pixel(geoTrans, maxX, minY) pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[ulY:lrY, ulX:lrX] xoffset = ulX yoffset = ulY print("Xoffset, Yoffset = ( %f, %f )" % ( xoffset, yoffset )) geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(World2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = ImageToArray(rasterPoly) clip = gdalnumeric.choose(mask,(clip, 0)).astype(gdalnumeric.uint8) gtiffDriver = gdal.GetDriverByName( 'GTiff' ) if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") gtiffDriver.CreateCopy(output,OpenArray( clip, prototype_ds=target, xoff=xoffset, yoff=yoffset )) if delete and os.path.exists(target): os.remove(target)
def clipImage(raster, sourceImagePath, outputImagePath): def imageToArray(i): """ Converts a Python Imaging Library array to a gdalnumeric image. """ a=gdalnumeric.fromstring(i.tostring(),'b') a.shape=i.im.size[1], i.im.size[0] return a def arrayToImage(a): """ Converts a gdalnumeric array to a Python Imaging Library Image. """ i=Image.fromstring('L',(a.shape[1],a.shape[0]), (a.astype('b')).tostring()) return i def world2Pixel(geoMatrix, x, y): """ Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate """ ulX = geoMatrix[0] ulY = geoMatrix[3] xDist = geoMatrix[1] yDist = geoMatrix[5] rtnX = geoMatrix[2] rtnY = geoMatrix[4] pixel = int((x - ulX) / xDist) line = int((y - ulY) / yDist) return (pixel, line) def getGeometryExtent(points): ## Convert the layer extent to image pixel coordinates V2? minX = min(points, key=lambda x: x[0])[0] maxX = max(points, key=lambda x: x[0])[0] minY = min(points, key=lambda x: x[1])[1] maxY = max(points, key=lambda x: x[1])[1] return minX, maxX, minY, maxY ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### srcImage = gdal.Open(sourceImagePath + raster + '.jp2') gdal.Warp(sourceImagePath + raster + '_WGS84.jp2', srcImage, dstSRS='EPSG:4326') ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### srcImage = gdal.Open(sourceImagePath + raster + '_WGS84.jp2') srcArray = gdalnumeric.LoadFile(sourceImagePath + raster + '_WGS84.jp2') geoTrans = srcImage.GetGeoTransform() sourceMinRasterX = geoTrans[0] xPixelSize = geoTrans[1] sourceMaxRasterY = geoTrans[3] yPixelSize = geoTrans[5] sourceRasterHeight = srcImage.RasterYSize sourceRasterWidth = srcImage.RasterXSize sourceMaxRasterX = sourceMinRasterX+(sourceRasterWidth*xPixelSize) sourceMinRasterY = sourceMaxRasterY+(sourceRasterHeight*yPixelSize) # Create an OGR layer from a boundary shapefile shapefile = ogr.Open("%s.shp" % shp) lyr = shapefile.GetLayer("PL") poly = lyr.GetNextFeature() cutterGeometry = poly.GetGeometryRef() rasterWKT = "POLYGON ((%s %s, %s %s, %s %s, %s %s, %s %s))" % (str(sourceMinRasterX), str(sourceMaxRasterY), str(sourceMaxRasterX), str(sourceMaxRasterY), str(sourceMaxRasterX), str(sourceMinRasterY), str(sourceMinRasterX), str(sourceMinRasterY), str(sourceMinRasterX), str(sourceMaxRasterY)) rasterGeometry = ogr.CreateGeometryFromWkt(rasterWKT) shapei = cutterGeometry.Intersection(rasterGeometry) pts = shapei.GetGeometryRef(0) points = [] for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) minX, maxX, minY, maxY = getGeometryExtent(points) ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) if (ulX <0): ulX = 0 if (ulY <0): ulY = 0 if (lrX > sourceRasterWidth): lrX = sourceRasterWidth if (lrY > sourceRasterHeight): lrY = sourceRasterHeight pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY pixels = [] for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### try: clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16 ) except ValueError: clip = mask ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### dst_filename = "%s.tif" % output #pxWidth = lrX - ulX #pxHeight = lrY - ulY driver = gdal.GetDriverByName('GTiff') dataset = driver.Create(outputImagePath + raster + '.tif' ,pxWidth, pxHeight, 1,gdal.GDT_UInt16) dataset.GetRasterBand(1).WriteArray(clip) proj=srcImage.GetProjection() dataset.SetGeoTransform(geoTrans) dataset.SetProjection(proj) dataset.FlushCache() dataset=None
def downloadImage(request, result_id, band): if request.method == 'GET': resultImg = models.QueryResult.objects.filter(pk=result_id).first() if resultImg == None: raise Http404 tiles = list(resultImg.tileMatrix) src_srs = osr.SpatialReference() src_srs.ImportFromWkt(tiles[0].image.wkt) tgt_srs = osr.SpatialReference() tgt_srs.ImportFromEPSG(4326) tgt_srs = src_srs.CloneGeogCS() preClipDS, preClipSize, preClipGeoTransform = GetPreClipImage( tiles, band, resultImg.imageName, src_srs, tgt_srs) # print preClipGeoTransform # Raster of input polygons rasterPoly = Image.new("L", (preClipSize[0], preClipSize[1]), 1) rasterize = ImageDraw.Draw(rasterPoly) inputPolygons = resultImg.inputPolygons.polygons mostULx = mostLRx = mostULy = mostLRy = None for polygon in inputPolygons: pixels = [] inputPolygonReprojected = ReprojectCoords( polygon['coordinates'][0], tgt_srs, src_srs) for p in inputPolygonReprojected: pixels.append(world2Pixel(preClipGeoTransform, p[0], p[1])) pixels = intersectPolygonToBorder(pixels, preClipSize[0], preClipSize[1]) if pixels is None: continue print pixels if mostULx == None or \ mostLRx == None or \ mostULy == None or \ mostLRy == None: mostULx = mostLRx = pixels[0][0] mostULy = mostLRy = pixels[0][1] for x, y in pixels: if x > mostLRx: mostLRx = x if x < mostULx: mostULx = x if y < mostULy: mostULy = y if y > mostLRy: mostLRy = y # mostULx, mostULy = world2Pixel(preClipGeoTransform, mostULx, mostULy) # mostLRx, mostLRy = world2Pixel(preClipGeoTransform, mostLRx, mostLRy) mostULx = 0 if mostULx < 0 else mostULx mostLRx = 0 if mostLRx < 0 else mostLRx mostULy = 0 if mostULy < 0 else mostULy mostLRy = 0 if mostLRy < 0 else mostLRy rasterize.polygon(pixels, 0) print '%i %i %i %i' % (mostULx, mostULy, mostLRx, mostLRy) # clipped the output dataset by minimum rect clip = preClipDS.GetRasterBand(1).ReadAsArray( 0, 0, preClipSize[0], preClipSize[1])[mostULy:mostLRy, mostULx:mostLRx] # create mask to clip image by polygon mask = imageToArray(rasterPoly)[mostULy:mostLRy, mostULx:mostLRx] # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16) finalFile = NamedTemporaryFile(suffix='.tif', prefix=resultImg.imageName + '-' + str(band)) gdalnumeric.SaveArray(clip, str(finalFile.name), format="GTiff") clippedGeoTransform = [ preClipGeoTransform[0] + mostULx * preClipGeoTransform[1], preClipGeoTransform[1], preClipGeoTransform[2], preClipGeoTransform[3] + mostULy * preClipGeoTransform[5], preClipGeoTransform[4], preClipGeoTransform[5] ] ds = gdal.Open(str(finalFile.name), gdal.GA_Update) ds.SetGeoTransform(clippedGeoTransform) ds.SetProjection(src_srs.ExportToWkt()) # Return HttpResponse Image wrapper = FileWrapper(finalFile) content_type = mimetypes.guess_type(finalFile.name)[0] response = StreamingHttpResponse(wrapper, content_type='content_type') response[ 'Content-Disposition'] = "attachment; filename=%s" % finalFile.name return response # return HttpResponse(json.dumps(dict(out=output_geo_transform, # ext=ext, # finalXSize=finalXSize, # finalYSize=finalYSize))) raise Http404
else: Usage() i = i + 1 if infile is None: Usage() if outfile is None: Usage() if inNoData is None: Usage() if outNoData is None: Usage() indataset = gdal.Open( infile, GA_ReadOnly ) out_driver = gdal.GetDriverByName(format) outdataset = out_driver.Create(outfile, indataset.RasterXSize, indataset.RasterYSize, indataset.RasterCount, type) for iBand in range(1, indataset.RasterCount + 1): inband = indataset.GetRasterBand(iBand) outband = outdataset.GetRasterBand(iBand) for i in range(inband.YSize - 1, -1, -1): scanline = inband.ReadAsArray(0, i, inband.XSize, 1, inband.XSize, 1) scanline = gdalnumeric.choose( gdalnumeric.equal( scanline, inNoData), (scanline, outNoData) ) outband.WriteArray(scanline, 0, i)
def run(bands, map_mask, dst_dir): cropped_bands = [] for band in bands: # http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html#clip-a-geotiff-with-shapefile # http://karthur.org/2015/clipping-rasters-in-python.html # https://gis.stackexchange.com/questions/228602/clip-raster-by-mask-without-change-values # http://karthur.org/2015/clipping-rasters-in-python.html # Copy the file corresponding to the band in the destination directory for the bands band_dir, band_filename = os.path.split(band) shutil.copy(band, dst_dir) # raster_path es our source band raster_path = os.path.join(dst_dir, band_filename) if band_filename.endswith('.jp2'): raster_gtiff = raster_path.replace('.jp2', '.tiff') jp2_to_gtiff(raster_path, raster_gtiff) raster_path = raster_gtiff # Load the source data as a gdalnumeric array rast = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdalnumeric.gdal.Open(raster_path) gt = srcImage.GetGeoTransform() srcImage = None # Create an OGR layer from a boundary shapefile shapef = ogr.Open(map_mask) lyr = shapef.GetLayer( os.path.split(os.path.splitext(map_mask)[0])[1]) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # In such a case... ulY ends up being negative--can't have that! iY = ulY ulY = 0 try: # Multi-band image? clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: # Nope: Must be single-band clip = rast[ulY:lrY, ulX:lrX] # create pixel offset to pass to new image Projection info xoffset = ulX yoffset = ulY # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # The clip features were "pushed down" to match the bounds of the # raster; this step "pulls" them back up premask = image_to_array(raster_poly) # We slice out the piece of our clip features that are "off the map" mask = np.ndarray( (premask.shape[-2] - abs(iY), premask.shape[-1]), premask.dtype) mask[:] = premask[abs(iY):, :] mask.resize(premask.shape) # Then fill in from the bottom # Most importantly, push the clipped piece down gt2[3] = maxY - (maxY - gt[3]) else: mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, 0)) clip = clip.astype(gdalnumeric.numpy.float32) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, 0)) clip = clip.astype(gdalnumeric.numpy.float32) # Save new tiff raster_name, raster_ext = os.path.splitext(band_filename) mask_dir, mask_file = os.path.split(map_mask) mask_name, mask_ext = os.path.splitext(mask_file) cropped_band = os.path.join( dst_dir, raster_name + '-' + mask_name + '.tiff') gtiff_driver = gdalnumeric.gdal.GetDriverByName('GTiff') if gtiff_driver is None: raise ValueError("Can't find GeoTiff Driver") a = open_array(clip, prototype_ds=raster_path, xoff=xoffset, yoff=yoffset) gtiff_driver.CreateCopy(cropped_band, a) gdalnumeric.gdal.ErrorReset() cropped_bands.append(cropped_band) # Remove the files from the auxiliary bands copied to the destination directory os.remove(raster_path) raster_path = raster_path.replace('.tiff', '.jp2') if os.path.exists(raster_path): os.remove(raster_path) return cropped_bands
def main(shapefile_path, raster_path): # Load the source data as a gdalnumeric array srcArray = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile shapef = ogr.Open(shapefile_path) lyr = shapef.GetLayer( os.path.split(os.path.splitext(shapefile_path)[0])[1]) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[ulY:lrY, ulX:lrX] # # EDIT: create pixel offset to pass to new image Projection info # xoffset = ulX yoffset = ulY print("Xoffset, Yoffset = ( %f, %f )" % (xoffset, yoffset)) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask # clip = gdalnumeric.choose(mask, \ # (clip, 0)).astype(gdalnumeric.uint8) clip = gdalnumeric.choose(mask, (clip, 0)) real = np.zeros(clip.shape) for i in range(len(clip)): for j in range(len(clip[i])): val = clip[i][j].real if (val < -4): val = -4 real[i, j] = val dst_ds = gdal.GetDriverByName('GTiff').Create("hello86568.tif", 300, 300, 1, gdal.GDT_CFloat32) # dst_ds.SetGeoTransform([444720, 30, 0, 3751320, 0, -30]) raster = np.zeros(real.shape, dtype=np.float32) dst_ds.GetRasterBand(1).WriteArray(real) # Once we're done, close properly the dataset dst_ds = None # This image has 3 bands so we stretch each one to make them # visually brighter # for i in range(3): clip2 = stretch(clip) # Save new tiff # # EDIT: instead of SaveArray, let's break all the # SaveArray steps out more explicity so # we can overwrite the offset of the destination # raster # ### the old way using SaveArray # # gdalnumeric.SaveArray(clip, "OUTPUT.tif", format="GTiff", prototype=raster_path) # ### # # gtiffDriver = gdal.GetDriverByName('GTiff') # if gtiffDriver is None: # raise ValueError("Can't find GeoTiff Driver") # gtiffDriver.CreateCopy("beijing9.tif", # gdal_array.OpenArray(clip, prototype_ds=raster_path) # ) # real = np.zeros(clip.shape) # for i in range(len(clip)): # for j in range(len(clip[i])): # val = clip[i][j].real # real[i, j] = val # draw(real) # Save as an 8-bit jpeg for an easy, quick preview clip3 = clip2.astype(gdalnumeric.uint8) gdalnumeric.SaveArray(clip3, "beijing.jpg", format="JPEG") # misc.imsave("beijing7.png", clip2) gdal.ErrorReset()
# 地图上的点到用在空白的8位黑白掩模图像上绘制边界的像素 points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # 用掩模裁剪图像 clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint8) # 这个图像有3个波段,因此我们得拉伸每一个波段使得他们有更好的可视化效果 for i in range(3): clip[i, :, :] = stretch(clip[i, :, :]) # 将ndvi另存为tiff gdalnumeric.SaveArray(clip, "%s.tiff" % output, format="GTiff", prototype=raster) # 将ndvi保存为8位的jpeg,以便于快速预览 clip = clip.astype(gdalnumeric.uint8) gdalnumeric.SaveArray(clip, "%s.jpg" % output, format="JPEG")
def crop(input_file, extents, geo_trans=None, nodata=np.nan): """ Adapted from http://karthur.org/2015/clipping-rasters-in-python.html Clips a raster (given as either a gdal.Dataset or as a numpy.array instance) to a polygon layer provided by a Shapefile (or other vector layer). If a numpy.array is given, a "GeoTransform" must be provided (via dataset.GetGeoTransform() in GDAL). Returns an array. Clip features must be a dissolved, single-part geometry (not multi-part). Modified from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html #clip-a-geotiff-with-shapefile Arguments: rast A gdal.Dataset or a NumPy array features_path The path to the clipping features geo_trans An optional GDAL GeoTransform to use instead nodata The NoData value; defaults to -9999. :param str input_file: input image file path :param list extents: extents for the cropped area :param list geo_trans: An optional GDAL GeoTransform to use instead :param int nodata: The NoData value; defaults to -9999 :return: clip: cropped part of the image :rtype: ndarray :return: gt2: geotransform parameters for the cropped image :rtype: list """ def image_to_array(i): """ Converts a Python Imaging Library (PIL) array to a gdalnumeric image. """ arr = gdalnumeric.frombuffer(i.tobytes(), 'b') arr.shape = i.im.size[1], i.im.size[0] return arr raster = gdal.Open(input_file) # Can accept either a gdal.Dataset or numpy.array instance if not isinstance(raster, np.ndarray): if not geo_trans: geo_trans = raster.GetGeoTransform() raster = raster.ReadAsArray() else: if not geo_trans: raise ValueError('geo transform must be supplied') # Convert the layer extent to image pixel coordinates min_x, min_y, max_x, max_y = extents ul_x, ul_y = world_to_pixel(geo_trans, min_x, max_y) lr_x, lr_y = world_to_pixel(geo_trans, max_x, min_y) # Calculate the pixel size of the new image px_width = int(lr_x - ul_x) px_height = int(lr_y - ul_y) # If the clipping features extend out-of-bounds and ABOVE the raster... if geo_trans[3] < max_y: # In such a case... ul_y ends up being negative--can't have that! # iY = ul_y ul_y = 0 # Multi-band image? try: clip = raster[:, ul_y:lr_y, ul_x:lr_x] except IndexError: clip = raster[ul_y:lr_y, ul_x:lr_x] # Create a new geomatrix for the image gt2 = list(geo_trans) gt2[0] = min_x gt2[3] = max_y # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_y, max_y)] pixels = [] for point in points: pixels.append(world_to_pixel(gt2, point[0], point[1])) raster_poly = Image.new('L', size=(px_width, px_height), color=1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) raster = None return clip, gt2
def ShapeClipRaster(shapefile_filename, FLAT, FLON, srcArray, resolutionX=0.01, resolutionY=0.01): if not os.path.isfile(shapefile_filename): print("%s is not exist, will be exit!!!" % shapefile_filename) exit(3) inShp = shapefile.Reader(shapefile_filename) # 获取shapefile文件经纬度范围 minX, minY, maxX, maxY = inShp.bbox print('minX, maxX, minY, maxY:', minX, maxX, minY, maxY) # 获取裁剪区域范围的经纬度 if minX < np.nanmin(FLON): minX = np.nanmin(FLON) if maxX > np.nanmax(FLON): maxX = np.nanmax(FLON) if minY < np.nanmin(FLAT): minY = np.nanmin(FLAT) if maxY > np.nanmax(FLAT): maxY = np.nanmax(FLAT) # 计算裁剪区域范围的行列号 ulX = Calculate_IJ(FLON[0, 0], minX, resolutionX) ulY = Calculate_IJ(FLAT[0, 0], maxY, resolutionY) lrX = Calculate_IJ(FLON[0, 0], maxX, resolutionX) lrY = Calculate_IJ(FLAT[0, 0], minY, resolutionY) print('ulX, lrX, ulY, lrY:', ulX, lrX, ulY, lrY) # 根据shapefile文件的范围对原始数据进行切片 pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) print(" pxHeight, pxWidth:", pxHeight, pxWidth) if len(srcArray.shape) == 3: Level, Row, Pix = srcArray.shape clip = srcArray[:, ulY:lrY, ulX:lrX] elif len(srcArray.shape) == 2: Row, Pix = srcArray.shape clip = srcArray[ulY:lrY, ulX:lrX] else: print("Input Data Dims is not 2 or 3!!!") return -1 xoffset = ulX yoffset = ulY print("Xoffset, Yoffset = ( %d, %d )" % (xoffset, yoffset)) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) for shape in inShp.shapes(): partCount = len(shape.parts) print(partCount) # 处理除最后一个部分之外的其他部分 for i in range(partCount - 1): pixels = [] for j in range(shape.parts[i], shape.parts[i + 1] - 1): pX = Calculate_IJ(minX, shape.points[j][0], resolutionX) pY = Calculate_IJ(maxY, shape.points[j][1], resolutionY) pixels.append((pX, pY)) rasterize.polygon(pixels, 0) mask = ImageToArray(rasterPoly) clip = gdalnumeric.choose(mask, (clip, 0)) # clip = clip.astype(gdalnumeric.uint8) # clip[clip == 0] = np.nan # clip[clip > 1] = np.nan return clip
def clip_raster1(shapefile_path, raster_path): ''' This function will convert the rasterized clipper shapefile to a mask for use within GDAL. This comes (with slight modification) from: https://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html#clip-a-geotiff-with-shapefile which is an updated version of: http://geospatialpython.com/2011/02/clip-raster-using-shapefile.html ''' def imageToArray(i): """ Converts a Python Imaging Library array to a gdalnumeric image. """ a = gdalnumeric.fromstring(i.tostring(), 'b') a.shape = i.im.size[1], i.im.size[0] return a def arrayToImage(a): """ Converts a gdalnumeric array to a Python Imaging Library Image. """ i = Image.fromstring('L', (a.shape[1], a.shape[0]), (a.astype('b')).tostring()) return i def world2Pixel(geoMatrix, x, y): """ Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate """ ulX = geoMatrix[0] ulY = geoMatrix[3] xDist = geoMatrix[1] yDist = geoMatrix[5] rtnX = geoMatrix[2] rtnY = geoMatrix[4] pixel = int((x - ulX) / xDist) line = int((ulY - y) / xDist) return (pixel, line) # EDIT: this is basically an overloaded # version of the gdal_array.OpenArray passing in xoff, yoff explicitly # so we can pass these params off to CopyDatasetInfo # def OpenArray(array, prototype_ds=None, xoff=0, yoff=0): ds = gdal.Open(gdalnumeric.GetArrayFilename(array)) if ds is not None and prototype_ds is not None: if type(prototype_ds).__name__ == 'str': prototype_ds = gdal.Open(prototype_ds) if prototype_ds is not None: gdalnumeric.CopyDatasetInfo(prototype_ds, ds, xoff=xoff, yoff=yoff) return ds def histogram(a, bins=range(0, 256)): """ Histogram function for multi-dimensional array. a = array bins = range of numbers to match """ fa = a.flat n = gdalnumeric.searchsorted(gdalnumeric.sort(fa), bins) n = gdalnumeric.concatenate([n, [len(fa)]]) hist = n[1:] - n[:-1] return hist def stretch(a): """ Performs a histogram stretch on a gdalnumeric array image. """ hist = histogram(a) im = arrayToImage(a) lut = [] for b in range(0, len(hist), 256): # step size step = reduce(operator.add, hist[b:b + 256]) / 255 # create equalization lookup table n = 0 for i in range(256): lut.append(n / step) n = n + hist[i + b] im = im.point(lut) return imageToArray(im) # Load the source data as a gdalnumeric array srcArray = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile shapef = ogr.Open(shapefile_path) lyr = shapef.GetLayer( os.path.split(os.path.splitext(shapefile_path)[0])[1]) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[:, ulY:lrY, ulX:lrX] # # EDIT: create pixel offset to pass to new image Projection info # xoffset = ulX yoffset = ulY print("Xoffset, Yoffset = ( %f, %f )" % (xoffset, yoffset)) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.uint8) # This image has 3 bands so we stretch each one to make them # visually brighter for i in range(3): clip[i, :, :] = stretch(clip[i, :, :]) # Save new tiff # # EDIT: instead of SaveArray, let's break all the # SaveArray steps out more explicity so # we can overwrite the offset of the destination # raster # ### the old way using SaveArray # # gdalnumeric.SaveArray(clip, "OUTPUT.tif", format="GTiff", # prototype=raster_path) # ### # gtiffDriver = gdal.GetDriverByName('GTiff') if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") gtiffDriver.CreateCopy( "OUTPUT.tif", OpenArray(clip, prototype_ds=raster_path, xoff=xoffset, yoff=yoffset)) # Save as an 8-bit jpeg for an easy, quick preview clip = clip.astype(gdalnumeric.uint8) gdalnumeric.SaveArray(clip, "OUTPUT.jpg", format="JPEG") gdal.ErrorReset() return (clip, ulX, ulY, geoTrans)
def initialClip(self, shapef=None, lyr=None, openfile=True): DriverName = "ESRI Shapefile" driver = ogr.GetDriverByName(DriverName) if openfile: # Create an OGR layer from a boundary shapefile shapef = driver.Open('%s.shp' % self.countryshp) lyr = shapef.GetLayer() geoTrans = self.srcImage.GetGeoTransform() poly = lyr.GetNextFeature() minX, maxX, minY, maxY = poly.GetGeometryRef().GetEnvelope() ulX, ulY = self.world2Pixel(geoTrans, minX, maxY) lrX, lrY = self.world2Pixel(geoTrans, maxX, minY) # Include offset to position correctly within overall image xoffset = ulX yoffset = ulY # Correction for countries that exceed satellite dataset boundaries if ulY < 0: ulY = 0 yoffset = 0 maxY = 75. # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = self.srcArray[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Create new mask image for each province rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) geom = poly.GetGeometryRef() for ring in range(geom.GetGeometryCount()): points = [] pixels = [] geom_poly = geom.GetGeometryRef(ring) # If picking the feature gets a polygon, there are islands, # go down another level to get LINEARRING if geom_poly.GetGeometryName() == "POLYGON": pts = geom_poly.GetGeometryRef(0) else: pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(self.world2Pixel(geoTrans, p[0], p[1])) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = self.imageToArray(rasterPoly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.uint32) except: print('%s exceeds the boundaries of the satellite dataset' % poly.GetField('name')) sys.exit() # Save clipped province image province_name = poly.GetField('name') gtiffDriver = gdal.GetDriverByName( 'GTiff' ) if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") if not os.path.exists(self.output): os.makedirs(self.output) gtiffDriver.CreateCopy( "%s%s.tif" % (self.output, province_name), self.OpenArray( clip, prototype_ds=self.raster, xoff=xoffset, yoff=yoffset ) ) return '%s%s.tif' % (self.output, province_name)
geo_trans = ds.GetGeoTransform() w = ds.RasterXSize h = ds.RasterYSize img_shape = [h, w] proj = ds.GetProjection() cls_l8s2 = ds.GetRasterBand(1).ReadAsArray() cls_s2 = ds.GetRasterBand(2).ReadAsArray() cmask = ds.GetRasterBand(3).ReadAsArray().astype(np.int8) cmask[cmask == 2] = 0 print(np.max(cmask), np.min(cmask)) cls_l8s2[cls_l8s2 == 3] = 33 cls_l8s2[cls_l8s2 == 2] = 3 cls_l8s2[cls_l8s2 == 33] = 2 cliped = gdalnumeric.choose(cmask, (cls_s2, cls_l8s2)) print("rice: ", len(cliped[cliped == 1])) print("soybean: ", len(cliped[cliped == 2])) print("corn: ", len(cliped[cliped == 3])) # build output path outpath = img_path.replace(".tif", "_masked.tif") # write output into tiff file out_ds = gdal.GetDriverByName("GTiff").Create(outpath, w, h, 1, gdal.GDT_Byte) out_ds.SetProjection(ds.GetProjection()) out_ds.SetGeoTransform(geo_trans) out_ds.GetRasterBand(1).WriteArray(cliped) out_ds.FlushCache() print("done")
def clip_raster(rast_path, features_path, nodata=-9999): """Clip raster to polygon. Args: rast_path (str): path to raster file features_path (str): path to features file or geojson string nodata: the no data value Returns: (numpy array, GeoTransform) Notes: Oddly, the "features path" can be either a filename OR a geojson string. GDAL seems to figure it out and do the right thing. """ rast = gdal.Open(rast_path) band = rast.GetRasterBand(1) rast_xsize = band.XSize rast_ysize = band.YSize gt = rast.GetGeoTransform() #Open Features and get all the necessary data for clipping #features = ogr.Open(open(features_path).read()) features = ogr.Open(features_path) if features.GetDriver().GetName() == 'ESRI Shapefile': lyr = features.GetLayer( os.path.split(os.path.splitext(features_path)[0])[1]) else: lyr = features.GetLayer() poly = lyr.GetNextFeature() minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) if pxWidth < 0: pxWidth = -pxWidth if pxHeight < 0: pxHeight = -pxHeight # If the clipping features extend out-of-bounds and # ABOVE the raster... # We don't want negative values if gt[3] < maxY: iY = ulY ulY = 0 # Ensure bounding box doesn't exceed the boundary of the geoTIFF if ulX < 0: ulX = 0 if ulY < 0: ulY = 0 if ulX + pxWidth > rast_xsize: pxWidth = rast_xsize - ulX if ulY + pxHeight > rast_ysize: pxHeight = rast_ysize - ulY clip = rast.ReadAsArray(ulX, ulY, pxWidth, pxHeight) # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. The canvas has the size of # pixWidth and pixHeight, the things that are not on the ploy # lines will be filled with 1 and on the poly lines will be # filled 0. # We start from creating a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) while pts.GetPointCount() == 0: pts = pts.GetGeometryRef(0) for p in range(pts.GetPointCount()): pixels.append(world_to_pixel(gt2, pts.GetX(p), pts.GetY(p))) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes if gt[3] < maxY: premask = image_to_array(raster_poly) mask = np.ndarray((premask.shape[-2] - abs(iY), premask.shape[-1]), premask.dtype) mask[:] = premask[abs(iY):, :] mask.resize(premask.shape) # Then fill in from the bottom gt2[3] = maxY - (maxY - gt[3]) else: mask = image_to_array(raster_poly) # Clip the image using the mask, no data is used to fill # the unbounded areas. try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and # BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) # TODO: I think this is provided above as gt2 # newGT = pixel_to_world(gt, ulX, ulY) return clip, gt2
def clip_image_to_shape(source_image_path, output_image_path): def image_to_array(pil_array): """ Converts a Python Imaging Library (PIL) array to a gdalnumeric image. """ gdal_numeric_array = gdalnumeric.fromstring(pil_array.tobytes(), 'b') gdal_numeric_array.shape = pil_array.im.size[1], pil_array.im.size[0] return gdal_numeric_array def split_path(source_path): file_dir = os.path.split(source_path)[0] file_name = os.path.split(source_path)[1] file_extension = os.path.splitext(file_name)[1] file_name = os.path.splitext(file_name)[0] print(file_name) return file_dir, file_name, file_extension def get_geometry_extent(polygons): xs = [] ys = [] for polygon in polygons: for point in polygon: xs.append(point[0]) ys.append(point[1]) min_x = min(xs) max_x = max(xs) min_y = min(ys) max_y = max(ys) # min_x = min(points, key=lambda x: x[0])[0] # max_x = max(points, key=lambda x: x[0])[0] # min_y = min(points, key=lambda x: x[1])[1] # max_y = max(points, key=lambda x: x[1])[1] return min_x, max_x, min_y, max_y def world_to_pixel(geotransform_matrix, x, y): """ Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate """ min_x = geotransform_matrix[0] max_y = geotransform_matrix[3] pixel_size_x = geotransform_matrix[1] pixel_size_y = geotransform_matrix[5] # rtnX = geotransform_matrix[2] # rtnY = geotransform_matrix[4] column = int((x - min_x) / pixel_size_x) row = int((y - max_y) / pixel_size_y) return column, row source_file_dir, source_file_name, source_file_extension = split_path(source_image_path) # Output file geographic projection wkt_projection = 'GEOGCS["WGS 84",' \ 'DATUM["WGS_1984",' \ 'SPHEROID["WGS 84",6378137,298.257223563,' \ 'AUTHORITY["EPSG","7030"]],' \ 'AUTHORITY["EPSG","6326"]],' \ 'PRIMEM["Greenwich",0,' \ 'AUTHORITY["EPSG","8901"]],' \ 'UNIT["degree",0.01745329251994328,' \ 'AUTHORITY["EPSG","9122"]],' \ 'AUTHORITY["EPSG","4326"]]' if source_file_extension == '.tif' or source_file_extension == '.tiff': source_image = gdal.Open(source_image_path) # (x, y) coordinates refer are geographical coordinates (latitude and longtitude) # (i, j) and (cols, rows) are pixel coordinates # Read coordinates of ground control points (GCPs) and calculate their extent (min and max x, y values) gcps = source_image.GetGCPs() gcp_x = [] gcp_y = [] for a, val in enumerate(gcps): gcp_x.append(gcps[a].GCPX) gcp_y.append(gcps[a].GCPY) min_source_x = min(gcp_x) max_source_x = max(gcp_x) min_source_y = min(gcp_y) max_source_y = max(gcp_y) # A warped virtual raster (middle_raster) needs to be created # because the source_raster has no geographical projection. # That's why it's being reprojected from None to wkt_projection (None to WGS84). error_threshold = 0.125 resampling = gdal.GRA_NearestNeighbour middle_image = gdal.AutoCreateWarpedVRT(source_image, None, wkt_projection, resampling, error_threshold) source_image = None # Calculate the GeoTransform matrix for the input image # geotransform[0] top left x, minimal x value # geotransform[1] pixel width, pixel size in x dimension # geotransform[2] 0 # geotransform[3] top left y, maximal y value # geotransform[4] 0 # geotransform[5] pixel height, pixel size in y dimension, should be negative source_cols = middle_image.RasterXSize source_rows = middle_image.RasterYSize geotransform = [min_source_x, (max_source_x - min_source_x) / source_cols, 0, max_source_y, 0, (max_source_y - min_source_y) / source_rows * (-1)] # Calculate the x, y coordinates for a lower right corner of the source_image pixel_size_source_x = geotransform[1] pixel_size_source_y = geotransform[5] max_source_x = min_source_x + (source_cols * pixel_size_source_x) min_source_y = max_source_y + (source_rows * pixel_size_source_y) # Create a polygon equal to extent of the source_image # POLYGON((x1 y1, x2 y2, x3 y3, x4 y4, x1 y1)) image_wkt = 'POLYGON ((' \ + str(min_source_x) + ' ' \ + str(max_source_y) + ',' \ + str(max_source_x) + ' ' \ + str(max_source_y) + ',' \ + str(max_source_x) + ' ' \ + str(min_source_y) + ',' \ + str(min_source_x) + ' ' \ + str(min_source_y) + ',' \ + str(min_source_x) + ' ' \ + str(max_source_y) + '))' source_geometry = ogr.CreateGeometryFromWkt(image_wkt) # Load a *.shp file and read the single feature containing border shapefile = ogr.Open(SHP_PATH) shapefile_layer = shapefile.GetLayer("PL") shapefile_polygon = shapefile_layer.GetNextFeature() border_geometry = shapefile_polygon.GetGeometryRef() # Calculate the spatial intersection of the source_image and the border shapefile # It's a shape of the output image output_geometry = border_geometry.Intersection(source_geometry) output_geometry_type = output_geometry.GetGeometryType() output_geometry_geom_count = output_geometry.GetGeometryCount() # GetGeometryType() == 2: LINEARRING # GetGeometryType() == 3: POLYGON # GetGeometryType() == 6: MULTIPOLYGON # Create a list of (x,y) pairs of output_geometry coordinates polygons = [] if output_geometry_type == 3: pts = output_geometry.GetGeometryRef(0) polygon = [] for point in range(pts.GetPointCount()): polygon.append((pts.GetX(point), pts.GetY(point))) polygons.append(polygon) elif output_geometry_type == 6: for geom in range(output_geometry_geom_count): pts = output_geometry.GetGeometryRef(geom) pts = pts.GetGeometryRef(0) polygon = [] for p in range(pts.GetPointCount()): polygon.append((pts.GetX(p), pts.GetY(p))) polygons.append(polygon) # Calculate the pixel extent of the output_geometry polygon min_output_x, max_output_x, min_output_y, max_output_y = get_geometry_extent(polygons) min_output_i, max_output_j = world_to_pixel(geotransform, min_output_x, max_output_y) max_output_i, min_output_j = world_to_pixel(geotransform, max_output_x, min_output_y) # If calculated extent is outside of the source_image array it has to be clipped if min_output_i < 0: min_output_i = 0 if max_output_j < 0: max_output_j = 0 if max_output_i > source_cols: max_output_i = source_cols if min_output_j > source_rows: min_output_j = source_rows # Width and height of the output_raster in pixels output_cols = int(max_output_i - min_output_i) output_rows = int(min_output_j - max_output_j) # Read the middle image as array and select pixels within calculated range middle_array = np.array(middle_image.GetRasterBand(1).ReadAsArray()) clip = middle_array[max_output_j:min_output_j, min_output_i:max_output_i] # Calculate the GeoTransform matrix for the output image, it has a different x and y origin output_geotransform = geotransform output_geotransform[0] = min_output_x output_geotransform[3] = max_output_y # Convert (x,y) pairs of output_geometry coordinates to pixel coordinates polygons_pixel = [] for polygon in polygons: polygon_pixel = [] for point in polygon: polygon_pixel.append(world_to_pixel(output_geotransform, point[0], point[1])) polygons_pixel.append(polygon_pixel) # Create a new PIL image and rasterize the clipping shape polygon_raster = Image.new("L", (output_cols, output_rows), 1) rasterize = ImageDraw.Draw(polygon_raster) for polygon in polygons_pixel: rasterize.polygon(polygon, 0) mask = image_to_array(polygon_raster) clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16) # Create the output file driver = gdal.GetDriverByName('GTiff') # ! # proj = middle_image.GetProjection() output_image = driver.Create(output_image_path, output_cols, output_rows, 1, gdal.GDT_UInt16) output_image.GetRasterBand(1).WriteArray(clip) output_image.SetGeoTransform(output_geotransform) # ! output_image.SetProjection(wkt_projection) output_image.FlushCache() output_image = None elif source_file_extension == '.jp2': source_image = gdal.Open(source_image_path) # TODO: output_image should be in UTM projection gdal.Warp(os.path.join(source_file_dir, source_file_name + '_WGS84' + source_file_extension), source_image, dstSRS='EPSG:4326') source_image = gdal.Open(os.path.join(source_file_dir, source_file_name + '_WGS84' + source_file_extension)) source_array = gdalnumeric.LoadFile(os.path.join(source_file_dir, source_file_name + '_WGS84' + source_file_extension)) geotransform = source_image.GetGeoTransform() min_source_x = geotransform[0] max_source_y = geotransform[3] source_cols = source_image.RasterXSize source_rows = source_image.RasterYSize pixel_size_source_x = geotransform[1] pixel_size_source_y = geotransform[5] max_source_x = min_source_x + (source_cols * pixel_size_source_x) min_source_y = max_source_y + (source_rows * pixel_size_source_y) image_wkt = 'POLYGON ((' \ + str(min_source_x) + ' ' \ + str(max_source_y) + ',' \ + str(max_source_x) + ' ' \ + str(max_source_y) + ',' \ + str(max_source_x) + ' ' \ + str(min_source_y) + ',' \ + str(min_source_x) + ' ' \ + str(min_source_y) + ',' \ + str(min_source_x) + ' ' \ + str(max_source_y) + '))' source_geometry = ogr.CreateGeometryFromWkt(image_wkt) shapefile = ogr.Open(SHP_PATH) shapefile_layer = shapefile.GetLayer("PL") shapefile_polygon = shapefile_layer.GetNextFeature() border_geometry = shapefile_polygon.GetGeometryRef() output_geometry = border_geometry.Intersection(source_geometry) output_geometry_type = output_geometry.GetGeometryType() output_geometry_geom_count = output_geometry.GetGeometryCount() # GetGeometryType() == 2: LINEARRING # GetGeometryType() == 3: POLYGON # GetGeometryType() == 6: MULTIPOLYGON polygons = [] if output_geometry_type == 3: pts = output_geometry.GetGeometryRef(0) polygon = [] for point in range(pts.GetPointCount()): polygon.append((pts.GetX(point), pts.GetY(point))) polygons.append(polygon) elif output_geometry_type == 6: for geom in range(output_geometry_geom_count): pts = output_geometry.GetGeometryRef(geom) pts = pts.GetGeometryRef(0) polygon = [] for p in range(pts.GetPointCount()): polygon.append((pts.GetX(p), pts.GetY(p))) polygons.append(polygon) min_output_x, max_output_x, min_output_y, max_output_y = get_geometry_extent(polygons) min_ouput_i, max_output_j = world_to_pixel(geotransform, min_output_x, max_output_y) max_output_i, min_output_j = world_to_pixel(geotransform, max_output_x, min_output_y) if min_ouput_i < 0: min_ouput_i = 0 if max_output_j < 0: max_output_j = 0 if max_output_i > source_cols: max_output_i = source_cols if min_output_j > source_rows: min_output_j = source_rows output_cols = int(max_output_i - min_ouput_i) output_rows = int(min_output_j - max_output_j) clip = source_array[max_output_j:min_output_j, min_ouput_i:max_output_i] output_geotransform = list(geotransform) output_geotransform[0] = min_output_x output_geotransform[3] = max_output_y polygons_pixel = [] for polygon in polygons: polygon_pixel = [] for point in polygon: polygon_pixel.append(world_to_pixel(output_geotransform, point[0], point[1])) polygons_pixel.append(polygon_pixel) polygon_raster = Image.new("L", (output_cols, output_rows), 1) rasterize = ImageDraw.Draw(polygon_raster) for polygon in polygons_pixel: rasterize.polygon(polygon, 0) mask = image_to_array(polygon_raster) clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16) driver = gdal.GetDriverByName('GTiff') output_image = driver.Create(output_image_path, output_cols, output_rows, 1, gdal.GDT_UInt16) output_image.GetRasterBand(1).WriteArray(clip) proj = source_image.GetProjection() output_image.SetGeoTransform(output_geotransform) output_image.SetProjection(proj) output_image.FlushCache() output_image = None else: print('unknown file format')
def downloadImage(request, result_id, band): if request.method == 'GET': resultImg = models.QueryResult.objects.filter(pk=result_id).first() if resultImg == None: raise Http404 tiles = list(resultImg.tileMatrix) src_srs=osr.SpatialReference() src_srs.ImportFromWkt(tiles[0].image.wkt) tgt_srs=osr.SpatialReference() tgt_srs.ImportFromEPSG(4326) tgt_srs = src_srs.CloneGeogCS() preClipDS, preClipSize, preClipGeoTransform = GetPreClipImage(tiles, band, resultImg.imageName, src_srs, tgt_srs) # print preClipGeoTransform # Raster of input polygons rasterPoly = Image.new("L", (preClipSize[0], preClipSize[1]), 1) rasterize = ImageDraw.Draw(rasterPoly) inputPolygons = resultImg.inputPolygons.polygons mostULx = mostLRx = mostULy = mostLRy = None for polygon in inputPolygons: pixels = [] inputPolygonReprojected = ReprojectCoords(polygon['coordinates'][0], tgt_srs, src_srs) for p in inputPolygonReprojected: pixels.append(world2Pixel(preClipGeoTransform, p[0], p[1])) pixels = intersectPolygonToBorder(pixels, preClipSize[0], preClipSize[1]) if pixels is None: continue print pixels if mostULx == None or \ mostLRx == None or \ mostULy == None or \ mostLRy == None: mostULx = mostLRx = pixels[0][0] mostULy = mostLRy = pixels[0][1] for x, y in pixels: if x > mostLRx: mostLRx = x if x < mostULx: mostULx = x if y < mostULy: mostULy = y if y > mostLRy: mostLRy = y # mostULx, mostULy = world2Pixel(preClipGeoTransform, mostULx, mostULy) # mostLRx, mostLRy = world2Pixel(preClipGeoTransform, mostLRx, mostLRy) mostULx = 0 if mostULx < 0 else mostULx mostLRx = 0 if mostLRx < 0 else mostLRx mostULy = 0 if mostULy < 0 else mostULy mostLRy = 0 if mostLRy < 0 else mostLRy rasterize.polygon(pixels, 0) print '%i %i %i %i' % (mostULx, mostULy, mostLRx, mostLRy) # clipped the output dataset by minimum rect clip = preClipDS.GetRasterBand(1).ReadAsArray(0, 0, preClipSize[0], preClipSize[1])[mostULy:mostLRy, mostULx:mostLRx] # create mask to clip image by polygon mask = imageToArray(rasterPoly)[mostULy:mostLRy, mostULx:mostLRx] # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16) finalFile = NamedTemporaryFile(suffix='.tif', prefix=resultImg.imageName+'-'+str(band)) gdalnumeric.SaveArray(clip, str(finalFile.name) , format="GTiff") clippedGeoTransform = [preClipGeoTransform[0] + mostULx*preClipGeoTransform[1], preClipGeoTransform[1], preClipGeoTransform[2], preClipGeoTransform[3] + mostULy*preClipGeoTransform[5], preClipGeoTransform[4], preClipGeoTransform[5]] ds = gdal.Open(str(finalFile.name), gdal.GA_Update) ds.SetGeoTransform(clippedGeoTransform) ds.SetProjection(src_srs.ExportToWkt()) # Return HttpResponse Image wrapper = FileWrapper(finalFile) content_type = mimetypes.guess_type(finalFile.name)[0] response = StreamingHttpResponse(wrapper, content_type='content_type') response['Content-Disposition'] = "attachment; filename=%s" % finalFile.name return response # return HttpResponse(json.dumps(dict(out=output_geo_transform, # ext=ext, # finalXSize=finalXSize, # finalYSize=finalYSize))) raise Http404
def clip(poly,rasterObj,field,date=0,vNan=numpy.nan): ''' :param poly:geometry in vectorObj :param rasterObj: rasterObj to clip :param field: rasterObj clip field :return: clip rasterObj and mask rasterObj ''' rasterGeoTrans=rasterObj.getGeoTransform() rasterProjection=rasterObj.getProjection() rasterArray=rasterObj.getData(field=field,date=date) minX, maxX, minY, maxY = poly.GetEnvelope() indx1, indy1 = world2Pixel(rasterGeoTrans, minX, maxY) indx2, indy2 = world2Pixel(rasterGeoTrans, maxX, minY) pxWidth = int(indx2 - indx1) pxHeight = int(indy2 - indy1) clip = rasterArray[indy1:indy2, indx1:indx2] geoTrans = list(rasterGeoTrans) geoTrans[0] = minX geoTrans[3] = maxY mask=None if poly.GetGeometryType()==6: for polygon in poly: points = [] pixels = [] pts = polygon.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) if mask is None: mask = imageToArray(rasterPoly) else: masktemp = imageToArray(rasterPoly) mask=mask*masktemp elif poly.GetGeometryType()==3: points = [] pixels = [] pts = poly.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) clip = gdalnumeric.choose(mask,(clip, vNan)) dx=rasterGeoTrans[1] dy=rasterGeoTrans[5] x1=rasterGeoTrans[0]+dx*indx1 y1=rasterGeoTrans[3]+dy*indy1 clipGeoTrans=(x1,dx,0.0,y1,0.0,dy) gdal.ErrorReset() clipObj=EarthModule.EarthObj_raster(field=field,geoProjection=rasterProjection, geoTransform=clipGeoTrans,data=clip) maskObj=EarthModule.EarthObj_raster(field=field,geoProjection=rasterProjection, geoTransform=clipGeoTrans,data=mask) return clipObj,maskObj
pixels = Stream(range(kiev_points.GetPointCount())) \ .map( lambda i: (kiev_points.GetX(i), kiev_points.GetY(i)) ) \ .map( lambda x, y: world2pixel(transform, x,y) ).list() rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = gdalnumeric.fromstring(rasterPoly.tobytes(),'b') mask.shape=rasterPoly.im.size[1], rasterPoly.im.size[0] print "Create mask %.3f sec" % (timer() - t1) # Clip the image using the mask clip = gdalnumeric.choose(mask, (clip, 0)).astype(gdalnumeric.uint16) gdalnumeric.SaveArray(clip, "kiev.tif", format="GTiff", prototype=raster_path) dataset = gdal.GetDriverByName('GTiff')\ .Create('kiev2.tif', pxWidth, pxHeight, 1, gdal.GDT_Byte) dataset.SetGeoTransform(transform) dataset.SetProjection(str(raster_proj)) print 'GetBlockSize()', dataset.GetRasterBand(1).GetBlockSize() dataset.GetRasterBand(1).SetNoDataValue(0); dataset.GetRasterBand(1).WriteArray(clip) dataset.FlushCache() clip = clip.astype(gdalnumeric.uint8)
def crop(input_file, extents, geo_trans=None, nodata=np.nan): """ Adapted from http://karthur.org/2015/clipping-rasters-in-python.html Clips a raster (given as either a gdal.Dataset or as a numpy.array instance) to a polygon layer provided by a Shapefile (or other vector layer). If a numpy.array is given, a "GeoTransform" must be provided (via dataset.GetGeoTransform() in GDAL). Returns an array. Clip features must be a dissolved, single-part geometry (not multi-part). Modified from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html #clip-a-geotiff-with-shapefile Parameters ---------- rast: A gdal.Dataset or a NumPy array features_path: The path to the clipping features geo_trans: An optional GDAL GeoTransform to use instead nodata: The NoData value; defaults to -9999 """ def image_to_array(i): """ Converts a Python Imaging Library (PIL) array to a gdalnumeric image """ arr = gdalnumeric.fromstring(i.tobytes(), 'b') arr.shape = i.im.size[1], i.im.size[0] return arr raster = gdal.Open(input_file) # Can accept either a gdal.Dataset or numpy.array instance if not isinstance(raster, np.ndarray): if not geo_trans: geo_trans = raster.GetGeoTransform() raster = raster.ReadAsArray() else: if not geo_trans: raise ValueError('geo transform must be supplied') # Convert the layer extent to image pixel coordinates min_x, min_y, max_x, max_y = extents ul_x, ul_y = world_to_pixel(geo_trans, min_x, max_y) lr_x, lr_y = world_to_pixel(geo_trans, max_x, min_y) # Calculate the pixel size of the new image px_width = int(lr_x - ul_x) px_height = int(lr_y - ul_y) # If the clipping features extend out-of-bounds and ABOVE the raster... if geo_trans[3] < max_y: # In such a case... ul_y ends up being negative--can't have that! # iY = ul_y ul_y = 0 # Multi-band image? try: clip = raster[:, ul_y:lr_y, ul_x:lr_x] except IndexError: clip = raster[ul_y:lr_y, ul_x:lr_x] # Create a new geomatrix for the image gt2 = list(geo_trans) gt2[0] = min_x gt2[3] = max_y # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [(min_x, min_y), (max_x, min_y), (max_x, max_y), (min_y, max_y)] pixels = [] # for point in range(pts.GetPointCount()): # points.append((pts.GetX(point), pts.GetY(point))) for point in points: pixels.append(world_to_pixel(gt2, point[0], point[1])) raster_poly = Image.new('L', size=(px_width, px_height), color=1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes # If the clipping features extend out-of-bounds and ABOVE the raster... # SB: we don't implement clipping for out-of-bounds and ABOVE the raster # We might need this down the line when we have looked at `maximum crop` in # detail # if geo_trans[3] < max_y: # # The clip features were "pushed down" to match the bounds of the # # raster; this step "pulls" them back up # premask = image_to_array(raster_poly) # # We slice out the piece of our clip features that are "off the map" # mask = np.ndarray((premask.shape[-2] - abs(iY), # premask.shape[-1]), premask.dtype) # mask[:] = premask[abs(iY):, :] # mask.resize(premask.shape) # Then fill in from the bottom # # # Most importantly, push the clipped piece down # gt2[3] = max_y - (max_y - geo_trans[3]) # # else: # mask = image_to_array(raster_poly) mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) raster = None # manual close return clip, gt2
def clipRaster(raster_path,shapefile_path): """ Cette fonction prend en entrée un Raster et un vecteur puis elle renvoie un raster decouper selon l'emprise du vecteur. Entree: raster_path,shapefile_path Sortie: clip """ #raster_path='MOD13Q1_h17v07_2000_001_NDVI.tif' #shapefile_path='Zones_Etudes.shp' # Load the source data as a gdalnumeric array srcArray = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile shapef = ogr.Open(shapefile_path) lyr = shapef.GetLayer( os.path.split( os.path.splitext( shapefile_path )[0] )[1] ) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[ulY:lrY, ulX:lrX] # # EDIT: create pixel offset to pass to new image Projection info # xoffset = ulX yoffset = ulY #print "Xoffset, Yoffset = ( %f, %f )" % ( xoffset, yoffset ) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.int16) return clip,minX,maxY,pxHeight,pxWidth
def clip_raster(rast, features_path, gt=None, nodata=-9999): ''' Copyright: http://karthur.org/2015/clipping-rasters-in-python.html Clips a raster (given as either a gdal.Dataset or as a numpy.array instance) to a polygon layer provided by a Shapefile (or other vector layer). If a numpy.array is given, a "GeoTransform" must be provided (via dataset.GetGeoTransform() in GDAL). Returns an array. Clip features must be a dissolved, single-part geometry (not multi-part). Modified from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html #clip-a-geotiff-with-shapefile Arguments: rast A gdal.Dataset or a NumPy array features_path The path to the clipping features gt An optional GDAL GeoTransform to use instead nodata The NoData value; defaults to -9999. ''' def array_to_image(a): ''' Converts a gdalnumeric array to a Python Imaging Library (PIL) Image. ''' i = Image.fromstring('L',(a.shape[1], a.shape[0]), (a.astype('b')).tostring()) return i def image_to_array(i): ''' Converts a Python Imaging Library (PIL) array to a gdalnumeric image. ''' a = gdalnumeric.fromstring(i.tobytes(), 'b') a.shape = i.im.size[1], i.im.size[0] return a def world_to_pixel(geo_matrix, x, y): ''' Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate; from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html#clip-a-geotiff-with-shapefile ''' ulX = geo_matrix[0] ulY = geo_matrix[3] xDist = geo_matrix[1] yDist = geo_matrix[5] rtnX = geo_matrix[2] rtnY = geo_matrix[4] pixel = int((x - ulX) / xDist) line = int((ulY - y) / xDist) return (pixel, line) # Can accept either a gdal.Dataset or numpy.array instance if not isinstance(rast, np.ndarray): gt = rast.GetGeoTransform() rast = rast.ReadAsArray() # Create an OGR layer from a boundary shapefile features = ogr.Open(features_path) if features.GetDriver().GetName() == 'ESRI Shapefile': lyr = features.GetLayer(os.path.split(os.path.splitext(features_path)[0])[1]) else: lyr = features.GetLayer() # Get the first feature poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # In such a case... ulY ends up being negative--can't have that! iY = ulY ulY = 0 # Multi-band image? try: clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: clip = rast[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # The clip features were "pushed down" to match the bounds of the # raster; this step "pulls" them back up premask = image_to_array(raster_poly) # We slice out the piece of our clip features that are "off the map" mask = np.ndarray((premask.shape[-2] - abs(iY), premask.shape[-1]), premask.dtype) mask[:] = premask[abs(iY):, :] mask.resize(premask.shape) # Then fill in from the bottom # Most importantly, push the clipped piece down gt2[3] = maxY - (maxY - gt[3]) else: mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) return (clip, ulX, ulY, gt2)
def clip_raster(rast, features_path, gt=None, nodata=-9999): """ Clips a raster (given as either a gdal.Dataset or as a numpy.array instance) to a polygon layer provided by a Shapefile (or other vector layer). If a numpy.array is given, a "GeoTransform" must be provided (via dataset.GetGeoTransform() in GDAL). Returns an array. Clip features must be a dissolved, single-part geometry (not multi-part). Modified from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html #clip-a-geotiff-with-shapefile Arguments: rast A gdal.Dataset or a NumPy array features_path The path to the clipping features gt An optional GDAL GeoTransform to use instead nodata The NoData value; defaults to -9999. """ print(features_path) def array_to_image(a): """ Converts a gdalnumeric array to a Python Imaging Library (PIL) Image. """ i = Image.fromstring('L', (a.shape[1], a.shape[0]), (a.astype('b')).tostring()) return i def image_to_array(i): """ Converts a Python Imaging Library (PIL) array to a gdalnumeric image. """ a = gdalnumeric.fromstring(i.tobytes(), 'b') a.shape = i.im.size[1], i.im.size[0] return a def world_to_pixel(geo_matrix, x, y): """ Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate; from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html#clip-a-geotiff-with-shapefile """ ul_x = geo_matrix[0] ul_y = geo_matrix[3] xDist = geo_matrix[1] yDist = geo_matrix[5] rtnX = geo_matrix[2] rtnY = geo_matrix[4] pixel = int((x - ul_x) / xDist) line = int((ul_y - y) / xDist) return pixel, line # Can accept either a gdal.Dataset or numpy.array instance if not isinstance(rast, np.ndarray): print("is not an array") gt = rast.GetGeoTransform() rast = rast.ReadAsArray() # Create an OGR layer from a boundary shapefile features = ogr.Open(features_path) if features.GetDriver().GetName() == 'ESRI Shapefile': lyr = features.GetLayer( os.path.split(os.path.splitext(features_path)[0])[1]) else: lyr = features.GetLayer() # Get the first feature poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # In such a case... ulY ends up being negative--can't have that! iY = ulY ulY = 0 # Multi-band image? try: clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: clip = rast[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # The clip features were "pushed down" to match the bounds of the # raster; this step "pulls" them back up premask = image_to_array(raster_poly) # We slice out the piece of our clip features that are "off the map" mask = np.ndarray((premask.shape[-2] - abs(iY), premask.shape[-1]), premask.dtype) mask[:] = premask[abs(iY):, :] mask.resize(premask.shape) # Then fill in from the bottom # Most importantly, push the clipped piece down gt2[3] = maxY - (maxY - gt[3]) else: mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) return (clip, ulX, ulY, gt2)
data, data_gray, gt, crs = read_raster(r'./使用数据/裁剪用影像.tif') poly = vector.iloc[0]['geometry'] minX, maxX = min(poly.envelope.exterior.coords.xy[0]), max( poly.envelope.exterior.coords.xy[0]) minY, maxY = min(poly.envelope.exterior.coords.xy[1]), max( poly.envelope.exterior.coords.xy[1]) uper_left_X, uper_left_Y = geoToPixel((minX, maxY), gt) lower_right_X, lower_right_Y = geoToPixel((maxX, minY), gt) ## 计算当前裁剪后栅格的GeoTransform gt2 = list(gt) gt2[0] = minX gt2[3] = maxY pxWidth = int(lower_right_X - uper_left_X) pxHeight = int(lower_right_Y - uper_left_Y) clip1 = data.ReadAsArray(int(uper_left_X), int(uper_left_Y), int(pxWidth), int(pxHeight)) ext_pix = np.array( [geoToPixel(points, gt2) for points in poly.exterior.coords]) ext_pix = np.expand_dims(ext_pix, axis=0) mask = np.ones([pxHeight, pxWidth], np.uint8) mask = cv2.fillPoly(mask, ext_pix, 0) clip = gdalnumeric.choose(mask, (clip1, 0)) plt.imshow(clip[1]) saveim(r'./输出数据/裁剪.tif', clip, crs, gt)
def clip_raster(rast, features_path, output_dir, gt, nodata=-9999, save2csv=None, save2raster=None, save2shp=None, unit_multiplier=None, return_array=False, OutputSRS=3035, suffix_namefield=None, add_suffix=None): ''' Clips a raster (given a numpy.array and its geo-transform array) to a polygon layer provided by a Shapefile (or other vector layer). Returns an array. Clip features can be multi-part geometry and with interior ring inside them. The code supports most of raster and clip vector arrangements; however, it does not support cases in which clip vector extent (envlope of it) goes beyond more than 2 sides of the raster. Arguments: rast A NumPy array features_path The path to the clipping layer gt GDAL GeoTransform array nodata The NoData value; defaults to -9999 save2csv should the outputs be saved in a csv file as well? unit_multiplier Factor to be multiplied into the summation to output the desired unit. suffix_namefield What to add at the end of the file name. must be field of shape file ''' def image_to_array(i): ''' Converts a Python Imaging Library (PIL) array to a gdalnumeric image. ''' a = gdalnumeric.fromstring(i.tobytes(), 'b') a.shape = i.im.size[1], i.im.size[0] return a def world_to_pixel(geo_matrix, x, y): ''' Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate; ''' ulX = geo_matrix[0] ulY = geo_matrix[3] xDist = geo_matrix[1] yDist = geo_matrix[5] rtnX = geo_matrix[2] rtnY = geo_matrix[4] pixel = int((x - ulX) / xDist) line = int((ulY - y) / xDist) return (pixel, line) clip_complete = None # get shapefile name shpName = features_path.replace('\\', '/') shpName = shpName.split('/')[-1][0:-4] # Create a data array for the output csv if save2csv: feat = [] demand = [] if unit_multiplier is None: unit_multiplier = 1.0 xRes, yRes = rast.shape # Create an OGR layer from a boundary shapefile features = ogr.Open(features_path) if features.GetDriver().GetName() == 'ESRI Shapefile': temp = os.path.split(os.path.splitext(features_path)[0]) lyr = features.GetLayer(temp[1]) else: lyr = features.GetLayer() for fid in range(lyr.GetFeatureCount()): flag = np.zeros(4) ''' if fid > 40: continue ''' poly = lyr.GetFeature(fid) geom = poly.GetGeometryRef() if suffix_namefield is not None: suffix = poly.GetField(suffix_namefield) if add_suffix is not None: suffix = '_'+ add_suffix + '_'+ suffix else: suffix = 'feature_' + str(fid) # Convert the feature extent to image pixel coordinates minX, maxX, minY, maxY = geom.GetEnvelope() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: if gt[3] < minY: continue else: # In such a case. ulY ends up being negative--can't have that! ulY = 0 flag[0] = 1 if gt[0] > minX: if gt[0] > maxX: continue else: ulX = 0 flag[1] = 1 rastXmax = gt[0] + yRes * gt[1] if rastXmax < maxX: if rastXmax < minX: continue else: lrX = yRes flag[2] = 1 rastYmin = gt[3] + xRes * gt[5] if rastYmin > minY: if rastYmin > maxY: continue else: lrY = xRes flag[3] = 1 flag_sum = np.sum(flag) # Multi-band image? try: clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: clip = rast[ulY:lrY, ulX:lrX] geometry_counts = geom.GetGeometryCount() clip_complete = np.zeros((pxHeight, pxWidth), clip.dtype) # perform the process for multi-part features for i in range(geometry_counts): # Do not delete this. Clip is set to None in each iteration and # should be initialized here again. try: clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: clip = rast[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = gt2[1]*int(minX/gt2[1]) gt2[3] = gt2[1]*int(maxY/gt2[1]) if gt2[3] < maxY: gt2[3] = gt2[1] * int(maxY/gt2[1] + 1) # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] # check multi-part geometries if geometry_counts > 1: geom1 = geom.GetGeometryRef(i) # check multi-part geometry with interior ring if geom1.GetGeometryName() == 'LINEARRING': pts = geom1 else: # get outer ring of polygon pts = geom1.GetGeometryRef(0) # print(geom1.GetGeometryName() + ' ' + pts.GetGeometryName()) else: # get outer ring of polygon pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) # Fill with zeroes rasterize.polygon(pixels, 0) premask = image_to_array(raster_poly) # with the calculated geotransform matrix gt2, clip matrix should # have the same dimension as premask clip_new = np.zeros_like(premask, clip.dtype) if flag_sum == 0: mask = premask clip_new = gdalnumeric.choose(mask, (clip, nodata)) else: if flag_sum < 3: row_clip, col_clip = clip.shape index = np.array([-flag[0]*row_clip, flag[3]*row_clip, -flag[1]*col_clip, flag[2]*col_clip] ).astype(int) mask_index = np.where(index == 0, None, index) mask = premask[mask_index[0]:mask_index[1], mask_index[2]:mask_index[3]] clip = gdalnumeric.choose(mask, (clip, nodata)) clip_new[mask_index[0]:mask_index[1], mask_index[2]:mask_index[3]] = clip else: s = 1 # raise InputError('Clip for the feature %d is not ' # 'supported' % fid) m1, n1 = np.nonzero(clip_new) clip_stack = set(list(zip(m1, n1))) m2, n2 = np.nonzero(clip_complete) clip_complete_stack = set(list(zip(m2, n2))) intersect_clip = clip_complete_stack.intersection(clip_stack) if len(intersect_clip) == 0: clip_complete = clip_complete + clip_new else: clip_complete = clip_complete - clip_new mask = None premask = None raster_poly = None rasterize = None geom1 = None pts = None gt3 = gt2 gt2 = None clip = None clip_new = None if save2csv: nuts_region = str(poly.GetField(0)) dem_sum = np.sum(clip_complete) * unit_multiplier if dem_sum > 0: feat.append(nuts_region) demand.append(dem_sum) print('The sum of values within the region %s is: %0.1f' % (nuts_region, dem_sum)) if save2raster: if not save2csv: dem_sum = np.sum(clip_complete) * unit_multiplier if dem_sum > 0: outRasterPath = output_dir + os.sep + shpName + '_feature_' + \ str(fid) + '.tif' outRasterPath = output_dir + os.sep + shpName + '_' + \ suffix + '.tif' CM19.main(outRasterPath, gt3, str(clip_complete.dtype), clip_complete, 0) if save2csv or save2shp: saveCSVorSHP(feat, demand, features_path, output_dir, shpName, save2csv, save2shp, OutputSRS=OutputSRS) if return_array: return clip_complete, gt3
def CLIP( shapefile_path, raster_path, outputName ): # Load the source data as a gdalnumeric array #shapefile_path = "C:/Users/Ray/Desktop/Clip/studyArea.shp" shapefile_path = str(shapefile_path) raster_path = str(raster_path) #raster_path = "C:/Users/Ray/Desktop/Clip/1.tif" print shapefile_path print raster_path srcArray = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile print shapefile_path shapef = ogr.Open(shapefile_path) print type(shapef) lyr = shapef.GetLayer( os.path.split( os.path.splitext( shapefile_path )[0] )[1] ) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[ ulY:lrY, ulX:lrX] # # EDIT: create pixel offset to pass to new image Projection info # xoffset = ulX yoffset = ulY print "Xoffset, Yoffset = ( %f, %f )" % ( xoffset, yoffset ) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask clip = gdalnumeric.choose(mask, \ (clip, 0)).astype('float64') # Save new tiff # # EDIT: instead of SaveArray, let's break all the # SaveArray steps out more explicity so # we can overwrite the offset of the destination # raster # ### the old way using SaveArray # # gdalnumeric.SaveArray(clip, "OUTPUT.tif", format="GTiff", prototype=raster_path) # ### # gtiffDriver = gdal.GetDriverByName( 'GTiff' ) if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") gtiffDriver.CreateCopy( outputName, OpenArray( clip, prototype_ds=raster_path, xoff=xoffset, yoff=yoffset ) ) # Save as an 8-bit jpeg for an easy, quick preview clip = clip.astype('float64')
def clip_by_shape(self, geom_wkt, nodata=-32767): ''' Clip an Imagee by wkt geometry. ''' rast = self._data gt = self._metadata['affine_transformation'] poly = ogr.CreateGeometryFromWkt(geom_wkt) # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = poly.GetEnvelope() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # In such a case... ulY ends up being negative--can't have that! iY = ulY ulY = 0 clip = rast[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) def rec(poly_geom): ''' Recursive drawing of parts of multipolygons over initialized PIL Image object using ImageDraw.Draw method. ''' if poly_geom.GetGeometryCount() == 0: points = [] pixels = [] for p in range(poly_geom.GetPointCount()): points.append((poly_geom.GetX(p), poly_geom.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) rasterize.polygon(pixels, 0) if poly_geom.GetGeometryCount() >= 1: for j in range(poly_geom.GetGeometryCount()): rec(poly_geom.GetGeometryRef(j)) rec(poly) mask = image_to_array(raster_poly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) d = {} d['affine_transformation'], d['ul_x'], d['ul_y'], d[ 'nodata'] = gt2, ulX, ulY, -32767 return (clip, d)
def ObtainPixelsfromShape(field, rasterPath, shapePath, INX): # field='zona' #img = gdal.Open('Testimg/subset_RGBNIR_affected_trees') # shapefile = "Testimg/features.shp" # open dataset, also load as a gdal image to get geotransform print "Starting clip...." start = time.time() img = gdal.Open(rasterPath) geoTrans = img.GetGeoTransform() geoTransaux = img.GetGeoTransform() proj = img.GetProjection() imgarrayaux = img.ReadAsArray().shape #open shapefile driver = ogr.GetDriverByName("ESRI Shapefile") dataSource = driver.Open(shapePath, 0) layer = dataSource.GetLayer() clipdic = defaultdict(list) count = 0 #Convert the layer extent to image pixel coordinates, we read only de pixels needed for feature in layer: minX, maxX, minY, maxY = feature.GetGeometryRef().GetEnvelope() geoTrans = img.GetGeoTransform() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) #print ulX,lrX,ulY,lrY # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) if INX == True: clip = ReadClipArray(lrY, ulY, lrX, ulX, img) clip = NewBands(clip, lrY, ulY, lrX, ulX) else: #print"Indexes = False" clip = ReadClipArray(lrY, ulY, lrX, ulX, img) # print clip[0] #print"Paso 2" #Image and shape to return in the same shape as it needs the classificator algorithms # imgReturn = np.concatenate(imgaux.T) # shapeReturn = imgaux.shape #imgReturn = np.concatenate(imgaux.T) # shapeReturn = img.ReadAsArray().shape # clip = imgarray[:, ulY:lrY, ulX:lrX] # print clip[0] #EDIT: create pixel offset to pass to new image Projection info xoffset = ulX yoffset = ulY #print "Xoffset, Yoffset = ( %d, %d )" % ( xoffset, yoffset ) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, black and white, mask image. points = [] pixels = [] geom = feature.GetGeometryRef() pts = geom.GetGeometryRef(0) [ points.append((pts.GetX(p), pts.GetY(p))) for p in range(pts.GetPointCount()) ] [pixels.append(world2Pixel(geoTrans, p[0], p[1])) for p in points] rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) #print mask.shape # #SHow the clips of the features # plt.imshow(mask) # plt.show() # Clip the image using the mask into a dict temp = gdalnumeric.choose(mask, (clip, np.nan)) # #SHow the clips of the image # plt.imshow(temp[4]) # plt.show() temp = np.concatenate(temp.T) temp = temp[~np.isnan(temp[:, 0])] clipdic[str(feature.GetField(field))].append(temp) count += temp.shape[0] end = time.time() print "Time clipshape:" print(end - start) return clipdic, count ##########################################################################
def get_area_by_state(palmmask, geoTrans, stateshppath, yearlabel): shapef = ogr.Open(stateshppath) lyr = shapef.GetLayer() arealist = [] # list which store area infos # arealist.append(["Name", "MPOB_area", "palm_area", "Error"]) npoly = 0 poly = lyr.GetNextFeature() while poly: # loop poly in lyr # Convert the layer extent to image pixel coordinates if npoly > 11: break pid = poly.GetField("NAME_1") npoly = npoly + 1 # print(npoly, pid) geon = poly.GetGeometryRef() geontype = geon.GetGeometryType() if geon.GetGeometryType() not in [3, 6]: raise SystemExit("This module can only load polygon/multipolygons") minX, maxX, minY, maxY = geon.GetEnvelope() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = palmmask[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image ngeoTrans = list(geoTrans) ngeoTrans[0] = minX ngeoTrans[3] = maxY # Map points to pixels points = [] pixels = [] # for multipolygons geontype = geon.GetGeometryType() if geontype == 6: # multipolygon rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) i = 0 for geonpart in geon: # loop each part polygon i = i + 1 pts = geonpart.GetGeometryRef(0) np = pts.GetPointCount() points = [] pixels = [] if np == 0: continue for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(ngeoTrans, p[0], p[1])) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # for polygons if geon.GetGeometryType() == 3: points = [] pixels = [] rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) pts = geon.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(ngeoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask and calculate palm percentage cliped = gdalnumeric.choose(mask, (clip, 0)) # .astype(gdalnumeric.uint8) x = cliped[cliped > 0] # watch out >0 palmnum = len(x) palm_area = round(palmnum * 20 * 20 * 0.0001, 2) MPOB_area = settings.MPOB_data[yearlabel][pid] palm_error = round(100.0 * (palm_area - MPOB_area) / (MPOB_area), 2) arealist.append([pid, MPOB_area, palm_area, palm_error]) poly = lyr.GetNextFeature() return arealist
def main(shapefile_path, raster_path): # Load the source data as a gdalnumeric array srcArray = gdalnumeric.LoadFile(raster_path) # Also load as a gdal image to get geotransform # (world file) info srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile shapef = ogr.Open(shapefile_path) lyr = shapef.GetLayer( os.path.split(os.path.splitext(shapefile_path)[0])[1]) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[:, ulY:lrY, ulX:lrX] # # EDIT: create pixel offset to pass to new image Projection info # xoffset = ulX yoffset = ulY print "Xoffset, Yoffset = ( %f, %f )" % (xoffset, yoffset) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.uint8) # This image has 3 bands so we stretch each one to make them # visually brighter for i in range(3): clip[i, :, :] = stretch(clip[i, :, :]) # Save new tiff # # EDIT: instead of SaveArray, let's break all the # SaveArray steps out more explicity so # we can overwrite the offset of the destination # raster # ### the old way using SaveArray # # gdalnumeric.SaveArray(clip, "OUTPUT.tif", format="GTiff", prototype=raster_path) # ### # gtiffDriver = gdal.GetDriverByName('GTiff') if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") gtiffDriver.CreateCopy( "beijing.tif", OpenArray(clip, prototype_ds=raster_path, xoff=xoffset, yoff=yoffset)) # Save as an 8-bit jpeg for an easy, quick preview clip = clip.astype(gdalnumeric.uint8) gdalnumeric.SaveArray(clip, "beijing.jpg", format="JPEG") gdal.ErrorReset()
def clip(poly, rasterObj, field, date=0, vNan=numpy.nan): ''' :param poly:geometry in vectorObj :param rasterObj: rasterObj to clip :param field: rasterObj clip field :return: clip rasterObj and mask rasterObj ''' rasterGeoTrans = rasterObj.getGeoTransform() rasterProjection = rasterObj.getProjection() rasterArray = rasterObj.getData(field=field, date=date) minX, maxX, minY, maxY = poly.GetEnvelope() indx1, indy1 = world2Pixel(rasterGeoTrans, minX, maxY) indx2, indy2 = world2Pixel(rasterGeoTrans, maxX, minY) pxWidth = int(indx2 - indx1) pxHeight = int(indy2 - indy1) clip = rasterArray[indy1:indy2, indx1:indx2] geoTrans = list(rasterGeoTrans) geoTrans[0] = minX geoTrans[3] = maxY mask = None if poly.GetGeometryType() == 6: for polygon in poly: points = [] pixels = [] pts = polygon.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) if mask is None: mask = imageToArray(rasterPoly) else: masktemp = imageToArray(rasterPoly) mask = mask * masktemp elif poly.GetGeometryType() == 3: points = [] pixels = [] pts = poly.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) clip = gdalnumeric.choose(mask, (clip, vNan)) dx = rasterGeoTrans[1] dy = rasterGeoTrans[5] x1 = rasterGeoTrans[0] + dx * indx1 y1 = rasterGeoTrans[3] + dy * indy1 clipGeoTrans = (x1, dx, 0.0, y1, 0.0, dy) gdal.ErrorReset() clipObj = EarthModule.EarthObj_raster(field=field, geoProjection=rasterProjection, geoTransform=clipGeoTrans, data=clip) maskObj = EarthModule.EarthObj_raster(field=field, geoProjection=rasterProjection, geoTransform=clipGeoTrans, data=mask) return clipObj, maskObj
def initialClip(self, shapef=None, lyr=None, openfile=True): DriverName = "ESRI Shapefile" driver = ogr.GetDriverByName(DriverName) if openfile: # Create an OGR layer from a boundary shapefile shapef = driver.Open('%s.shp' % self.countryshp) lyr = shapef.GetLayer() geoTrans = self.srcImage.GetGeoTransform() poly = lyr.GetNextFeature() minX, maxX, minY, maxY = poly.GetGeometryRef().GetEnvelope() ulX, ulY = self.world2Pixel(geoTrans, minX, maxY) lrX, lrY = self.world2Pixel(geoTrans, maxX, minY) # Include offset to position correctly within overall image xoffset = ulX yoffset = ulY # Correction for countries that exceed satellite dataset boundaries if ulY < 0: ulY = 0 yoffset = 0 maxY = 75. # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = self.srcArray[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Create new mask image for each province rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) geom = poly.GetGeometryRef() for ring in range(geom.GetGeometryCount()): points = [] pixels = [] geom_poly = geom.GetGeometryRef(ring) # If picking the feature gets a polygon, there are islands, # go down another level to get LINEARRING if geom_poly.GetGeometryName() == "POLYGON": pts = geom_poly.GetGeometryRef(0) else: pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(self.world2Pixel(geoTrans, p[0], p[1])) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = self.imageToArray(rasterPoly) # Clip the image using the mask try: clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.uint32) except: print('%s exceeds the boundaries of the satellite dataset' % poly.GetField('name')) sys.exit() # Save clipped province image province_name = poly.GetField('name') gtiffDriver = gdal.GetDriverByName('GTiff') if gtiffDriver is None: raise ValueError("Can't find GeoTiff Driver") if not os.path.exists(self.output): os.makedirs(self.output) gtiffDriver.CreateCopy( "%s%s.tif" % (self.output, province_name), self.OpenArray(clip, prototype_ds=self.raster, xoff=xoffset, yoff=yoffset)) return '%s%s.tif' % (self.output, province_name)
def ObtainPixelsfromShape(field, rasterPath, shapePath, INX, *args): # field='zona' # open dataset, also load as a gdal image to get geotransform # INX can be false. If True, uses additional layers. print "Starting clip...." start = time.time() if args: texture_train_Path = args[0] print texture_train_Path img, textArrayShp = createTextureArray(texture_train_Path, rasterPath) else: #print"Indexes = False" img = gdal.Open(rasterPath) geoTrans = img.GetGeoTransform() geoTransaux = img.GetGeoTransform() proj = img.GetProjection() # imgarrayaux = img.ReadAsArray().shape # print "img.ReadAsArray().shape", img.ReadAsArray().shape #open shapefile driver = ogr.GetDriverByName("ESRI Shapefile") dataSource = driver.Open(shapePath, 0) layer = dataSource.GetLayer() clipdic = defaultdict(list) count = 0 #Convert the layer extent to image pixel coordinates, we read only de pixels needed for feature in layer: minX, maxX, minY, maxY = feature.GetGeometryRef().GetEnvelope() geoTrans = img.GetGeoTransform() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) #print ulX,lrX,ulY,lrY # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = ReadClipArray(lrY, ulY, lrX, ulX, img) #EDIT: create pixel offset to pass to new image Projection info xoffset = ulX yoffset = ulY #print "Xoffset, Yoffset = ( %d, %d )" % ( xoffset, yoffset ) # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, black and white, mask image. points = [] pixels = [] geom = feature.GetGeometryRef() pts = geom.GetGeometryRef(0) [ points.append((pts.GetX(p), pts.GetY(p))) for p in range(pts.GetPointCount()) ] [pixels.append(world2Pixel(geoTrans, p[0], p[1])) for p in points] rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) #SHow the clips of the features # plt.imshow(mask) # plt.show() # Clip the image using the mask into a dict temp = gdalnumeric.choose(mask, (clip, np.nan)) # #SHow the clips of the image # plt.imshow(temp[4]) # plt.show() temp = np.concatenate(temp.T) temp = temp[~np.isnan(temp[:, 0])] #NaN #print temp.shape clipdic[str(feature.GetField(field))].append(temp) count += temp.shape[0] end = time.time() print "Time clipshape:" print(end - start) print "count", count return clipdic, count
def clip_raster(rast_path, features_path, gt=None, nodata=-9999): def array_to_image(a): ''' Converts a gdalnumeric array to a Python Imaging Library (PIL) Image. ''' i = Image.fromstring('L', (a.shape[1], a.shape[0]), (a.astype('b')).tostring()) return i def image_to_array(i): ''' Converts a Python Imaging Library (PIL) array to a gdalnumeric image. ''' a = gdalnumeric.fromstring(i.tobytes(), 'b') a.shape = i.im.size[1], i.im.size[0] return a def world_to_pixel(geo_matrix, x, y): ''' Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate the pixel location of a geospatial coordinate; from: http://pcjericks.github.io/py-gdalogr-cookbook/raster_layers.html#clip-a-geotiff-with-shapefile ''' ulX = geo_matrix[0] ulY = geo_matrix[3] xDist = geo_matrix[1] yDist = geo_matrix[5] rtnX = geo_matrix[2] rtnY = geo_matrix[4] if xDist < 0: xDist = -xDist if yDist < 0: yDist = -yDist pixel = int((x - ulX) / xDist) # This one probably a bug # In the geo_matrix the yDist appears to be negative # which doesn't make any f*****g sense line = int((ulY - y) / yDist) return (pixel, line) # Since in the file what we have is just a path instead of the file rast = gdal.Open(rast_path) # Can accept either a gdal.Dataset or numpy.array instance if not isinstance(rast, np.ndarray): gt = rast.GetGeoTransform() rast = rast.ReadAsArray() # Create an OGR layer from a boundary shapefile ''' Does that mean all I need to do is just get the driver? ''' # TODO: Update the gdal version #features = ogr.Open(open(features_path).read()) features = ogr.Open(features_path) if features.GetDriver().GetName() == 'ESRI Shapefile': lyr = features.GetLayer(os.path.split( os.path.splitext(features_path)[0])[1]) else: lyr = features.GetLayer() # Get the first feature poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world_to_pixel(gt, minX, maxY) lrX, lrY = world_to_pixel(gt, maxX, minY) # print minX, maxX, minY, maxY # print ulX, ulY, lrX, lrY # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) ''' Wow, does this man really run his codes? ''' pxHeight = int(lrY - ulY) # print "Debug messages" # print pxWidth # print pxHeight # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # In such a case... ulY ends up being negative--can't have that! iY = ulY ulY = 0 # Multi-band image? try: clip = rast[:, ulY:lrY, ulX:lrX] except IndexError: clip = rast[ulY:lrY, ulX:lrX] # Create a new geomatrix for the image gt2 = list(gt) gt2[0] = minX gt2[3] = maxY # Map points to pixels for drawing the boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world_to_pixel(gt2, p[0], p[1])) raster_poly = Image.new('L', (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(raster_poly) rasterize.polygon(pixels, 0) # Fill with zeroes # If the clipping features extend out-of-bounds and ABOVE the raster... if gt[3] < maxY: # The clip features were "pushed down" to match the bounds of the # raster; this step "pulls" them back up premask = image_to_array(raster_poly) # We slice out the piece of our clip features that are "off the map" mask = np.ndarray((premask.shape[-2] - abs(iY), premask.shape[-1]), premask.dtype) mask[:] = premask[abs(iY):, :] mask.resize(premask.shape) # Then fill in from the bottom # Most importantly, push the clipped piece down gt2[3] = maxY - (maxY - gt[3]) else: mask = image_to_array(raster_poly) # Clip the image using the mask try: # No data is used in here to fill the unbounded areas clip = gdalnumeric.choose(mask, (clip, nodata)) # If the clipping features extend out-of-bounds and BELOW the raster... except ValueError: # We have to cut the clipping features to the raster! rshp = list(mask.shape) if mask.shape[-2] != clip.shape[-2]: rshp[0] = clip.shape[-2] if mask.shape[-1] != clip.shape[-1]: rshp[1] = clip.shape[-1] mask.resize(*rshp, refcheck=False) clip = gdalnumeric.choose(mask, (clip, nodata)) # return (clip, ulX, ulY, gt2) # print clip # print gt2 return clip
def apply(self, arg): # iterate over our input raster dataset, masking each file. for raster in self.inputDataset.inputFileArray: rasterInput = rasterRaw_input(raster) # Append a new clip file path for our current raster self.outputDataset.append(raster[:raster.rfind(".")]+"clipped"+raster[raster.rfind("."):]) # Also load as a gdal image to get geotransform # (world file) info geoTrans = srcImage.GetGeoTransform() # Create an OGR layer from a boundary shapefile shapef = ogr.Open("%s.shp" % shp) lyr = shapef.GetLayer(shp) poly = lyr.GetNextFeature() # Convert the layer extent to image pixel coordinates minX, maxX, minY, maxY = lyr.GetExtent() ulX, ulY = world2Pixel(geoTrans, minX, maxY) lrX, lrY = world2Pixel(geoTrans, maxX, minY) # Calculate the pixel size of the new image pxWidth = int(lrX - ulX) pxHeight = int(lrY - ulY) clip = srcArray[:, ulY:lrY, ulX:lrX] # Create a new geomatrix for the image geoTrans = list(geoTrans) geoTrans[0] = minX geoTrans[3] = maxY # Map points to pixels for drawing the # boundary on a blank 8-bit, # black and white, mask image. points = [] pixels = [] geom = poly.GetGeometryRef() pts = geom.GetGeometryRef(0) for p in range(pts.GetPointCount()): points.append((pts.GetX(p), pts.GetY(p))) for p in points: pixels.append(world2Pixel(geoTrans, p[0], p[1])) rasterPoly = Image.new("L", (pxWidth, pxHeight), 1) rasterize = ImageDraw.Draw(rasterPoly) rasterize.polygon(pixels, 0) mask = imageToArray(rasterPoly) # Clip the image using the mask clip = gdalnumeric.choose(mask, \ (clip, 0)).astype(gdalnumeric.uint8) # This image has 3 bands so we stretch each one to make them # visually brighter for i in range(3): clip[i,:,:] = stretch(clip[i,:,:]) # Save ndvi as tiff gdalnumeric.SaveArray(clip, "%s.tif" % output, \ format="GTiff", prototype=raster) # Save ndvi as an 8-bit jpeg for an easy, quick preview clip = clip.astype(gdalnumeric.uint8) gdalnumeric.SaveArray(clip, "%s.jpg" % output, format="JPEG")