QGIS 3.22导出OpenStreetMap图层模糊问题求助
QGIS导出OSM瓦片图层模糊问题排查与解决
问题背景
在QGIS 3.22中通过https://tile.openstreetmap.org/{z}/{x}/{y}.png加载OSM瓦片图层后,使用自定义Python代码导出局部区域PNG时图像模糊,但相同区域在QGIS画布及OSM官网显示清晰。已尝试调整瓦片分辨率、导出分辨率、DPI、缩放级别等参数,均未改善导出质量。
代码问题分析
- DPI设置不同步:仅设置了
QImage的dotspermeter,未同步配置QgsMapSettings的DPI参数。QGIS渲染瓦片时会根据自身DPI计算加载的瓦片层级,两者不一致会导致瓦片被强制缩放拉伸,出现模糊。 dotspermeter参数值不合理:设置的1、10等值过小,不符合实际导出分辨率需求,应根据目标DPI计算正确数值(1 DPI ≈ 39.37 dots/meter)。- 缩放与尺寸不匹配:手动设置的
zoom值和输出尺寸未对应OSM瓦片原生分辨率,导致渲染时瓦片被插值缩放,丢失细节。 - 坐标转换方式过时:使用了pyproj旧版
Proj(init=...)语法,QGIS内置了更可靠的坐标转换方法,无需依赖外部库。
修正后的代码
def to3857Coords(lat, lon): # 使用QGIS内置坐标转换,替代旧版pyproj crs_4326 = QgsCoordinateReferenceSystem("EPSG:4326") crs_3857 = QgsCoordinateReferenceSystem("EPSG:3857") transform = QgsCoordinateTransform(crs_4326, crs_3857, QgsProject.instance()) point = transform.transform(QgsPointXY(lon, lat)) return point.x(), point.y() def saveImg(xsize, ysize, dpi): # 计算dotspermeter:1 DPI = 39.37 dots/meter dotspermeter = int(dpi * 39.37) img = QImage(QSize(xsize, ysize), QImage.Format_ARGB32_Premultiplied) img.setDotsPerMeterX(dotspermeter) img.setDotsPerMeterY(dotspermeter) ms = QgsMapSettings() # 同步设置QgsMapSettings的DPI,确保瓦片加载层级正确 ms.setDpi(dpi) p = QPainter() p.begin(img) # 添加渲染优化提示,减少缩放模糊 p.setRenderHint(QPainter.HighQualityAntialiasing) p.setRenderHint(QPainter.SmoothPixmapTransform) # 直接获取图层,保持正确顺序 layers = [lyr for lyr in QgsProject.instance().mapLayers().values()] ms.setLayers(layers) # 设置渲染范围 rect = iface.mapCanvas().extent() ms.setExtent(rect) ms.setOutputSize(img.size()) # 执行渲染 render = QgsMapRendererCustomPainterJob(ms, p) render.start() render.waitForFinished() p.end() # 保存图像 img.save(f'/tmp/test_render_{xsize}_{ysize}_{dpi}.png') print('Done') # 配置参数:纬度、经度、目标DPI、输出宽高 # 输出尺寸需与画布范围、DPI匹配,避免强制缩放 conf=[ [51.11, 17.032222, 300, 1540, 770], # 300 DPI,对应OSM层级18的清晰瓦片 [51.11, 17.032222, 150, 770, 385], [51.11, 17.032222, 600, 3080, 1540], ] lat, lon, dpi, xsize, ysize = conf[0] canvas = iface.mapCanvas() x, y = to3857Coords(lat, lon) canvas.setCenter(QgsPointXY(x, y)) # OSM层级18对应QGIS缩放值约1128.5,保持此值并同步DPI canvas.zoomScale(1128.5) saveImg(xsize, ysize, dpi)
关键优化说明
- 同步DPI设置:必须同时配置
QgsMapSettings和QImage的DPI,确保QGIS加载的瓦片层级与输出分辨率匹配,避免瓦片拉伸。 - 启用平滑渲染:添加
SmoothPixmapTransform渲染提示,减少瓦片缩放时的模糊感。 - 匹配尺寸与缩放:输出尺寸需根据画布范围和DPI计算,保证每个瓦片像素对应输出图像的整数像素,避免插值模糊。
- 优先使用内置工具:如果无需自定义逻辑,直接使用QGIS自带的「导出地图为图像」功能(菜单栏
项目 > 导出 > 导出地图为图像),可更精准控制参数,保证导出质量。
内容的提问来源于stack exchange,提问作者Simone




