GDAL 实现投影转换

^ 关注我,带你一起学GIS ^

前言

在GIS开发中,对于数据源首先要确定的第一件事就是坐标系统,这就涉及到坐标转换处理问题。而经常遇到的便是Shapefile数据的投影转换,如何高效、准确的将源数据坐标系转换到目标坐标系是我们需要研究解决的问题。

在之前的文章中讲了如何使用GDAL或者ogr2ogr工具将txt以及csv文本数据转换为Shp格式,本篇教程在之前一系列文章的基础上讲解如何使用GDAL 实现投影转换

如果你还没有看过,建议从以上内容开始。

1. 开发环境

本文使用如下开发环境,以供参考。

时间:2025年

系统:Windows 11

Python:3.11.7

GDAL:3.11.1

2. 数据准备

如下是本文选取的全国省级行政区Shp数据(数据坐标系为4326):

部分景点数据:

3. 投影形式

参考网站:https://epsg.io/4490

坐标定义信息具有多种格式,可以选择符合通用标准的OGC格式,下面以EPSG编码4490,即CGCS2000坐标系为例进行展示。

  • OGC WKT
css 复制代码
GEOGCS["China Geodetic Coordinate System 2000",    DATUM["China_2000",        SPHEROID["CGCS2000",6378137,298.257222101,            AUTHORITY["EPSG","1024"]],
        AUTHORITY["EPSG","1043"]],
    PRIMEM["Greenwich",0,        AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.0174532925199433,        AUTHORITY["EPSG","9122"]],
    AUTHORITY["EPSG","4490"]]
  • ESRI WKT
css 复制代码
GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",    DATUM["D_China_2000",        SPHEROID["CGCS2000",6378137.0,298.257222101]],
    PRIMEM["Greenwich",0.0],
    UNIT["Degree",0.0174532925199433]]
  • PROJ.4
ini 复制代码
+proj=longlat +ellps=GRS80 +no_defs +type=crs
  • Proj4js
arduino 复制代码
proj4.defs("EPSG:4490","+proj=longlat +ellps=GRS80 +no_defs +type=crs");
  • GeoServer
css 复制代码
4490=GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]

4. 获取图层坐标系统

使用GetSpatialRef方法可以获取图层坐标参考,若图层缺少投影信息,则返回None

ini 复制代码
# 获取图层及坐标系统
sourceLayer = shpDs.GetLayer(0)
geomType = sourceLayer.GetGeomType()
sourceSrs = sourceLayer.GetSpatialRef()

也可以使用Geometry对象方法GetSpatialReference获取。

ini 复制代码
# 获取坐标系统
geom = feature.GetGeometryRef()
sourceSrs = geom.GetSpatialReference()

5. 图层投影转换

5.1. 导入依赖

Shp作为一种矢量数据格式,可以使用矢量库OGR进行处理,用于打开数据源和获取图层。还需要引入osr模块用于坐标定义以及os模块用于判断文件数据路径。

javascript 复制代码
from osgeo import ogr,osr
import os

5.2. 获取数据

定义一个方法LayerProject用于图层投影转换,该方法接收两个参数,一个源数据文件路径sourcePath,一个投影转换文件数据路径projectPath

python 复制代码
"""
说明:GDAL 投影转换
参数:
    -sourcePath:源文件Shp数据路径
    -projectPath:投影转换图层数据路径
"""
def LayerProject(sourcePath,projectPath):

按照老规矩添加数据驱动,使用checkFilePath方法检查文件路径是否存在,使用checkDriver判断数据驱动是否正常,之后获取图层及坐标系统。

ini 复制代码
# 检查文件是否存在
checkFilePath(sourcePath)
checkFilePath(projectPath)

# 获取数据驱动
shpDriver = ogr.GetDriverByName("ESRI Shapefile")

# 检查数据驱动是否正常
checkDriver(shpDriver)

# 获取数据源
shpDs = shpDriver.Open(sourcePath)

# 获取源图层及坐标信息
sourceLayer = shpDs.GetLayer(0)
geomType = sourceLayer.GetGeomType()
sourceSrs = sourceLayer.GetSpatialRef()

# 获取源数据结构
featureDefn = sourceLayer.GetLayerDefn()
fieldCount = featureDefn.GetFieldCount()

文件和数据驱动检查方法定义如下。

python 复制代码
"""
说明:检查文件路径是否正常
参数:
    -filePath:文件数据路径
"""
def checkFilePath(filePath):
    if os.path.exists(filePath):
        print(f"{filePath} 文件数据路径存在")
    else:
        print(f"{filePath} 文件数据路径不存在,请检查!")

"""
说明:检查数据驱动是否正常
"""
def checkDriver(driver):
    if driver is None:
        print("数据驱动不可用")
        return False

5.3. 创建投影

使用osr.SpatialReference()创建空间参考,然后将投影信息导入到坐标系统。可以使用如下多种方法:

objectivec 复制代码
- ImportFromEPSG(SpatialReference self, int arg)
- ImportFromESRI(SpatialReference self, char ** ppszInput)
- ImportFromProj4(SpatialReference self, char * ppszInput)
- ImportFromUSGS(SpatialReference self, long proj_code, long zone=0, double [15] argin=0, long datum_code=0)
- ImportFromWkt(SpatialReference self, char ** ppszInput)

其中个人觉得最简单方便的还是ImportFromEPSG方法。

5.4. 创建投影图层

使用CreateDataSource方法创建投影数据源和图层,并根据源数据复制要素。创建图层方法CreateLayer第二个参数用于指定数据坐标系,坐标系统可以使用ImportFromEPSG方法定义,只需传入一个EPSG编码。

python 复制代码
"""
投影转换操作
"""
# 创建投影数据源
prjDs = shpDriver.CreateDataSource(projectPath)

# 投影坐标对象
srs = osr.SpatialReference()
srs.ImportFromEPSG(4522)

# 创建投影图层
prjLayer = prjDs.CreateLayer("prj_layer",srs,geomType)

# 添加属性结构
for i in range(fieldCount):
    fieldDefn = featureDefn.GetFieldDefn(i)
    prjLayer.CreateField(fieldDefn)

# 写入要素
for feature in sourceLayer:    
    prjLayer.CreateFeature(feature)    

5.5. 导出投影

可以使用以下方法导出投影信息。

objectivec 复制代码
- ExportToPrettyWkt(SpatialReference self, int simplify=0)
- ExportToProj4(SpatialReference self)
- ExportToUSGS(SpatialReference self)
- ExportToWkt(SpatialReference self, char ** options=None)
- ExportToXML(SpatialReference self, char const * dialect="")

5.6. 几何投影

使用CoordinateTransformation方法定义转换信息,第一个参数为源数据坐标系,第二个参数为目标投影坐标系,然后调用Geometry对象方法Transform进行坐标转换。

scss 复制代码
# 源数据坐标参考
sourceSrs = osr.SpatialReference()
sourceSrs.ImportFromEPSG(4326)
print("源数据坐标系名称:",sourceSrs.GetName())

# 添加几何对象
geom = feature.GetGeometryRef()
print("之前的坐标:",geom.GetX(),geom.GetY())

# 几何投影
targetSrs = osr.SpatialReference()
targetSrs.ImportFromEPSG(4522)
print("目标数据坐标系名称:",targetSrs.GetName())

# 坐标转换
coordsTransform = osr.CoordinateTransformation(sourceSrs,targetSrs)
geom.Transform(coordsTransform)

print("之后的坐标:",geom.GetX(),geom.GetY())

坐标系输出信息显示如下。

5.7. 创建投影文件

对于缺少.prj文件的数据可以使用空间参考方法MorphToESRI()修改坐标信息,使用ExportToWkt()方法导出坐标参考后将其写入投影文件中。

创建一个方法CreatePrjFile用于创建投影文件。

python 复制代码
"""
说明:创建.prj文件
参数:
    -shpPath: Shp文件路径
"""
def CreatePrjFile(shpPath):
    prjSrs = osr.SpatialReference()
    prjSrs.ImportFromEPSG(4522)

    prjSrs.MorphToESRI()

    fileName = os.path.splitext(shpPath)[0]
    prjFile = fileName + ".prj"

    with open(prjFile,"w") as f:
        f.write(prjSrs.ExportToWkt())
        print(f"成功创建投影文件: {prjFile}")

6. 注意事项

windows开发环境中同时安装GDALPostGIS,其中投影库PROJ的环境变量指向PostGIS的安装路径,在运行GDAL程序时,涉及到要素、几何与投影操作时会导致异常。具体意思为GDAL不支持PostGIS插件中的投影库版本,需要更换投影库或者升级版本。

RuntimeError: PROJ: proj_identify: D:Program FilesPostgreSQL13sharecontribpostgis-3.5projproj.db contains DATABASE.LAYOUT.VERSION.MINOR = 2 whereas a number >= 5 is expected. It comes from another PROJ installation.

解决办法为修改PROJ的环境变量到GDAL支持的版本或者在GDAL程序开头添加以下代码:

python 复制代码
os.environ['PROJ_LIB'] = r'D:\Programs\Python\Python311\Libsite-packages\osgeo\data\proj'

图片效果


OpenLayers示例数据下载,请在公众号后台回复:ol数据

全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试

GIS之路 公众号已经接入了智能 助手,可以在对话框进行提问,也可以直接搜索历史文章进行查看。

都看到这了,不要忘记点赞、收藏 + 关注

本号不定时更新有关 GIS开发 相关内容,欢迎关注


GeoTools 开发合集(全)

OpenLayers 开发合集

GDAL 实现矢量合并

GDAL 图层合并操作

国产版的Google Earth,吉林一号卫星App"共生地球"来了

2026年全国自然资源工作会议召开

日本欲打造"本土版"星链系统

GDAL 实现矢量裁剪

GDAL 实现空间分析

GDAL 空间关系解析

GDAL 实现数据空间查询

GDAL 实现数据属性查询

吉林一号国内首张高分辨率彩色夜光卫星影像发布

GDAL 实现创建几何对象

GDAL 数据类型大全

相关推荐
源心锁2 小时前
丧心病狂!在浏览器全天候记录用户行为排障
前端·架构
烛阴3 小时前
从“无”到“有”:手动实现一个 3D 渲染循环全过程
前端·webgl·three.js
BD_Marathon3 小时前
SpringBoot——辅助功能之切换web服务器
服务器·前端·spring boot
Kagol3 小时前
JavaScript 中的 sort 排序问题
前端·javascript
eason_fan3 小时前
Service Worker 缓存请求:前端性能优化的进阶利器
前端·性能优化
光影少年3 小时前
rn如何和原生进行通信,是单线程还是多线程,通信方式都有哪些
前端·react native·react.js·taro
好大哥呀4 小时前
Java Web的学习路径
java·前端·学习
HashTang4 小时前
【AI 编程实战】第 7 篇:登录流程设计 - 多场景、多步骤的优雅实现
前端·uni-app·ai编程
cos4 小时前
Fork 主题如何更新?基于 Ink 构建主题更新 CLI 工具
前端·javascript·git