简介E-FOTO是一套面向教学场景的开源数字摄影测量工作站适合测绘、地理信息、遥感等专业的学生与教师用于理解摄影测量从图像校正到数字立体展绘的完整原理。资源包内含1个doc文档压缩包约1.62MB以论文形式系统介绍了该项目的设计理念、模块构成与教学应用。文档围绕图像校正、内定向、外定向、摄影三角测量、立体图正态化、数字高程模型、正射纠正和数字立体展绘八大模块展开并说明各模块通过XML文件交换数据、形成整体工作流程的集成思路。项目自2002年启动遵循自由使用与自学原则配套在线帮助、电子书与项目网站等教学材料已被巴西及国际多所机构采用。目前已有302人学习适合希望深入理解商业软件背后算法与工具链、并具备一定摄影测量基础的读者参考。1. 数字摄影测量教学工具链为什么我建议你从这套开源工作站拆起如果你正在带摄影测量课或者自学空三、DEM 提取却卡在商业软件的黑匣子里E-FOTO 这套面向教学的数字摄影测量工作站值得你花一个下午拆开看看。它把图像校正、内定向、外定向、摄影三角测量、立体图正态化、DEM 抽取、正射纠正、数字立体展绘这八个核心模块全部开源配套一本数字摄影测量电子书和在线帮助文档。和那些只给你一个按钮、不告诉你内部怎么算的商业软件不同E-FOTO 的每个模块都能看到源码、改参数、验证中间结果。它适合高校实验室做课程设计也适合刚入行的测绘从业者补理论短板——毕竟能把共线方程、核线几何这些概念跑通一遍比看十遍 PPT 都管用。2. 拆开这套工作站八个模块的算法底子和数据流设计2.1 从图像校正到正射纠正每个模块在算什么E-FOTO 的模块划分基本对应航空摄影测量的标准作业流程。图像校正模块负责消除传感器姿态引起的变形支持一般仿射、等角仿射、正交仿射、刚体仿射、等角变换和投影变换六种变换类型插值方案有最近邻、双线性、双三次和拉格朗日四种。内定向确定相机内部参数输出变换矩阵和定向质量统计参数。外定向解算相机在空间中的位置和姿态结果里除了矩阵和统计量还会给出迭代次数和调整是否收敛的消息。摄影三角测量用光束法平差计算点坐标模块提供两个接口一个用于联机测量点并获取坐标另一个用于定义测量点集合批量计算。立体图正态化采用 Schenk-Cho 算法基于核线几何生成立体图目的是让后续自动测量更高效。DEM 抽取模块用共线性方程重构透视光束通过空间交叉法重建立体模型解析图在地形上创建虚拟网格推导高程值。正射纠正紧接 DEM 抽取生成两种产品含高程和灰度信息的完整模型以及仅含灰度信息的数字正射影像。数字立体展绘模块根据立体像对生成物体表面轮廓这些三维要素可以作为 back-lines 插入 DEM。2.2 XML 控制层模块之间怎么传数据E-FOTO 的模块不是集成在一个大程序里而是各自独立的可执行程序。它们通过 XML 摄影测量项目控制文件交换数据控制层负责保存、访问、验证和处理各模块产生的数据。这个设计的好处是每个模块可以单独开发、单独测试学生做毕业设计时只领一个模块就能上手。代价是模块之间的连接不够顺畅用户需要手动管理 XML 文件的流转。控制层的另一个功能是验证用户在 UI 界面输入的数据减少因为输入错误导致的解算失败。2.3 开发策略MathCAD 验证C 落地E-FOTO 的算法开发有个值得借鉴的流程先在 MathCAD 平台上用高阶语言实现并测试算法确认公式和逻辑正确后再用 C 配合 Qt 图形接口重写。图像校正模块最早是本科毕业设计项目2003 年在 MathCAD 上实现六种变换2005 年用 C 语言做成可执行程序发布。内定向模块 2002 年用 C 和 Qt 实现但因为界面友好性和代码可重用性问题2006 年被废弃重写新版本引入了 View 类负责可视化和测量这个类后来被内定向、外定向、数字测量、摄影三角测量和正态化模块共用。外定向模块直接用 C 语言实现第一版结果不错代码在改进时被重用。摄影三角测量模块同样经历了从 MathCAD 到 C 的移植最终创建了点测量和点创建两个接口。2.4 编译环境搭建Qt 4.0 和跨平台注意事项E-FOTO 当前版本是 4.0使用 Qt 4.0 图形用户接口可以在 Windows、Linux、MacOS 上编译。Qt 升级带来的代码迁移工作量不小因为很多类被废弃了。如果你打算从源码编译先确认系统里的 Qt 版本。以 Ubuntu 为例安装依赖的命令大致如下# 安装 Qt 4 开发库和编译工具 sudo apt-get install qt4-dev-tools qt4-qmake g make # 安装 XML 解析库E-FOTO 用 XML 做模块间数据交换 sudo apt-get install libxml2-dev # 克隆源码后进入目录 cd e-foto/src # 生成 Makefile qmake e-foto.pro # 编译 make -j4编译过程中如果报错找不到 Qt 头文件检查qmake -v输出的路径是否指向 Qt 4 而不是 Qt 5。E-FOTO 的代码没有做 Qt 5 的兼容用 Qt 5 编译会遇到大量废弃 API 报错。如果必须在 Qt 5 环境下跑常见做法是手动替换废弃类比如把QWorkspace换成QMdiArea但工作量不小。另一个坑是 XML 文件的编码E-FOTO 生成的 XML 默认用 UTF-8如果系统 locale 不是 UTF-8读写中文路径时可能乱码。3. 跑通一个完整流程从航拍影像到正射影像的操作步骤3.1 准备输入数据影像、控制点和相机文件E-FOTO 主页提供了教学材料包含三个数字化框架、航拍影像、PDF 版的相机校正证明和地面控制点。如果你用自己的数据需要准备以下内容航拍影像常见格式是 TIFF 或 JPG、地面控制点的坐标文件至少四个点用于外定向、相机内参数文件焦距、像主点坐标、镜头畸变系数。控制点坐标的坐标系要和影像的坐标系一致常见的是 UTM 或地理坐标系。相机文件里焦距单位要和影像尺寸单位匹配一般用毫米。把这些文件放在同一个项目目录下后续每个模块都会从这个目录读取输入、写入输出。3.2 内定向量测框标点并解算变换矩阵内定向是后续所有步骤的入口。打开内定向模块加载航拍影像界面会显示影像和框标点位置。你需要手动量测四个框标点或者导入已有的框标点坐标文件。量测完成后点击解算模块会输出变换矩阵和定向质量统计参数。统计参数里重点关注单位权中误差如果数值明显偏大说明框标点量测有粗差需要检查是不是点错了位置。内定向结果会保存为 XML 文件后续外定向模块会读取这个文件获取内定向参数。!-- 内定向输出的 XML 片段示例 -- InteriorOrientation ImageFileaerial_001.tif/ImageFile FiducialPoints Point id1 x1024.5 y768.3 / Point id2 x5120.1 y768.5 / Point id3 x5120.3 y3840.2 / Point id4 x1024.2 y3840.0 / /FiducialPoints TransformationMatrix a111.000012/a11 a120.000003/a12 a21-0.000002/a21 a220.999998/a22 /TransformationMatrix Sigma00.0032/Sigma0 /InteriorOrientationSigma0是单位权中误差单位是像素。一般要求小于 0.5 像素如果超过 1 像素检查框标点坐标是否读错。TransformationMatrix是仿射变换矩阵把影像坐标转到框标坐标系。3.3 外定向导入控制点并检查收敛消息外定向模块读取内定向的 XML 文件然后加载地面控制点坐标。界面支持缩放影像和管理测量点你的任务是在影像上找到控制点对应的位置并量测。量测完至少四个点后点击解算模块用共线方程做空间后方交会。结果里除了变换矩阵和统计参数还会显示迭代次数和调整是否收敛的消息。如果消息显示未收敛常见原因是控制点分布太集中、控制点坐标有粗差、或者相机内参数不准确。解决办法是增加控制点数量、检查控制点坐标、重新做内定向。3.4 摄影三角测量光束法平差计算加密点坐标摄影三角测量模块读取外定向结果然后进行光束法平差。模块提供两个接口点测量接口允许你联机测量一个点并获取坐标点创建接口允许你定义测量点集合批量计算。实际操作中先用量测接口在立体像对上量测连接点然后用创建接口批量解算。平差结果会输出每个加密点的三维坐标和精度信息。如果平差不收敛检查连接点是否匹配错误、控制点数量是否足够、外定向精度是否达标。3.5 DEM 抽取与正射纠正生成地形模型和正射影像DEM 抽取模块用共线性方程重构透视光束通过空间交叉法重建立体模型解析图。你需要在立体像对上量测地形特征点模块根据这些点生成规则网格的高程值。网格间距根据地形复杂度和精度要求设定平坦地区可以设大一些山区要设小一些。DEM 生成后正射纠正模块读取 DEM 和原始影像生成正射影像。正射影像有两种输出含高程和灰度信息的完整模型以及仅含灰度信息的数字正射影像。完整模型可以导入三维可视化软件查看地形数字正射影像可以用于制作 DOM 产品。4. 避坑与排查编译、数据流和精度问题的血泪经验4.1 编译报错找不到 Qt 头文件现象qmake执行成功但make时报错fatal error: QWorkspace: No such file or directory。原因系统里装的是 Qt 5E-FOTO 用的是 Qt 4QWorkspace在 Qt 5 里被移除了。解决安装 Qt 4 开发库或者手动把QWorkspace替换成QMdiArea同时修改相关的头文件引用和 API 调用。如果不想改代码用 Docker 跑一个带 Qt 4 的 Ubuntu 16.04 环境是最省事的办法。4.2 XML 文件读写乱码现象模块生成的 XML 文件在另一个模块里打开时中文路径或中文注释变成乱码。原因E-FOTO 的 XML 读写默认用 UTF-8但系统 locale 可能是 GBK 或 ISO-8859-1。解决在启动脚本里设置export LANGen_US.UTF-8和export LC_ALLen_US.UTF-8或者在 XML 文件头显式声明?xml version1.0 encodingUTF-8?。如果还是乱码检查文件系统是否支持 UTF-8 文件名。4.3 外定向不收敛现象外定向解算后提示未收敛迭代次数达到上限但残差仍然很大。原因控制点分布不合理比如四个点全在影像同一侧、控制点坐标有粗差、内定向精度不够、相机焦距设置错误。解决先检查控制点分布理想情况是四个点均匀分布在影像四角然后检查控制点坐标用已知点做检核再检查内定向的Sigma0是否小于 0.5 像素最后确认相机焦距单位是毫米且数值正确。4.4 DEM 抽取时高程值异常现象DEM 生成后部分区域高程值明显偏离实际地形出现尖峰或深坑。原因立体像对上量测的地形特征点有粗差或者空间交叉法解算时交会角太小。解决检查量测点是否匹配错误删除明显异常的点重新解算如果交会角太小增加立体像对的重叠度或者换用交会角更大的像对。另外DEM 网格间距不要设得比影像分辨率还小否则会出现大量空白格网。4.5 正射影像出现拉伸条纹现象正射纠正后的影像在陡峭地形区域出现拉伸条纹地物变形严重。原因DEM 在该区域的高程值不准确或者正射纠正的插值方法不适合。解决先检查 DEM 在该区域的高程值是否合理必要时手动编辑 DEM然后尝试更换正射纠正的插值方法E-FOTO 支持最近邻、双线性、双三次和拉格朗日四种插值双线性通常比最近邻平滑但会损失一些高频细节。5. 进阶用法用 XML 控制文件做批量处理和精度验证E-FOTO 的 XML 控制文件不只是数据交换格式还可以用来做批量处理和精度验证。我一般会写一个 Python 脚本批量生成 XML 项目文件然后调用 E-FOTO 的命令行接口依次执行内定向、外定向、摄影三角测量、DEM 抽取和正射纠正。这样一套流程跑下来一个项目几十张影像的处理时间从手动操作的几小时压缩到十几分钟。import os import subprocess import xml.etree.ElementTree as ET # 批量生成 XML 项目文件 def generate_project_xml(image_list, output_dir): for img in image_list: root ET.Element(E-FOTOProject) ET.SubElement(root, ImageFile).text img ET.SubElement(root, OutputDir).text output_dir tree ET.ElementTree(root) xml_path os.path.join(output_dir, f{os.path.splitext(img)[0]}.xml) tree.write(xml_path, encodingUTF-8, xml_declarationTrue) yield xml_path # 依次调用各模块 def run_pipeline(xml_path): modules [interior_orientation, exterior_orientation, phototriangulation, dem_extraction, ortho_rectification] for mod in modules: cmd [f./{mod}, --project, xml_path] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: print(f{mod} failed: {result.stderr}) return False return True # 精度验证对比检查点坐标 def validate_accuracy(xml_path, check_points): tree ET.parse(xml_path) root tree.getroot() residuals [] for cp in check_points: # 从 XML 读取解算坐标和已知坐标对比 solved root.find(f.//CheckPoint[id{cp[id]}]) if solved is not None: dx float(solved.get(x)) - cp[x] dy float(solved.get(y)) - cp[y] residuals.append((dx**2 dy**2)**0.5) rmse (sum(r**2 for r in residuals) / len(residuals))**0.5 print(fRMSE: {rmse:.4f} pixels) return rmsegenerate_project_xml函数为每张影像生成一个 XML 项目文件run_pipeline函数依次调用五个模块validate_accuracy函数用检查点坐标计算 RMSE。检查点不要参与平差否则精度指标会虚高。RMSE 小于 1 像素算合格小于 0.5 像素算优秀。如果 RMSE 偏大先检查检查点坐标是否有粗差再检查平差模型是否选对。从那以后我每次带学生做实验都强制走一遍 XML 批量流程和精度验证不跑完不准提交报告。希望帮到你。本文还有配套的精品资源点击获取