拼接掩模 R CNN 预测了由影像片分隔的地理空间多边形

Stitching Mask R CNN predicted geospatial polygons separated by image chips

提问人:Gautam Mathur 提问时间:11/14/2023 最后编辑:MatifouGautam Mathur 更新时间:11/15/2023 访问量:61

问:

我和我的团队最近使用Mask-R-CNN模型,使用卫星图像来预测农田的空间范围。该过程包括将卫星图像分割成 512 X 512 像素的芯片,从那里预测场,然后将每个图像的多边形连接起来。我们发现该模型没有在 512X512 芯片的边缘进行预测,这在图像芯片的边缘留下了没有数据的区域:

合并后的数据集最终如下所示:

我想想出已经分离的多边形,以便进行操作,以便合并,提出了以下修复程序:

  • 我使用了较大未裁剪图像的角坐标和图像的空间分辨率,并创建了模拟 512X512 图像芯片的渔网多边形。
  • 然后,我为每个渔网设置了 shapefile 的子集。
  • 我查看了子集中每个多边形的顶点坐标,发现子集中每个东边和北边都在边界 2 m 以内,并且重复了不止一次(北边和南边的北边,东边和西边的边线)。我这样做是因为我听起来多边形在 2 m 标记附近被切断,并且它们被切断的方式最终是一条直线——所以我假设它们会有重复的东移/北向)。
  • 对于每个多边形中包含任何这些东向和北纬的每个顶点,我将相应的坐标更改为渔网的相关坐标。
  • 对每个渔网内的多边形完成此操作后,我使用 gpd.unary_union 将整个数据集合并为一个多多边形。这合并了多边形,其顶点已更改为位于渔网边界的两侧。这会将整个数据集更改为单个多面。然后我分解了多多边形。 以下是应用此技术后的图像图片。

在大多数情况下,该函数是成功的。在很多情况下,它只合并部分多边形

这是可以接受的,因为它仍然合并为一个多边形并代表多边形的大部分区域,但并不理想。在少数情况下,其中一些多边形仍未合并

我想知道这里是否有人知道我应该如何修改我的代码以捕获其中一些混合多边形并将它们合并,甚至修复部分合并的多边形。请让我知道你的想法。非常感谢!代码如下:

import os
import pandas as pd
import geopandas as gpd
import rasterio
from shapely.geometry import Polygon
from collections import Counter
from pathlib import Path


def stitchshp(img, polys, endpath):
    img = rasterio.open(img)
    polys = gpd.read_file(polys)
   #Making Fishnets from the image
    firsteast = img.bounds.left
    firstnorth = img.bounds.top
    easting = [img.bounds.left]
    northing = [img.bounds.top]

    def funeast(image):
        while image < img.bounds.right:
            image = image +(0.5*512)
            easting.append(image)
            return funeast(image)
        
    def funnorth(image):
        while image > img.bounds.bottom:
            image = image -(0.5*512)
            northing.append(image)
            return funnorth(image)


    funeast(firsteast)
    funnorth(firstnorth)

    geom = []

    for i in range(len(northing)):
        for j in range(len(easting)):
            coords = [(easting[j], northing[i]), (easting[j]+(0.5*512), northing[i]), (easting[j]+(0.5*512), northing[i]-(0.5*512)), (easting[j], northing[i]-(0.5*512))]
            geom.append(Polygon(coords))

    table = gpd.GeoDataFrame({"geometry": geom}, crs ={'init' :'epsg:32644'} )


    #using fishnets to subset manipulate, and stitch polygons
    allpolyslist = []
    for fish in range(len(table.geometry)):
        net = table.geometry[fish]
        east = max([i[0] for i in [*net.exterior.coords]])
        west = min([i[0] for i in [*net.exterior.coords]])
        north = max([i[1] for i in [*net.exterior.coords]])
        south = min([i[1] for i in [*net.exterior.coords]])
        subpolys = polys[polys.intersects(net)]
        net = gpd.GeoSeries(net)

        maxeast = []
        mineast = []
        maxnorth = []
        minnorth = []
        for sequ in [[*i.exterior.coords] for i in subpolys.geometry]:
            maxeast.append(max(i[0] for i in sequ))
            mineast.append(min(i[0] for i in sequ))
            maxnorth.append(max(i[1] for i in sequ))
            minnorth.append(min(i[1] for i in sequ))
        
        eastdict = Counter(maxeast)
        eastchange = [key for key, value in eastdict.items() if key >east-2 and key <east+2 and value>1]
        westdict = Counter(mineast)
        westchange = [key for key, value in westdict.items() if key <west+2 and key >west-2 and value>1]
        northdict = Counter(maxnorth)
        northchange = [key for key, value in northdict.items() if key >north-2 and key <north+2 and value>1]
        southdict = Counter(minnorth)
        southchange = [key for key, value in southdict.items() if key <south+2 and key >south-2 and value>1]

        polylists = [[*i.exterior.coords] for i  in subpolys.geometry]

        properpolys = []
        for poly in polylists:
            if len(poly)>6:
                properpolys.append(poly)


        for poly in properpolys:
            for j in range(len(poly)):
                if poly[j][0] in eastchange:
                    poly[j] = (east, poly[j][1])
                if poly[j][0] in westchange:
                    poly[j] = (west, poly[j][1])
                if poly[j][1] in northchange:
                    poly[j] = (poly[j][0], north)
                if poly[j][1] in southchange:
                    poly[j] = (poly[j][0], south)
        

        
        allpolyslist = allpolyslist + properpolys
    print("ok, iterated thru!")
    #gpd.GeoSeries([Polygon(i) for i in allpolyslist]).plot()   

    allpolylist = [Polygon(i) for i in allpolyslist]
    print("converted to polygons!")
    allpolydict = gpd.GeoDataFrame({"geometry": allpolylist}, crs = {'init' :'epsg:32644'})
    merge = allpolydict.unary_union
    merge = gpd.GeoSeries(merge)
    merge = merge.explode()
    print("exploded polys!")
    united = gpd.GeoDataFrame(geometry = merge)
    print("Made final df!")
    united.to_file(endpath, crs = allpolydict.crs)

GIS 地理空间 多边形 Geopandas 掩码-RCNN

评论


答:

-1赞 Pieter 11/15/2023 #1

为了避免图像边缘的检测质量较差,您可以在稍大的重叠芯片上运行检测:例如,在 4 个方向上添加 32 个像素。

检测后,可以将多余的边框像素设置为黑色,以便在对检测进行多边形化时忽略它们。这确保了一致的检测质量,并避免了您遇到的问题。

以下代码片段显示了如何忽略额外的边框像素:

# Make the pixels at the borders of the prediction black so they are ignored
if border_pixels_to_ignore and border_pixels_to_ignore > 0:
    mask_arr[0:border_pixels_to_ignore, :] = 0  # Left border
    mask_arr[-border_pixels_to_ignore:, :] = 0  # Right border
    mask_arr[:, 0:border_pixels_to_ignore] = 0  # Top border
    mask_arr[:, -border_pixels_to_ignore:] = 0  # Bottom border

这个“技巧”也用于正射,这是我开发的一些软件,可以更轻松地检测射图像上的东西。可以在此处找到获取上述代码片段的完整相关代码。

评论

0赞 Jesse 11/15/2023
请不要只是发布一些工具或库作为答案。至少在答案本身中展示它是如何解决问题的
0赞 Pieter 11/15/2023
哎呀,我以为我已经这样做了,但显然还不清楚......我会再试一次。