次のコードのレビューをリクエストしています。空間参照イメージとポリゴンがあります。新しい画像 (クリップされた領域) を保存するために、この画像をクリップするコード (以下を参照) を書きました。この関数は、フィーチャクラスのジオメトリに基づいてラスターをクリップします。ジオメトリに基づくクリッピングとは、フィーチャ クラス内のすべてのフィーチャの境界を使用してラスターをクリップすることを意味し、これらのフィーチャの最小境界矩形ではありません。
入力: ポリゴン レイヤーと 1 つ以上のラスター レイヤー 出力: 新しいラスター レイヤー、ポリゴン境界にクリップ
import osgeo.gdal
import shapefile
import struct, numpy, pylab
import numpy as np
import ogr
import osr,gdal
from shapely.geometry import Polygon
import osgeo.gdal as gdal
import sys
from osgeo import gdal, gdalnumeric, ogr, osr
import Image,ImageDraw
def world2Pixel(geoMatrix, x, y):
"""
Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate
the pixel location of a geospatial coordinate
(http://geospatialpython.com/2011/02/clip-raster-using-shapefile.html)
geoMatrix
[0] = top left x (x Origin)
[1] = w-e pixel resolution (pixel Width)
[2] = rotation, 0 if image is "north up"
[3] = top left y (y Origin)
[4] = rotation, 0 if image is "north up"
[5] = n-s pixel resolution (pixel Height)
"""
ulX = geoMatrix[0]
ulY = geoMatrix[3]
xDist = geoMatrix[1]
yDist = geoMatrix[5]
rtnX = geoMatrix[2]
rtnY = geoMatrix[4]
pixel = np.round((x - ulX) / xDist).astype(np.int)
line = np.round((ulY - y) / xDist).astype(np.int)
return (pixel, line)
def Pixel2world(geoMatrix, x, y):
ulX = geoMatrix[0]
ulY = geoMatrix[3]
xDist = geoMatrix[1]
yDist = geoMatrix[5]
coorX = (ulX + (x * xDist))
coorY = (ulY + (y * yDist))
return (coorX, coorY)
def RASTERClipByPolygon(inFile,poly,outFile):
# Open the image as a read only image
ds = osgeo.gdal.Open(inFile,gdal.GA_ReadOnly)
# Check the ds (=dataset) has been successfully open
# otherwise exit the script with an error message.
if ds is None:
raise SystemExit("The raster could not openned")
# Get image georeferencing information.
geoMatrix = ds.GetGeoTransform()
ulX = geoMatrix[0]
ulY = geoMatrix[3]
xDist = geoMatrix[1]
yDist = geoMatrix[5]
rtnX = geoMatrix[2]
rtnY = geoMatrix[4]
# get the WKT (= Well-known text)
dsWKT = ds.GetProjectionRef()
# get driver information
DriverName = ds.GetDriver().ShortName
# open shapefile (= border of are of interest)
shp = osgeo.ogr.Open(poly)
if len(shp.GetLayer()) != 1:
raise SystemExit('The shapefile must have exactly one layer')
# Create an OGR layer from a boundary shapefile
layer = shp.GetLayer(0)
feature = layer.GetNextFeature()
geometry = feature.GetGeometryRef()
# Make sure that it is a polygon
if geometry.GetGeometryType() != osgeo.ogr.wkbPolygon:
raise SystemExit('This module can only load polygon')
# get Extent of the clip area
X_min, X_max, Y_min, Y_max = layer.GetExtent()
# Convert the layer extent to image pixel coordinates
uldX, uldY = world2Pixel(geoMatrix, X_min, Y_max)
lrdX, lrdY = world2Pixel(geoMatrix, X_max, Y_min)
# Calculate the pixel size of the new image
pxWidth = int(lrdX - uldX)
pxHeight = int(lrdY - uldY)
# get the Coodinate of left-up vertex of the pixel
X_minPixel, Y_maxPixel = Pixel2world(geoMatrix, uldX, uldY)
# get polygon's vertices
pts = geometry.GetGeometryRef(0)
points = []
for p in range(pts.GetPointCount()):
points.append((pts.GetX(p), pts.GetY(p)))
pnts = np.array(points).transpose()
# work band by band
nBands = ds.RasterCount
# panchromatic
if nBands == 1:
band = ds.GetRasterBand(1)
# get nodata value
nodata = band.GetNoDataValue()
# convert band in Array
bandArray = band.ReadAsArray()
del band
# clip arrey
bandArray_Area = bandArray[uldY:lrdY, uldX:lrdX]
del bandArray
# Create 2D Polygon Mask. Mode 'L', not '1', because
# Numpy-1.5.0 / PIL-1.1.7 does not support the numpy.array(img)
# conversion nicely for bivalue images.
img = Image.new('L', (pxWidth, pxHeight), 0)
target_ds = gdal.GetDriverByName(DriverName).Create(outFile, pxWidth, pxHeight, nBands, ds.GetRasterBand(1).DataType)
target_ds.SetGeoTransform((X_minPixel, xDist, rtnX,Y_maxPixel, rtnY, yDist))
pixels, line = world2Pixel(target_ds.GetGeoTransform(),pnts[0],pnts[1])
listdata = [(pixels[i],line[i]) for i in xrange(len(pixels))]
ImageDraw.Draw(img).polygon(listdata, outline=1, fill=1)
mask = numpy.array(img)
bandArray_Masked = bandArray_Area*mask
del bandArray_Area, mask
target_ds.GetRasterBand(nBands).WriteArray(bandArray_Masked)
target_ds.GetRasterBand(nBands).SetNoDataValue(nodata)
else:
img = Image.new('L', (pxWidth, pxHeight), 0)
target_ds = gdal.GetDriverByName(DriverName).Create(outFile, pxWidth, pxHeight, nBands, ds.GetRasterBand(1).DataType)
target_ds.SetGeoTransform((X_min, xDist, rtnX,Y_max, rtnY, yDist))
pixels, line = world2Pixel(target_ds.GetGeoTransform(),pnts[0],pnts[1])
listdata = [(pixels[i],line[i]) for i in xrange(len(pixels))]
ImageDraw.Draw(img).polygon(listdata, outline=1, fill=1)
mask = numpy.array(img)
for bandno in range(1, nBands+1):
band = ds.GetRasterBand(bandno)
nodata = band.GetNoDataValue()
# convert band in Array
bandArray = band.ReadAsArray()
del band
# clip arrey
bandArray_Area = bandArray[ulY:lrY, ulX:lrX]
del bandArray
bandArray_Masked = bandArray_Area*mask
target_ds.GetRasterBand(bandno).WriteArray(bandArray_Masked)
del bandArray_Area
target_ds.GetRasterBand(bandno).SetNoDataValue(nodata)
# set the reference info
if len(dsWKT) is 0:
# Source has no projection (needs GDAL >= 1.7.0 to work)
target_ds.SetProjection('LOCAL_CS["arbitrary"]')
else:
# Make the target raster have the same projection as the source
target_ds.SetProjection(dsWKT)
target_ds = None