GDAL和Python:如何获取具有特定值的所有单元格的坐标?


12

我有一个Arc / Info Binary Grid(具体地说,是ArcGIS流累积栅格),并且我想识别所有具有特定值(或值范围)的像元。最终,我想要一个表示这些单元的点的shapefile。

我可以使用QGIS打开hdr.adf并获得此结果,工作流程为:

  • QGIS>栅格菜单>栅格计算器(用目标值标记所有点)
  • QGIS>栅格菜单>多边形
  • QGIS>矢量菜单>几何子菜单>多边形形心
  • 编辑质心以删除不需要的多质心(这些质心= 0)

这种方法“完成了任务”,但是对我来说并不有吸引力,因为它创建了两个我必须删除的文件,然后我必须从形心的shapefile中删除不需要的记录(即那些= 0)。

一个现有的问题可以解决这个问题,但是它是针对ArcGIS / ArcPy量身定制的,我想留在FOSS领域。

是否有人拥有可查询栅格像元值的现有GDAL / Python配方/脚本,并且在找到目标值(或目标范围内的值)时,将记录添加到shapefile中?这样不仅可以避免与UI的交互,而且还可以通过一次创建干净的结果。

我通过与Chris Garrard的一个演示文稿进行对比而对此进行了射击,但是光栅工作不在我的操盘手,并且我不想用我的弱代码使问题变得混乱。

如果有人希望使用确切的数据集,我将它作为.zip放在这里


[编辑注释]留给后代保留。请参阅与om_henners的评论交流。基本上,x / y(行/列)值被翻转。最初的答案是这样的:

(y_index, x_index) = np.nonzero(a == 1000)

倒像这样:

(x_index, y_index) = np.nonzero(a == 1000)

当我第一次遇到屏幕快照中说明的问题时,我想知道我是否正确地实现了几何图形,并通过在此行中翻转x / y坐标值进行了实验:

point.SetPoint(0, x, y)

..如..

point.SetPoint(0, y, x)

但是那没有用。而且我不认为尝试翻转om_henners的Numpy表达式中的值,是错误地认为在任一行上翻转它们都是等效的。我认为真正的问题分别与x_sizey_size值有关,当行和列索引用于计算单元格的点坐标时,将应用和。30-30

[原始编辑]

@om_henners,我正在尝试您的解决方案,与使用ogr(invisibleroads.comChris Garrard)制作点shapefile的一些方法配合使用,但是我遇到了一个问题,即这些点的显示好像在一条直线上反射一样通过315/135度。

浅蓝色点:由我的QGIS方法创建,上方

紫点:由GDAL / OGR py代码在下面创建

在此处输入图片说明


[解决了]

此Python代码实现了@om_henners提出的完整解决方案。我已经对其进行了测试,并且可以正常工作。谢啦!


from osgeo import gdal
import numpy as np
import osgeo.ogr
import osgeo.osr

path = "D:/GIS/greeneCty/Greene_DEM/GreeneDEM30m/flowacc_gree/hdr.adf"
print "\nOpening: " + path + "\n"

r = gdal.Open(path)
band = r.GetRasterBand(1)

(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()

a = band.ReadAsArray().astype(np.float)

# This evaluation makes x/y arrays for all cell values in a range.
# I knew how many points I should get for ==1000 and wanted to test it.
(y_index, x_index) = np.nonzero((a > 999) & (a < 1001))

# This evaluation makes x/y arrays for all cells having the fixed value, 1000.
#(y_index, x_index) = np.nonzero(a == 1000)

# DEBUG: take a look at the arrays..
#print repr((y_index, x_index))

# Init the shapefile stuff..
srs = osgeo.osr.SpatialReference()
#srs.ImportFromProj4('+proj=utm +zone=15 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs')
srs.ImportFromWkt(r.GetProjection())

driver = osgeo.ogr.GetDriverByName('ESRI Shapefile')
shapeData = driver.CreateDataSource('D:/GIS/01_tutorials/flow_acc/ogr_pts.shp')

layer = shapeData.CreateLayer('ogr_pts', srs, osgeo.ogr.wkbPoint)
layerDefinition = layer.GetLayerDefn()

# Iterate over the Numpy points..
i = 0
for x_coord in x_index:
    x = x_index[i] * x_size + upper_left_x + (x_size / 2) #add half the cell size
    y = y_index[i] * y_size + upper_left_y + (y_size / 2) #to centre the point

    # DEBUG: take a look at the coords..
    #print "Coords: " + str(x) + ", " + str(y)

    point = osgeo.ogr.Geometry(osgeo.ogr.wkbPoint)
    point.SetPoint(0, x, y)

    feature = osgeo.ogr.Feature(layerDefinition)
    feature.SetGeometry(point)
    feature.SetFID(i)

    layer.CreateFeature(feature)

    i += 1

shapeData.Destroy()

print "done! " + str(i) + " points found!"

1
代码的快速提示:您可以将栅格投影用作shapefile投影srs.ImportFromWkt(r.GetProjection())(而不必从已知的proj字符串创建投影)。
om_henners 2012年

您的代码执行了我正在寻找的所有操作,但是它不包含栅格像元值,因为您编写了numpy过滤器时只包含了值=1000。您能指出正确的方向在其中包含栅格像元值吗?输出?谢谢!
布伦特·爱德华兹

Answers:


19

在GDAL中,您可以将栅格作为numpy数组导入。

from osgeo import gdal
import numpy as np

r = gdal.Open("path/to/raster")
band = r.GetRasterBand(1) #bands start at one
a = band.ReadAsArray().astype(np.float)

然后,使用numpy可以很容易地获得与布尔表达式匹配的数组的索引:

(y_index, x_index) = np.nonzero(a > threshold)
#To demonstate this compare a.shape to band.XSize and band.YSize

从栅格地理变换中,我们可以获得诸如左上角的x和y坐标以及像元大小之类的信息。

(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()

左上方的单元格对应于a[0, 0]。Y大小将始终为负,因此使用x和y索引可以基于索引计算每个像元的坐标。

x_coords = x_index * x_size + upper_left_x + (x_size / 2) #add half the cell size
y_coords = y_index * y_size + upper_left_y + (y_size / 2) #to centre the point

从这里开始,使用OGR创建shapefile就足够简单了。有关一些示例代码,请参见此问题,以获取有关如何使用点信息生成新数据集的信息。


嘿伙计,我在实现此功能时遇到了一个小问题。我更新了问题,以包括我正在使用的代码和我得到的内容的摘要。基本上,.py代码正在创建QGIS方法所生成内容的镜像(点放置)。我的实现中的要点不在栅格范围之内,因此问题必须出在我的代码上。:=我希望你能有所启发。谢谢!
elrobis

抱歉-完全是我的错。在GDAL中导入栅格时,行是y方向,列是x方向。我已经更新了上面的代码,但是诀窍是使用(y_index, x_index) = np.nonzero(a > threshold)
om_henners

1
另外,以防万一,请注意在两个方向上将一半的像元大小加到坐标上,以使点在像元中居中。
om_henners 2012年

是的,这就是问题所在。当我第一次遇到该错误时(如屏幕抓图所示),我想知道我是否正确地实现了点几何,所以当我做.shp--- only 时,我尝试将x / y翻转为y / x。工作,也没有附近的地方。因为x值是十万,而y是数百万,所以我没有感到震惊,所以这让我很困惑。我不认为尝试将它们翻转回Numpy表情。非常感谢您的帮助,这很酷。正是我想要的。:)
elrobis

4

为什么不使用QGIS中的Sexante工具箱?有点像ArcGIS的模型构建器。这样,您可以链接操作并将其视为一个操作。如果我没有记错的话,您可以自动删除中间文件并删除不需要的记录。


1

将数据导入postgis(具有栅格支持)并在其中使用功能可能会有所帮助。本教程可能包含您需要的元素。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.