Python 查找与多边形相交的光栅单元的索引

Python 查找与多边形相交的光栅单元的索引,python,gdal,ogr,Python,Gdal,Ogr,我想为属于多边形要素或与多边形要素相交的所有光栅单元获取索引列表(行、列)。正在寻找python解决方案,最好是使用gdal/ogr模块 其他帖子建议对多边形进行栅格化,但如果可能的话,我宁愿直接访问单元索引。如果您想手动执行此操作,您需要测试每个单元: 正方形与v多边形相交 正方形v线交点 如果将每个正方形视为二维点,这将变得更容易-现在是点v多边形问题。检查游戏开发论坛中的冲突算法 祝你好运 显然,上面的Rutger解决方案就是解决这个问题的方法,但是我将保留我的解决方案。我开发了一个脚本,

我想为属于多边形要素或与多边形要素相交的所有光栅单元获取索引列表(行、列)。正在寻找python解决方案,最好是使用gdal/ogr模块


其他帖子建议对多边形进行栅格化,但如果可能的话,我宁愿直接访问单元索引。

如果您想手动执行此操作,您需要测试每个单元: 正方形与v多边形相交 正方形v线交点

如果将每个正方形视为二维点,这将变得更容易-现在是点v多边形问题。检查游戏开发论坛中的冲突算法


祝你好运

显然,上面的Rutger解决方案就是解决这个问题的方法,但是我将保留我的解决方案。我开发了一个脚本,通过以下内容实现了我所需要的:

  • 获取我要检查的每个向量特征的边界框
  • 使用边界框限制计算窗口(确定光栅的哪些部分可能具有交点)
  • 在光栅的这一部分中的单元上迭代,并为每个单元构造多边形几何体
  • 使用
    ogr.Geometry.Intersects()
    检查单元是否与多边形特征相交
  • 请注意,我只定义了方法,但我认为实现应该非常清楚——只需使用适当的参数(
    ogr.Geometry
    object和geotransform matrix)调用
    match\u cells
    )。代码如下:

    from osgeo import ogr
    
    # Convert projected coordinates to raster cell indices
    def parse_coords(x,y,gt):
        row,col = None,None
        if x:
            col = int((x - gt[0]) // gt[1])
            # If only x coordinate is provided, return column index
            if not y:
                return col
        if y:
            row = int((y - gt[3]) // gt[5])
            # If only x coordinate is provided, return column index
            if not x:
                return row
        return (row,col)
    
    # Construct polygon geometry from raster cell
    def build_cell((row,col),gt):
        xres,yres = gt[1],gt[5]
        x_0,y_0 = gt[0],gt[3]
        top = (yres*row) + y_0
        bottom = (yres*(row+1)) + y_0
        right = (xres*col) + x_0
        left = (xres*(col+1)) + x_0
        # Create ring topology
        ring = ogr.Geometry(ogr.wkbLinearRing)
        ring.AddPoint(left,bottom)
        ring.AddPoint(right,bottom)
        ring.AddPoint(right,top)
        ring.AddPoint(left,top)
        ring.AddPoint(left,bottom)
        # Create polygon
        box = ogr.Geometry(ogr.wkbPolygon)
        box.AddGeometry(ring)
        return box
    
    # Iterate over feature geometries & check for intersection
    def match_cells(inputGeometry,gt):
        matched_cells = []
        for f,feature in enumerate(inputGeometry):
            geom = feature.GetGeometryRef()
            bbox = geom.GetEnvelope()
            xmin,xmax = [parse_coords(x,None,gt) for x in bbox[:2]]
            ymin,ymax = [parse_coords(None,y,gt) for y in bbox[2:]]
            for cell_row in range(ymax,ymin+1):
                for cell_col in range(xmin,xmax+1):
                    cell_box = build_cell((cell_row,cell_col),gt)
                    if cell_box.Intersects(geom):
                        matched_cells += [[(cell_row,cell_col)]]
        return matched_cells 
    

    因为你没有提供一个有效的例子,所以你的出发点有点不清楚。我创建了一个包含1个多边形的数据集,如果您有一个包含多个多边形的数据集,但只希望以特定多边形为目标,则可以将
    SQLStatement
    where
    添加到
    gdal.Rasterize
    调用中

    样本多边形 光栅化 可以使用
    gdal.Rasterize
    完成光栅化。您需要指定目标网格的属性。如果没有预定义的网格,则可以从多边形本身提取这些网格

    ds = gdal.Rasterize('/vsimem/tmpfile', geojson, xRes=1, yRes=-1, allTouched=True,
                        outputBounds=[-120, 30, -100, 50], burnValues=1, 
                        outputType=gdal.GDT_Byte)
    mask = ds.ReadAsArray()
    ds = None
    gdal.Unlink('/vsimem/tmpfile')
    
    转换为指数 可以使用Numpy从光栅化多边形检索索引:

    y_ind, x_ind = np.where(mask==1)
    

    你知道有什么好的资源描述如何做到这一点吗?如果我可以使用多边形的边界框来限制必须检查的光栅单元的数量,这可能是可行的。多边形可能不适合边界框。使用三角形中点的变化。你可以找到很多。确保对您选择的任何算法进行几个单元测试,以验证其正确性!这听起来比我的解决方案更复杂,但不幸的是,我现在没有时间来研究它。不过,我会在某个时候研究这个问题。谢谢你的建议!是的,在大多数情况下,这不是一个便宜的操作。这是可以理解的。幸运的是,虽然我将要处理的光栅很大,但多边形很小,而且相对较少。因此,对于我需要它执行的任务,这段代码执行得非常快。为什么不使用光栅化呢?它可能会更快,并且给出完全相同的结果。因为我需要单元格索引作为列表,而不是光栅产品。除非我误解了它的工作原理,否则我认为光栅化无法提供此功能。好吧,你赢了!这大约是我的方法的两倍,所需的代码也少得多。您能否建议一种方法,从多边形(shapefile)属性字段中获取刻录值,然后将其与坐标一起传递到numpy数组?使用
    属性=“name”
    代替
    刻录值=1
    ,如果要提取单个多边形,则每个特征的属性值必须是唯一的(或使用单独的步骤)。在我的情况下,不需要将单个特征分开。每个特性都属于一个类,我只需要确保类ID与单元索引保持连接。谢谢你的帮助!您知道有没有一种方法可以使用
    gdal.RasterizeLayer
    来执行类似的操作(即,光栅化为临时文件)?几个月后,我刚刚重温了这段代码&我意识到如果我可以这样做会很方便,因为我可以在光栅化之前应用层属性过滤器。
    y_ind, x_ind = np.where(mask==1)