遥感图像处理:栅格转矢量面、重新赋予栅格投影坐标系


前言

仅仅是分享我在做大棚识别觉得有意义的几个方法,希望别过期


一、栅格转矢量面

import os

from osgeo import gdal, ogr, osr
import cv2
def raster_to_shapefile(raster_path, shapefile_path, threshold_value=128):
    # Open the raster file
    raster_ds = gdal.Open(raster_path)
    band = raster_ds.GetRasterBand(1)
    array = band.ReadAsArray()

    # Apply threshold to create binary image
    binary_array = (array > threshold_value).astype(int)

    # Create a temporary raster file with the binary image
    temp_raster_path = 'temp_binary.tif'
    driver = gdal.GetDriverByName('GTiff')
    temp_raster_ds = driver.Create(temp_raster_path, raster_ds.RasterXSize, raster_ds.RasterYSize, 1, gdal.GDT_Byte)
    temp_raster_ds.SetGeoTransform(raster_ds.GetGeoTransform())
    temp_raster_ds.SetProjection(raster_ds.GetProjection())
    temp_raster_ds.GetRasterBand(1).WriteArray(binary_array)
    temp_raster_ds.FlushCache()

    # Create shapefile
    shp_driver = ogr.GetDriverByName('ESRI Shapefile')
    if shp_driver is None:
        raise Exception("Shapefile driver not available.")

    # Create new shapefile
    if os.path.exists(shapefile_path):
        shp_driver.DeleteDataSource(shapefile_path)
    shp_ds = shp_driver.CreateDataSource(shapefile_path)

    # Define the spatial reference system
    spatial_ref = osr.SpatialReference()
    spatial_ref.ImportFromWkt(raster_ds.GetProjection())

    # Create a new layer
    layer = shp_ds.CreateLayer('raster_layer', srs=spatial_ref, geom_type=ogr.wkbPolygon)

    # Create a field for IDs
    field_def = ogr.FieldDefn('ID', ogr.OFTInteger)
    layer.CreateField(field_def)

    # Raster to polygon conversion
    gdal.Polygonize(temp_raster_ds.GetRasterBand(1), None, layer, 0, [], callback=None)

    # Clean up
    temp_raster_ds = None
    raster_ds = None
    shp_ds = None
    os.remove(temp_raster_path)

以及我项目中存在一个最大矢量面的问题

def remove_largest_polygon_and_convert_to_shapefile(raster_path, shapefile_path, threshold_value=128):
    # 打开栅格文件
    raster_ds = gdal.Open(raster_path)
    if raster_ds is None:
        raise Exception(f"无法打开栅格文件: {raster_path}")

    # 获取栅格波段并读取数组数据
    band = raster_ds.GetRasterBand(1)
    array = band.ReadAsArray()

    # 应用阈值进行二值化处理
    binary_array = (array > threshold_value).astype(int)

    # 创建临时栅格文件
    temp_raster_path = 'temp_binary.tif'
    driver = gdal.GetDriverByName('GTiff')
    temp_raster_ds = driver.Create(temp_raster_path, raster_ds.RasterXSize, raster_ds.RasterYSize, 1, gdal.GDT_Byte)

    # 设置临时栅格的地理变换和投影
    temp_raster_ds.SetGeoTransform(raster_ds.GetGeoTransform())
    temp_raster_ds.SetProjection(raster_ds.GetProjection())
    temp_raster_ds.GetRasterBand(1).WriteArray(binary_array)
    temp_raster_ds.FlushCache()

    # 创建 shapefile
    shp_driver = ogr.GetDriverByName('ESRI Shapefile')
    if shp_driver is None:
        raise Exception("Shapefile 驱动不可用")

    # 如果文件已存在,则删除
    if os.path.exists(shapefile_path):
        shp_driver.DeleteDataSource(shapefile_path)
    shp_ds = shp_driver.CreateDataSource(shapefile_path)

    # 从栅格中提取空间参考系统
    spatial_ref = osr.SpatialReference()
    spatial_ref.ImportFromWkt(raster_ds.GetProjection())

    # 打印空间参考系统信息
    spatial_ref_wkt = spatial_ref.ExportToWkt()
    print("空间参考系统 WKT 信息:")
    print(spatial_ref_wkt)

    # 创建图层并应用空间参考系统
    layer = shp_ds.CreateLayer('raster_layer', srs=spatial_ref, geom_type=ogr.wkbPolygon)

    # 为图层创建一个 ID 字段
    field_def = ogr.FieldDefn('ID', ogr.OFTInteger)
    layer.CreateField(field_def)

    # 将栅格转换为多边形
    gdal.Polygonize(temp_raster_ds.GetRasterBand(1), None, layer, 0, [], callback=None)

    # 删除最大多边形
    layer_defn = layer.GetLayerDefn()
    max_area = 0
    max_feature = None
    for feature in layer:
        geom = feature.GetGeometryRef()
        area = geom.GetArea()
        if area > max_area:
            max_area = area
            max_feature = feature

    if max_feature:
        layer.DeleteFeature(max_feature.GetFID())

    # 清理临时数据
    temp_raster_ds = None
    raster_ds = None
    shp_ds = None
    os.remove(temp_raster_path)
    print(f"已创建 shapefile 并删除最大多边形: {shapefile_path}")

二、赋予矢量栅格投影坐标系

import os
from osgeo import gdal, ogr, osr
import cv2
def copy_geoCoordSys(tif_proj, tif_geotrans,Image_Line):
    def def_geoCoordSys(read_path, img_transf, img_proj):
        array_dataset = gdal.Open(read_path)
        img_array = array_dataset.ReadAsArray(0, 0, array_dataset.RasterXSize, array_dataset.RasterYSize)
        if 'int8' in img_array.dtype.name:
            datatype = gdal.GDT_Byte
        elif 'int16' in img_array.dtype.name:
            datatype = gdal.GDT_UInt16
        else:
            datatype = gdal.GDT_Float32

        if len(img_array.shape) == 3:
            img_bands, im_height, im_width = img_array.shape
        else:
            img_bands, (im_height, im_width) = 1, img_array.shape
        filename = read_path[:-4] + '_proj' + read_path[-4:]
        driver = gdal.GetDriverByName("GTiff")  # 创建文件驱动
        dataset = driver.Create(filename, im_width, im_height, img_bands, datatype)
        dataset.SetGeoTransform(img_transf)  # 写入仿射变换参数
        dataset.SetProjection(img_proj)  # 写入投影

        # 写入影像数据
        if img_bands == 1:
            dataset.GetRasterBand(1).WriteArray(img_array)
        else:
            for i in range(img_bands):
                dataset.GetRasterBand(i + 1).WriteArray(img_array[i])
        print(read_path, 'geoCoordSys get!')

    cv2.imwrite('pre.tif',img=Image_Line)
    def_geoCoordSys('pre.tif', tif_geotrans, tif_proj)

使用案例

来源于大棚识别的项目的部分代码

# 线化处理:使用霍夫变换直线检测来提取直线
	dataloader, original_width, original_height, tif_proj, tif_geotrans = get_dataset(law_tif_path, stride=128, size=(256, 256))
    median_img = cv2.medianBlur(head_img-edge_img, 5)
    # 二值化
    ret, BW_Original = cv2.threshold(median_img, 128, 255, cv2.THRESH_BINARY)
    # 生成二值化的边缘分割图以及地块图
    cv2.imwrite(r"pre2.tif", BW_Original)
    cv2.imwrite(r"edge.tif", edge_img)
    # 将投影坐标系注入进生成的pre_proj.tif文件中,并生成output.shp的矢量数据
    copy_geoCoordSys(tif_proj, tif_geotrans, Image_Line=median_img)
    remove_largest_polygon_and_convert_to_shapefile("pre_proj.tif", "output.shp")

总结

最终,它们的分割图会被赋予原来的坐标系 ,也刚好在底图上显示,分割效果不怎么好其实。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘘嘘出差

给个1分钱都行,主要看不到活人

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值