ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Photoscan/Metashape无人机航测生成DEM与正射影像全流程

Photoscan/Metashape无人机航测生成DEM与正射影像全流程 简介这份PDF文档围绕Agisoft Photoscan生成DEM与正射影像的完整作业流程展开面向无人机航测、测绘遥感与GIS方向的初学者及一线技术人员帮助打通从原始航拍照片到数字高程模型、正射影像产品之间的参数配置与操作路径。内容按参数预设、添加照片、装载相机POS文件、检查相机校准、对齐照片、布设像控点标记、优化照片对齐、设置边界框、建立密集点云等环节逐条梳理并延伸至构建网格、编辑几何、构建纹理、Build DEM与Build Orthomosaic等步骤对精度、配对预选、关键点数量、深度过滤等参数给出具体推荐值与设置依据同时说明GCP精度设置与验证点评估思路便于对照实操与排查问题。资源包共1个PDF文件约512KB篇幅紧凑可作航测内业作业的操作参照与速查手册。目前已有1357人学习下载。1. 从航拍到 DEM 和正射影像Photoscan 这套流程解决什么问题一个 2 平方公里的丘陵测区无人机飞三个架次拿回 800 多张带 POS 的照片委托方要两份成果一份能进 GIS 做坡度、汇流分析的高程栅格一份能当底图量田埂、量房角的正射影像。Photoscan新版更名 Metashape菜单与参数基本沿用从头到尾都能做出来。它走的是 SfM 加 MVS 的路子先从重叠区域找特征点反算每张照片的拍摄位置和姿态再把照片按像素匹配成稠密三维点云最后把点云栅格化成高程模型、把照片按正射投影拼成影像。不需要摄影测量工作站一台大内存机器加一块像样的显卡就能跑。点云、DEM、正射影像这三样要分清点云是带高程的离散点DEM 是栅格化之后的高程面正射影像是消除了相机倾斜和地形投影差、每个像素都对应真实平面位置的影像。做地形分析用 DEM做底图用 DOM做三维展示才用点云和 Mesh。适合测绘、地信、水利、矿山的作业人员自己出成果而不是外包也适合手里攥着一批照片要转栅格的研究人员。默认参数能出东西但能不能过检查全看旋钮怎么调。2. 重叠度、GSD 与工程坐标系DEM 精度在起飞前就定死了2.1 航向旁向重叠度与 GSD 的换算给出可套用的数字先给结论航向重叠不低于 75%旁向重叠不低于 65%这是航测出 DEM 的常规门槛。低于这个数在草地、水面、裸岩这类弱纹理区域特征点提取会成片失败匹配断链密集点云上留下空洞后面 DEM 插值出来是一层平滑的假地形——看着正常拿去做坡度分析全是错的。地面分辨率GSD决定成果的物理极限公式是GSD 像元尺寸 × 相对航高 / 镜头焦距三项单位统一到米。举例1 英寸传感器像元 2.4 μm镜头焦距 8.8 mm航高 120 mGSD 2.4e-6 m × 120 m / 8.8e-3 m ≈ 0.0327 m ≈ 3.3 cm反过来要凑一个指定 GSD航高按H GSD × f / 像元尺寸推。很多新手先飞再算飞完发现 GSD 只到 8 cm出不了 1:500 的图只能重飞。项目常规建议平坦或水面多的测区说明航向重叠75%–80%≥80%低于 65% 极易断链旁向重叠65%–70%≥70%丘陵区按上限走GCP 数量每架次 5–8 个8–10 个四角加中心别挤在中间GCP 刺点精度优于 0.5 倍 GSD优于 0.5 倍 GSD影像上大约半个像素快门类型全局快门优先卷帘需开补偿快飞时卷帘会出果冻效应2.2 GCP 布设与刺点精度绝对精度的唯一来源GCP 决定了成果的绝对坐标。没有 GCP空三出来的模型形状再漂亮位置也是飘的平面能差几米高程差几十厘米都属正常。靶标用黑白十字或对顶三角边长 40–60 cm在 120 m 航高、3 cm GSD 下大约占 10–15 个像素足够刺准。布点原则是包住测区而不是铺满测区四角各一个中心一个测区跨度大就在长边中点补。RTK/PPK 无人机可以不布 GCP但建议留 2–3 个当检查点一旦发现系统性偏差能立刻分清是空三的问题还是机载 GPS 高程的问题。刺点动作本身容易被轻视。在 Photoscan 的 Reference 面板里把影像放大到像素级中心对着靶标中心点刺偏一个像素就约等于 1 倍 GSD 的误差。3 cm 的 GSD刺偏 3 个像素高程上就是接近 10 cm 的来源比很多误差项都大。2.3 新建工程、导入照片与投影坐标系设置的最小脚本Photoscan 支持用 Python 控制台跑流程比纯手工点击更可复现。import PhotoScan doc PhotoScan.app.document chunk doc.addChunk() # 照片列表注意路径要用原始 JPG别用已经被压缩过的缩略图 photo_list [rD:\flight\IMG_0001.JPG, rD:\flight\IMG_0002.JPG] chunk.addPhotos(photo_list) # 关键一步设成投影坐标系而不是 EPSG::4326 这种地理坐标系 # EPSG::32650 WGS84 / UTM zone 50N高程系统按项目需求挂 EGM96 crs PhotoScan.CoordinateSystem(EPSG::32650) chunk.crs crs doc.save(rD:\proj\demo.psz)逻辑说明addPhotos会把 EXIF 里的 POS 读进 Reference 表后续对齐时用作初值。chunk.crs必须设成投影坐标系因为地理坐标系下 DEM 的像素单位是度分辨率没法用米表达面积和距离都带形变。挂高程基准时可以用复合坐标系比如把 UTM 50N 和 EGM96 大地水准面组合否则机载 GPS 给的椭球高和实测正常高之间会差一个大地水准面差距丘陵区能到十几米。注意工程文件要及时另存版本。地面点分类、DEM 重建这些操作会覆盖中间结果出问题时能回退到对齐完成那一步比重新跑一遍密集点云省几个小时。2.4 掩膜处理把天空、水面和移动物体挡在特征匹配之外掩膜不是可选项。天空背景、水面反光、路上的移动车辆这三类是特征匹配的噪声源。水面反光会让软件在同一个物理点上匹配出不同深度的点车辆会在地面上糊出一块凸起天空区域则直接产生远处的错误点。手工做法是在照片视图里用矩形或多边形工具刷掉。批量做法是在脚本里按规则生成# 对每张照片生成掩膜参数为容差与矩形边界 chunk.generateMasks( methodPhotoScan.MaskMethod.Background, tolerance10, camerachunk.cameras[0] ) # 让对齐阶段使用掩膜 chunk.matchPhotos(filter_maskTrue, mask_tiepointsTrue)tolerance控制背景判定的宽容度纯色背景调到 8–15 之间复杂的城市天空要手工补。mask_tiepointsTrue会让掩膜区域内的连接点不参与运算代价是要重建一次掩膜收益是点云上的鬼影明显减少。测区里有大面积水域时更稳的做法是拿到水面矢量或者在 GIS 里手工描出范围再回导靠容差自动判水面反光经常失效。3. 对齐照片到密集点云Photoscan 重建阶段的参数逐项拆解3.1 Align Photos 的 5 个参数与最小运行脚本对齐这一步决定了后面所有成果的地基。参数不多但每一个都有明确的代价和收益。参数建议值参数说明AccuracyHigh大测区先 Medium 试跑降采样层级Highest 用原图Generic preselection照片超过 50 张时开用影像相似度先分组能省一半时间Reference preselection有 POS 数据时开按坐标临近选候选匹配提速最明显Key point limit40000弱纹理调到 60000单张照片保留的特征点数上限Tie point limit00 表示不限制连接点总数Adaptive camera model fitting开自动决定额外畸变参数chunk.matchPhotos( accuracyPhotoScan.Accuracy.HighAccuracy, generic_preselectionTrue, reference_preselectionTrue, filter_maskTrue, mask_tiepointsTrue, keypoint_limit40000, tiepoint_limit0 ) chunk.alignCameras()accuracy不是越高越好。Highest 用原图匹配时间可能是 High 的四倍而在地形起伏平缓、纹理重复的农田区多出来的特征点大多是噪声。测区跨十几个架次时先用 Medium 跑一遍看对齐率是否达到 95% 以上再决定要不要提高。reference_preselection依赖 POS 精度。无人机自带的单点 GPS 精度只有几米参考预选可能选错候选集导致局部匹配失败。这种情况下把它关掉用 Generic preselection 更稳。3.2 Optimize Cameras 与渐进式点过滤把 GCP 残差压到 1 倍 GSD 以内对齐完成后连接点里混着大量误差偏大的点直接建密集点云会把误差放大。标准动作是循环三步过滤、重优化、再看残差。# 第一轮按重建不确定性过滤阈值 10 f PhotoScan.PointCloudFilter() f.init(chunk, PhotoScan.Criterion.ReconstructionUncertainty) f.selectPoints(10.0) f.removePoints() chunk.optimizeCameras(fit_fTrue, fit_cxTrue, fit_cyTrue, fit_k1True, fit_k2True, fit_k3True, fit_p1True, fit_p2True, adaptive_fittingTrue) # 第二轮按投影精度过滤阈值 3 f.init(chunk, PhotoScan.Criterion.ProjectionAccuracy) f.selectPoints(3.0) f.removePoints() chunk.optimizeCameras(fit_fTrue, fit_cxTrue, fit_cyTrue, fit_k1True, fit_k2True, fit_k3True, fit_p1True, fit_p2True, adaptive_fittingTrue) # 第三轮按重投影误差过滤阈值 0.3 f.init(chunk, PhotoScan.Criterion.ReprojectionError) f.selectPoints(0.3) f.removePoints() chunk.optimizeCameras(fit_fTrue, fit_cxTrue, fit_cyTrue, fit_k1True, fit_k2True, fit_k3True, fit_p1True, fit_p2True, adaptive_fittingTrue)每一步删完连接点都要重新优化一次否则相机参数还是按旧的连接点算出来的等于白删。三个阈值是经验值重建不确定性针对的是游离在主体结构之外的点投影精度针对的是匹配位置不准的点重投影误差针对的是残差大的点。当主点 cx、cy 和焦距 f 的初始值本来就不确定时可以先勾上fit_f、fit_cx、fit_cy做一次粗优化把参数拉到合理区间再放开径向畸变 k1–k3 和切向畸变 p1、p2。一次全放开容易收敛到局部极小残差反而变大。优化结束后看 GCP 残差。chunk.markers里每个标记点的 error 都会更新正常应该在 1 倍 GSD 以内。某个点突然比别的点大三五倍先别急着删把它单独勾掉再优化一次做对比多数时候是刺点位置偏了而不是那个点本身有问题。3.3 Build Dense CloudQuality 与 Depth Filtering 对 DEM 的实际影响密集点云是 DEM 的直接数据源这里的参数直接决定成果的颗粒度。chunk.buildDenseCloud( qualityPhotoScan.Quality.HighQuality, filter_modePhotoScan.FilterMode.AggressiveFiltering, keep_depthTrue, reusable_depthTrue )quality对应图像降采样倍率实际影响是点间距Quality降采样点间距相对 GSD典型用途Ultra High原图约 1 倍精细单体建模耗时最长High1/4约 2 倍常规 DEM 与正射影像Medium1/16约 4 倍大测区快速出图Low1/64约 8 倍质量预检查Lowest1/256约 16 倍只做概览不适合出图按 3 cm 的 GSD 算High 出来的点间距约 6 cmDEM 分辨率设在 0.05–0.1 m 是匹配的。选 Ultra High 而 DEM 只出 0.5 m多花的时间全浪费。filter_mode影响的是离群点处理强度。Aggressive 对地形测量最合适会把建筑边缘、树冠外侧那些飘出去的点削掉代价是薄结构电线、护栏、细杆也会一起消失。如果成果要包含这些细节改用 Mild。keep_depth和reusable_depth打开后会保留深度图后续重新生成点云时能直接复用省一次完整计算代价是工程文件膨胀SSD 紧张就别开。4. Build DEM 与 Build Orthomosaic两套成果的生成参数表4.1 高程源选密集点云还是 Mesh分辨率设到多少Photoscan 允许从三种数据源生成高程栅格稀疏连接点、密集点云、Mesh。连接点只用来看粗略形态正式成果不用它。剩两个选择密集点云细节最全保留了所有可见面包括植被冠层、车顶、屋顶出来的本质是 DSM。Mesh 是点云三角化后的结果表面连续、没有空洞适合做正射影像的投影面因为它不会在影像上留下因点云空洞产生的破洞。做法上是先出 DSM 用于正射影像再对点云做地面点分类用 Ground 类点重新生成 DEM。分辨率设置有个反直觉的点把 DEM 分辨率设得比 GSD 还细比如 GSD 3 cm 却设成 0.01 m不会提高精度只会把文件撑大好几倍地图上看到的还是插值出来的平滑曲面。合理区间是 GSD 的 1–3 倍。4.2 Build DEM 的关键参数与无数据区域填充chunk.buildDem( source_dataPhotoScan.DataSource.DenseCloudData, interpolationPhotoScan.Interpolation.EnabledInterpolation, projectionchunk.crs, regionchunk.region, classesPhotoScan.PointClass.All )source_data三个取值TiePointsData只做预览DenseCloudData是常规选择MeshData在点云空洞多时更稳。projection一定要显式指定成和 chunk 一致的投影坐标系跨带测区先决定用哪个带不要中途改。interpolation是重灾区三个取值的差别很大Disabled不填充点云没覆盖到的地方留 NoData。做地形分析时这是最诚实的做法让人一眼看出数据缺失在哪里。EnabledInterpolation只填内部空洞边界外不延伸适合大多数交付场景。Extrapolated连边界外都外推大范围使用会在测区边缘造出一圈根本不存在的地形水文分析时这些假高程会直接污染汇流结果。classes决定用哪一类点。默认的 All 出的是 DSM建筑和树的高度都在里面改成PhotoScan.PointClass.Ground得到的是真正意义上的 DEM前提是点云已经做过地面点分类。注意DEM 里 NoData 的取值不要用 0。0 在多数高程基准下是合法值海平面附近或者低洼地区会被当成真实地形参与计算。4.3 Build Orthomosaic 的混合模式、颜色校正与接缝线正射影像的生成参数里混合模式对观感的影响最大。chunk.buildOrthomosaic( surface_dataPhotoScan.DataSource.ElevationData, blending_modePhotoScan.BlendingMode.MosaicBlending, color_correctionTrue, enable_holesTrue, fill_holesTrue, ghosting_filterTrue, resolution_x0.03, resolution_y0.03 )混合模式效果适用场景Mosaic按接缝线取单张影像锐度最好常规 DOM 交付Average多张取平均接缝平顺但边缘发虚有薄结构、想掩盖接缝跳变Disabled不做混合排查拼接问题color_correction处理的是不同架次、不同光照下的色调跳变。白天光照变化快的时段飞行不开就会出现明显色块。反过来说如果成果要拿去做植被指数、辐射反演这类定量分析必须关掉因为它直接改动像素亮度值破坏了辐射一致性。ghosting_filter专治移动物体路上跑的车会在多张照片里出现在不同位置开启后能挑一张作为主影像。接缝线在建筑边缘、陡坎和大高差处最容易拉花Photoscan 支持手工编辑接缝线把缝挪到人眼不敏感的地面区域。4.4 导出 GeoTIFF 并用 gdalinfo 校验坐标系# 导出 DEM chunk.exportRaster( pathrD:\out\dem.tif, image_formatPhotoScan.ImageFormat.ImageFormatTIFF, source_dataPhotoScan.DataSource.ElevationData, nodata_value-9999, tiledTrue, bigtiffTrue ) # 导出正射影像 chunk.exportRaster( pathrD:\out\dom.tif, image_formatPhotoScan.ImageFormat.ImageFormatTIFF, source_dataPhotoScan.DataSource.OrthomosaicData, tiledTrue, bigtiffTrue, compressionPhotoScan.CompressionType.LZW )bigtiffTrue在成果超过 4 GB 时必开不开会在写到一半时报错。tiledTrue让 GIS 软件按块读取浏览大图时不卡。nodata_value统一设成 -9999 或 -32767全流程保持一致不然拼接时会出现 NoData 被当成有效值的低级错误。导出之后不要直接交付用 GDAL 验一遍# 查看坐标系、像素大小、NoData 值和统计范围 gdalinfo -stats dem.tif # 只看高程极值超出测区合理范围的多半是噪声点 gdalinfo -mm dem.tif | grep Computed Min/Max-stats会算一遍统计量如果最大值出现在测区边界且比周围高出几十米基本是外推或者边缘噪声造成的回去在点云里把边界外的点裁掉再重生成。-mm只看极值速度更快适合批量检查。5. 地面点分类与成果校验把 DSM 修成能进 GIS 的 DEM5.1 用 Classify Ground Points 从密集点云里抠出地面不做分类出来的 DEM 其实是 DSM屋顶、树冠的高度全在里面。坡度分析会报出荒诞的结果——一栋 30 米的楼在 5 米的间距上算出几百度的坡。chunk.dense_cloud.classifyGroundPoints( max_angle15.0, # 地面最大坡度角度 max_distance1.0, # 点到地面拟合面的最大距离米 cell_size2.0 # 分析窗口大小米 )max_angle是判断坡面连续性的上限丘陵区用 15–20密集城区调到 10–12否则屋顶斜坡会被误判成地面。max_distance控制点被接受为地面点的容差点云噪声大时适当放宽到 1.5–2.0但放太宽会把低矮灌木一起收进来。cell_size是窗口尺寸经验值是 GSD 的 50–100 倍3 cm 的 GSD 对应 1.5–3 m。分类完先看比例裸地测区地面点应占 60%–70%城市建成区 20%–40% 属正常低于 15% 说明参数过严地面被削得残缺不全。然后回到 4.2 节把classes改成PhotoScan.PointClass.Ground重新生成一次 DEM这才是能用来做地形分析的高程数据。5.2 独立检查点与 RMSEDEM 精度怎么算出来精度不是靠看图看出来的要靠不参与平差的检查点算出来。在 Reference 面板里把用作检查的标记点取消勾选它们就不会参与优化只在平差后显示残差。chunk.exportReference( pathrD:\out\check_points.csv, formatPhotoScan.ReferenceFormatCSV, columnsnxyzXYZ, delimiter, )导出的 CSV 里同时有实测坐标和模型坐标用中误差公式统一算RMSE_z sqrt( Σ(z_i − ẑ_i)² / n )平面和高程分开算。判据用 GSD 的倍数比较直观指标良好需要返工平面 RMSE≤ 1 倍 GSD 3 倍 GSD高程 RMSE≤ 2 倍 GSD 3 倍 GSD单个 GCP 残差均匀分布单点突变超过 3 倍单点突变和整体偏大是两类问题。整体偏大查 POS 高程和坐标系统设置单点突变查刺点。把检查点结果留档后面换算法或改参数重跑能直接对比是否真的变好了。5.3 GIS 中的 DEM 分割与水文预处理DEM 交付后最常见的两个后续动作是切块和水文分析。切块用 GDAL 比在 GIS 里手工裁剪更可控# 按像素窗口切出一块坐标系不变 gdal_translate -srcwin 0 0 2000 2000 dem.tif tile_00.tif # 按地理范围裁剪顺便重采样到 5 米 gdalwarp -te 500000 4000000 505000 4005000 -tr 5 5 dem.tif dem_clip.tif-srcwin用像素行列号定位适合规整分幅-te用左上右下地理坐标定位适合按行政区或流域范围裁剪。切出来的瓦片保留 1–2 个像素的重叠边拼接时用 VRT 或合并工具而不是简单镶嵌能避免接缝处出现坡度突变。水文分析前要先处理 DEM 本身的问题。桥、涵洞会让水流在地表模型上断开低洼处的凹陷会让流向计算陷入死循环这就是水文预处理环节报错的高频来源。通行做法是先填洼再按道路矢量抬升同时把 NoData 区域显式标注出来不要让软件把 -9999 当成一个深坑去参与汇流计算。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进