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 数据类型大全

相关推荐
CHANG_THE_WORLD17 分钟前
PDF文档结构分析 一
前端·pdf
东东51632 分钟前
果园预售系统的设计与实现spingboot+vue
前端·javascript·vue.js·spring boot·个人开发
rainbow688934 分钟前
Python学生管理系统:JSON持久化实战
java·前端·python
打小就很皮...37 分钟前
React Router 7 全局路由保护
前端·react.js·router
起风的蛋挞1 小时前
Matlab提示词语法
前端·javascript·matlab
有味道的男人1 小时前
1688获得商品类目调取商品榜单
java·前端·spring
txwtech1 小时前
第20篇esp32s3小智设置横屏
前端·html
Exquisite.1 小时前
企业高性能web服务器---Nginx(2)
服务器·前端·nginx
DFT计算杂谈1 小时前
VASP+PHONOPY+pypolymlpj计算不同温度下声子谱,附批处理脚本
java·前端·数据库·人工智能·python
广州华水科技1 小时前
如何选择合适的单北斗变形监测系统来保障水库安全?
前端