IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Python中将GCJ02转换为WGS84坐标系

    1900发表于 2024-08-18 14:49:53
    love 0

    前文 用workflow转换Google地图kmz数据为geojson数据 中提到了我是如何获取Google Map里MyMap的数据,并自动转换为GeoJSON数据应用在博客上的。

    但是最近在查看我更新的地点时,发现有部分数据实际应用在Mapbox中会存在偏差,导致很多定位在陆地上的地点漂移到了江河之上。比如这个 重庆来福士广场 就漂移到了长江上。

    定位偏移

    其实这个问题我发现已经满久的了,之前也咨询了一下 昱行 和 大发哥,不过他们的给的方案我没太弄明白,当时碍于技术问题一直处于搁置状态,最近因为重新更新了地点,又把这个问题给勾了起来。

    不过这次这个问题让我联想起之前在将华为的数据导入到Strava时好像也遇到过,同样也是坐标偏移的问题,当时同步软件里有个「使用XX坐标系」的选项,启用之后重新同步的数据就可以在Strava正常显示了。

    所以我尝试找了个坐标系在线转换工具 EasyMap ,这个工具可以很方便的进行多种坐标系的互相转换,我试着将转换好的GeoJSON数据复制进去,并转换成WGS84坐标系后在贴到 Mapbox 的在线 GeoJSON 工具 https://geojson.io/ 中预览,发现定位已经正确显示,应该可以确定就是这个问题。

    奇怪的是我之前查过GoogleMap的坐标系标准就是WGS84呀?为什么实际上是GCJ02呢?
    定位恢复正常

    接下来就是修改上次的转换代码,在获取定位坐标的时候想办法将坐标进一步转换成WGS84坐标系即可。

    幸运的是Github有大佬分享了一个基于python的互转脚本 coordTransform_py
    ,该脚本提供了以下特性,同时还提供了一个js版本:

    此模块用于百度坐标系(bd-09)、火星坐标系(国测局坐标系、gcj02)、WGS84坐标系的相互转换,并提供中文地址到坐标的转换功能,仅使用Python标准模块,无其他依赖。

    中文地址到坐标转换使用高德地图API,需要申请API KEY。

    需要js版本可以移步coordtransform

    所以我们在之前 convert_kmz_to_geojson.py 文件中引入该库,并对坐标进行处理:

    import os
    import sys
    import json
    import zipfile
    import xml.etree.ElementTree as ET
    from shapely.geometry import shape, Point, LineString, Polygon, mapping
    from coordTransform_utils import gcj02_to_wgs84 # 引入gcj02 to wgs84的转入函数
    
    def convert_kmz_to_geojson(kmz_file_path, geojson_file_path):
        with zipfile.ZipFile(kmz_file_path, 'r') as kmz:
            kml_content = kmz.read('doc.kml')
            
            root = ET.fromstring(kml_content)
            geojson_content = kml_to_geojson(root)
            
            with open(geojson_file_path, 'w') as geojson_file:
                json.dump(geojson_content, geojson_file, indent=4)
    
    def kml_to_geojson(element):
        geojson = {
            "type": "FeatureCollection",
            "features": []
        }
    
        for placemark in element.iterfind('.//{http://www.opengis.net/kml/2.2}Placemark'):
            feature = {
                "type": "Feature",
                "properties": {},
                "geometry": None
            }
    
            for name in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}name'):
                feature["properties"]["name"] = name.text
            
            for description in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}description'):
                feature["properties"]["description"] = description.text
    
            for point in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}Point'):
                coords = point.find('{http://www.opengis.net/kml/2.2}coordinates').text.strip()
                lon, lat, _ = map(float, coords.split(','))
                # 在获取坐标时进行转换
                feature["geometry"] = mapping(Point(gcj02_to_wgs84(lon, lat)[0], gcj02_to_wgs84(lon, lat)[1]))
    
            
            for linestring in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}LineString'):
                coords = linestring.find('{http://www.opengis.net/kml/2.2}coordinates').text.strip()
                points = [tuple(map(float, coord.split(',')))[:2] for coord in coords.split()]
                feature["geometry"] = mapping(LineString(points))
            
            for polygon in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}Polygon'):
                outer_boundary = polygon.find('.//{http://www.opengis.net/kml/2.2}outerBoundaryIs')
                if outer_boundary is not None:
                    coords = outer_boundary.find('.//{http://www.opengis.net/kml/2.2}coordinates').text.strip()
                    points = [tuple(map(float, coord.split(',')))[:2] for coord in coords.split()]
                    feature["geometry"] = mapping(Polygon([points]))
            
            if feature["geometry"] is not None:
                geojson["features"].append(feature)
        
        return geojson
    
    if __name__ == "__main__":
        # kmz_file_path = "sys.argv[1]"
        # geojson_file_path = sys.argv[2]
        kmz_file_path = "downloaded_file.kmz"
        geojson_file_path = "downloaded_file.json"
        convert_kmz_to_geojson(kmz_file_path, geojson_file_path)

    目前足迹功能还会出现比较卡的情况,但是目前还没处理头绪,幸运的卡顿只是略微影响使用,就留待下次处理把。



沪ICP备19023445号-2号
友情链接