如何用Python+GDAL将GeoTIFF经纬度坐标转换为像素坐标
经纬度转GeoTIFF像素坐标的Python实现方案
咱们先解决你遇到的两个核心问题:一是osr库调用时的参数错误,二是subprocess调用gdaltransform的执行问题。
方法一:基于GDAL原生API的稳定实现(推荐)
你之前用osr的代码出错,主要是三个原因:投影信息导入方式不对、坐标顺序搞反了,以及对TransformPoint的参数理解有误。下面是修正后的完整代码,用GDAL的Dataset直接读取图像的地理信息,更可靠:
from osgeo import gdal, osr import numpy as np # 让GDAL抛出异常,方便排查错误 gdal.UseExceptions() def convert_latlon_to_pixel(lat, lon, tiff_file_path): # 打开GeoTIFF文件 dataset = gdal.Open(tiff_file_path) if not dataset: raise FileNotFoundError(f"找不到或无法打开文件:{tiff_file_path}") # 获取图像的原生投影和目标经纬度投影(EPSG:4326) image_proj = osr.SpatialReference(wkt=dataset.GetProjection()) wgs84_proj = osr.SpatialReference() wgs84_proj.ImportFromEPSG(4326) # 创建坐标转换器:从WGS84经纬度转换到图像的原生投影坐标 coord_transformer = osr.CoordinateTransformation(wgs84_proj, image_proj) # 重点:EPSG:4326的坐标顺序是「经度在前,纬度在后」,别搞反! # TransformPoint返回 (投影X, 投影Y, 高程),高程我们可以忽略 proj_x, proj_y, _ = coord_transformer.TransformPoint(lon, lat) # 获取图像的地理变换参数:(左上角X, 像素宽度, 旋转参数, 左上角Y, 旋转参数, 像素高度) geo_transform = dataset.GetGeoTransform() # 用地理变换公式计算像素坐标 pixel_x = (proj_x - geo_transform[0]) / geo_transform[1] pixel_y = (proj_y - geo_transform[3]) / geo_transform[5] # 如果需要整数像素坐标,直接四舍五入即可 return int(np.round(pixel_x)), int(np.round(pixel_y)) # 调用示例 tiff_path = "/path/imagename.tiff" target_lat = -17.4380493164062 target_lon = 14.6951949085676 px, py = convert_latlon_to_pixel(target_lat, target_lon, tiff_path) print(f"对应的像素坐标:({px}, {py})")
对你原osr代码的错误解析:
source.ImportFromUrl(path + TIFFFilename):ImportFromUrl是用来从网络URL加载投影信息的,不是本地文件,应该从Dataset的GetProjection()获取图像的投影。- 坐标顺序错误:你传入的是
(lat, lon),但EPSG:4326要求的是(lon, lat),这会导致转换结果完全错误。 - 虽然
TransformPoint的参数格式没问题,但前面的投影导入错误已经导致整个转换器失效,所以才抛出NotImplementedError。
方法二:修复subprocess调用gdaltransform的问题
你之前的subprocess调用有两个关键错误:参数格式不对,以及没有正确读取输出结果。下面是修正后的代码:
import subprocess import numpy as np def convert_via_gdaltransform(lat, lon, tiff_file_path): # 构建gdaltransform命令参数,注意顺序:先经度,后纬度 cmd_args = [ 'gdaltransform', '-i', '-t_srs', 'epsg:4326', tiff_file_path, str(lon), str(lat) ] # 执行命令并捕获输出 result = subprocess.run( cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True # 如果命令执行失败,直接抛出异常 ) # 解析输出结果(gdaltransform会输出一行像素坐标) px_str, py_str = result.stdout.strip().split() return int(np.round(float(px_str))), int(np.round(float(py_str))) # 调用示例 tiff_path = "/path/imagename.tiff" target_lat = -17.4380493164062 target_lon = 14.6951949085676 px, py = convert_via_gdaltransform(target_lat, target_lon, tiff_path) print(f"对应的像素坐标:({px}, {py})")
对你原subprocess代码的错误解析:
- TRY1中
' -t_srs'前面多了空格,导致gdaltransform无法识别这个参数,应该写成'-t_srs',同时路径后面不要加\n。 - TRY2中用
shell=True但没有读取输出,也没有等待命令执行完成,用subprocess.run()并指定check=True可以自动处理错误,同时捕获stdout获取结果。
总结
推荐使用第一种方法,因为它不需要调用外部命令,代码更易维护,也更容易处理异常情况;第二种方法适合你已经熟悉gdaltransform命令的场景,但要注意参数顺序和格式。
内容的提问来源于stack exchange,提问作者drheinrich940




