C++(Qt)-显示离线瓦片图

发布时间:2026/7/1 2:35:55
C++(Qt)-显示离线瓦片图 背景在高分辨率图像浏览、地图渲染或工业视觉中单张完整图像往往非常大直接加载会导致内存占用过高甚至崩溃。因此常采用瓦片化Tile-based策略将大图切分为小块Tile按需加载和渲染。二、瓦片图的基本结构与地图瓦片结构不同本文瓦片图格式使用 level.x.y.ext 的格式其中level是当前瓦片实际缩放的倍数。如1:1显示的最底层的level是1上一层使用1:2的缩放的level是2再上一层使用1:4的缩放的level是4以此类推。所以最高层的level最大也是最大的鸟瞰图同时level也一定是2的倍数。这次层级关系是与常见的GIS模式不用 如果需要兼容可以重写以下部分即可​MXTGraphicsTileLoader::Private::ParseLevelInfo修改瓦片文件夹的解析流程进行层级转化到本文的level模式​MXTGraphicsTileLoader::Private::MakeTilePath生成瓦片文件的路径层级Level / Zoom Level每个瓦片图通常有多个层级用于支持不同缩放级别层级 N 表示最小缩放整体缩略图层级 1 表示最大分辨率每上升一层瓦片分辨率 / 2瓦片层级 × 2瓦片坐标x, y每个层级的图像被切分成大小固定的瓦片如 256×256以(x, y)作为瓦片坐标且从11开始计算常用命名规则level.x.y.png或level.x.y.tif瓦片存储路径单文件夹全部存储如果需要分层分行存储需要修改代码三、核心配置结构// 瓦片加载器配置信息 struct MXTGraphicsTileLoaderConfig { QString folderPath; // 文件夹路径瓦片所在根目录 QByteArray format tif; // 瓦片图像格式tif/png/jpg/bmp QSize tileSize QSize(1024, 1024); // 每个瓦片在 scene 中显示的大小 // 影响缩放比例可与真实瓦片不一致实现缩放/拉伸 // 若原图512x512设置为256x256则缩小显示 int ringRadius 1; // 环形加载半径视野扩展加载优化 int crossLevelRadius 1; // 交叉层加载跨度通常用于多层级预加载 int debounceMs 80; // 加载请求防抖控制毫秒 // 避免鼠标滚轮或平移时过多请求 long long maxCacheCount 200; // Tile 最大缓存数量LRU 淘汰 int mutexSleepTime 200; // 互斥锁等待超时毫秒 LayerFilterMode filterMode LayerFilterMode::Auto; // 层级过滤模式自动/手动 QSetZLEVEL filterLevels; // 若为手动模式这里指定要加载的层级 bool autoCropEdges true; // 自动裁剪右/下边缘黑边不规则大图常用 };结构体要点解析重点tileSize ≠ 原图分割瓦片大小tileSize 控制瓦片的显示比例可以用来让整图整体缩放、拉伸显示、甚至做分辨率适配例如想降低 GPU 压力可把 1024×1024 的瓦片以 512×512 的方式显示ringRadius 与 crossLevelRadius 是性能关键参数ringRadius 用于“视野周边提前加载”crossLevelRadius 用于“缩放时提前加载其他层级瓦片”maxCacheCount 推荐根据显存或内存调整200 → 一般合适1000 → 内存大时能减少频繁加载autoCropEdges 自动裁剪因为原图尺寸不太可能是瓦片的整数倍这里假设会在右侧和下侧的边缘区域填充黑色像素开启后可显示自动裁剪该黑色区域四、关键函数计算当前需要显示哪一个层级时获取参数显示视图尺寸visibleRect获取显示视图内物理显示屏的像素尺寸physicalViewportSize去计算不同层级下显示视图尺寸在当前缩放倍数下和像素尺寸的差距以最小值作为显示层级。详细代码如下:static ZLEVEL FindClosestLevel( const QMapZLEVEL, TileLevelInfo levels, const QRectF visibleRect, const QSize physicalViewportSize) { ZLEVEL bestLevel 0; double minDist2 std::numeric_limitsdouble::max(); for (auto it levels.constBegin(); it ! levels.constEnd(); it) { const TileLevelInfo info it.value(); // 计算当前 level 对应的 point double w visibleRect.width() / info.level_; double h visibleRect.height() / info.level_; QPointF pt(w, h); // 计算与 physicalViewportSize 的平方距离 double dx pt.x() - physicalViewportSize.width(); double dy pt.y() - physicalViewportSize.height(); double dist2 dx * dx dy * dy; if (dist2 minDist2) { minDist2 dist2; bestLevel it.key(); } } return bestLevel; }五、使用示例// 创建瓦片图 Item MXTGraphicsTilePixmapItem* item new MXTGraphicsTilePixmapItem(); // 构建加载配置 MXTGraphicsTileLoaderConfig lConfig; lConfig.folderPath D:/TEST_IMAGES; lConfig.tileSize QSize(500, 500); // 控制瓦片显示的缩放比例 lConfig.format tif; lConfig.maxCacheCount 200; // 初始化加载器 item-InitializeLoader(lConfig); // 添加到 scene view-scene()-addItem(item); // !!! 必须绑定 view触发视图更新瓦片缓存 item-bindView(view); // 删除当前图片 item-ClearLoader(); // 加载新图片 item-InitializeLoader(lAnotherConfig);六、流程图