简介:面向摄影测量与三维建模用户的Photoscan相机标定及畸变改正流程文档,重点解决空三处理中相机内参与畸变参数解算、批量影像畸变校正等实操问题。全文以Word格式系统梳理两大核心模块:相机标定涵盖添加影像、对齐影像、优化相机参数与导出参数文件四个环节,并结合空三原理说明参数优化逻辑;畸变改正详解导入标定参数、导出未畸变影像的具体操作路径,特别指出大规模测区可选取纹理丰富的部分影像估计参数、再批量改正全部影像的实用策略,兼顾计算效率与精度。资源包内含1个docx文档,大小2.37MB,内容按步骤配合关键界面呈现,适合航测数据处理人员、三维建模初学者及相关专业学生阅读学习。已有4761人在CSDN学习下载,可作为理解Photoscan摄影测量内业流程、提升三维重建成果精度的入门参考资料。
1. 为什么Photoscan处理流程里,相机标定和畸变改正决定了建模的成败
做过近景摄影测量或者无人机航测的人应该都遇到过这种怪事:照片拍得很清楚,重叠率也够,Photoscan一跑完对齐,模型整体像个大锅盖——地面拱起来,墙面朝外鼓。第一反应是“照片太少”或者“匹配点不够”,但往往加了几十张照片重跑,锅盖还在。这时候真正的问题多半不在照片数量,而在于相机标定参数没给对,畸变改正做了个寂寞。
Photoscan的处理流程说穿了就是“照片对齐 → 稀疏点云 → 密集点云 → 网格 → 纹理”,而照片对齐这一步,软件同时干两件事:估计每张照片的外方位元素(相机位置和姿态),估计相机内参(焦距、主点、畸变系数)。也就是说,相机标定不是一项可做可不做的预处理,它嵌在对齐里,精度直接决定后续所有步骤的几何骨架。畸变改正不到位,模型不是弯曲就是扭曲,控制点再密也拉不回来。这篇笔记就围绕这套流程里的相机标定与畸变改正展开:先说清原理,再给可照抄的落地操作,最后把踩过的坑全部摆出来。
2. Photoscan相机标定解析:内参、畸变模型与自标定的边界
2.1 内参是什么?fx/fy/cx/cy在Photoscan里的真实含义
相机内参描述的是一束光线穿过镜头后,如何在传感器平面上落成像素坐标。四个基本量是fx、fy(x和y方向的像素焦距)和cx、cy(像素主点)。很多人以为主点就是画面的正中心,其实镜头装配总有偏差,主点经常偏离中心几个像素甚至几十个像素,短焦镜头尤其明显。
Photoscan里的相机标定参数表,核心就是这个内参矩阵加畸变系数。它的f就是像素焦距,单位不是毫米;cx、cy在旧版PhotoScan里也以像素为单位,但含义是主点偏离画面中心的值,而不是OpenCV那种“主点距离左上角距离”的绝对坐标。举例来说,一张1280×720的图像,OpenCV标定出cx=634.7像素,那Photoscan里应填的是634.7 - 1280/2 = -5.3左右,表示主点略微偏左。把这两套表达直接混用,很多人第一次导入标定参数就在这里翻车。
像素焦距和物理焦距的关系也很要紧。f(像素)= 镜头物理焦距(毫米)÷ 像元尺寸(毫米/像素)。比如8.4mm镜头配1.4μm像元,像素焦距约6000。Photoscan的高级参数里填sensor width(传感器宽度)和focal length mm(毫米焦距)后,它会自动按像素尺寸折算,但如果你的图像经过了缩放裁剪,EXIF里的焦距和实际像幅不匹配,软件就会算出错误的像素焦距。
2.2 畸变模型的好坏:k1/k2/k3和p1/p2各自管什么
理想针孔模型是直线投影,实际镜头不是。径向畸变让直线变成弧线,枕形畸变是图像边缘向外凸,桶形畸变是向内凹,这是k1、k2、k3三个系数管的。切向畸变是因为镜头光轴和传感器平面不严格垂直,成像出现“平行四边形”式的剪切,这是p1、p2两个系数管的。Photoscan默认的Brown模型把这五个系数全部纳入,标定时一起解算。
畸变改正在Photoscan里不是一个独立的“按钮”,而是在对齐过程中,软件把每个像点按当前畸变系数重新投影回理想位置,再参与同名点匹配和光束法平差。系数差一点,图像边缘的点就会偏出几个像素,匹配点就会找错地方,平差结果随之整体扭曲。有一个非常反直觉的现象:畸变系数错了,重投影误差未必会特别大,因为平差会用外方位元素去“吸收”这部分误差,结果就是点云依然光滑,但绝对形状是弯的。
2.3 自标定 vs 预标定:为什么不能无脑自动
Photoscan默认是自标定:对齐时把所有内参、畸变系数作为未知数一起解算。这个方案在照片数量充足、重叠度高、相机有运动视差的场景下相当靠谱,无人机航测那种几百张照片、航线规则、地面纹理丰富的序列,让它自己跑就行。
自标定的软肋在于“解空间太大”。如果只有十几张照片,或者相机几乎没有旋转和平移,那内参和外参互相纠缠,解出来的焦距可能偏了30%,k1偏一个数量级,但平差照样收敛。这正是模型弯曲但软件不报错的根本原因。预标定就是提前用棋盘格或者其他工具把内参固定下来,让Photoscan只去解外方位元素,几何稳定性好很多。我的习惯是:近景拍摄、短基线、大广角镜头这三类场景,一律预标定,不让软件自由发挥。
下表是我取舍时的判断依据:
| 场景特征 | 自标定 | 预标定 |
|---|---|---|
| 照片数量大于100、重叠度大于70% | 推荐 | 可选 |
| 照片数少于30、视角单一 | 不推荐 | 强烈推荐 |
| 鱼眼/超广角镜头 | 不推荐 | 推荐 |
| 已知同型号相机多次标定结果 | 可选 | 推荐 |
| 需要多个测区成果拼接 | 不推荐 | 必须 |
3. 把已知内参写进Photoscan:畸变改正落地的步骤和Python脚本
3.1 从OpenCV/ROS标定结果到Photoscan的参数映射
很多从业者手头已经有标定好的相机参数,比如用D435i在ROS下跑过相机标定,或者用OpenCV的棋盘格标定过单目相机。这些工具输出的是camera_matrix(fx、fy、cx、cy)和distortion_coefficients(k1、k2、p1、p2、k3),把它们搬进Photoscan时不能原样粘贴,要做两次换算。
第一次换算是主点坐标。OpenCV的cx是相对图像左上角的绝对像素坐标,Photoscan要的是相对图像中心的偏移量。以1280×720图像为例:cx=634.7换算后约-5.3,cy=356.2换算后约-3.8。第二次换算是fy的处理。OpenCV的fx和fy分别是两个方向的像素焦距,而Photoscan的sensor.f只有一个值,另一个方向靠纵横比aspect来体现。aspect=fy/fx,正常镜头这个值接近1,但D435i这类相机并非绝对正方像素,随手填成1.0会留下几个像素的误差。
畸变系数k1、k2、p1、p2、k3的符号和数值直接对应,但要注意:ROS里distortion_model标成plumb_bob时是Brown模型,标成equidistant或fisheye时是其他模型,不能混填进Photoscan的默认模型。
3.2 用Metashape Python API写入并锁定标定参数
Photoscan从2.0时代开始就提供Python API,后来改名为Metashape,API模块名也从PhotoScan换成了Metashape。我一般会在照片导入后、对齐之前用一段脚本把标定参数写死。下面是针对D435i标定结果的一个可运行示例:
import Metashape chunk = Metashape.app.document.chunk # 假设图像尺寸为1280x720,以下是ROS相机标定得到的内参 fx = 615.4 fy = 614.9 cx = 634.7 cy = 356.2 k1, k2, p1, p2, k3 = -0.0561, 0.0628, -0.0002, 0.0001, 0.0 sensor = chunk.sensors[0] sensor.fixed = True # 锁定标定,不让对齐时随意修改 sensor.width = 1280 sensor.height = 720 sensor.f = fx # 像素焦距 sensor.aspect = fy / fx # 纵横比 sensor.cx = cx - sensor.width / 2.0 sensor.cy = cy - sensor.height / 2.0 sensor.k1 = k1 sensor.k2 = k2 sensor.k3 = k3 sensor.p1 = p1 sensor.p2 = p2这里最关键的是sensor.fixed = True。如果不锁,对齐时软件认为这些值只是初值,依旧会去优化它们,等于你白填。sensor.cx和sensor.cy用“OpenCV绝对值减半幅”的方式换算成相对中心偏移。sensor.aspect的意义是f/fy,我填的是fy/fx,因为Photoscan里aspect基线是f对应的方向。
如果你用的相机是多相机系统,比如双目相机,每个sensor要单独设置。常见做法是先创建一个空chunk,把左右目照片分别添加到两个camera group,再分别取chunk.sensors里的对应传感器做赋值。不同设备的内参不同,混在一起会让对齐直接失败,这一点比单目还要敏感。
3.3 校准窗口的手动操作与“固定标定”的正确姿势
没有Python环境的时候,也可以纯界面操作。在Metashape工作区选中相机,右键点击“调节”(Calibrate),弹出的对话框里列出了该相机的标定参数。把“固定标定”(Fixed calibration)勾上,然后手动修改f、cx、cy、k1、k2、k3、p1、p2这些值,确定后重新执行对齐。
手动操作里我踩过一个很隐蔽的坑:修改标定参数后直接点击“对齐照片”,结果软件依然重新优化了这些参数。原因是对齐对话框里的“Adaptive camera model fitting”选项开着,它会让软件按照片实际情况重新适应。正确做法是保持勾选“固定标定”,同时对照片对齐对话框里的“自适应模型拟合”保持默认,因为此时参数已经被锁,那个选项只对未锁定的参数起作用。改完参数之后,建议看一眼控制台输出,确认打印出来的初始焦距确实是你填的值。
如果Photoscan提示“相机标定参数无效”,最常见的坑是图像尺寸和填写尺寸对不上。图像导入后被自动缩放,而你填的是原始尺寸的标定值,软件按错误尺度换算像素焦距,自然报错。解决方法是先读取sensor.width和sensor.height确认真实分辨率,再换算主点偏移。
4. 相机标定与畸变改正避坑指南:5条让模型翻车的血泪经验
4.1 模型成碟形或锅盖形:先查k1的符号和量级
做了控制点约束还是弯,那基本可以断定畸变参数没有正确生效。常见原因是k1的正负号填反了:桶形畸变的k1是负值,枕形畸变是正值。Photoscan默认展示的畸变曲线图和OpenCV的符号约定是反的,很多人按OpenCV结果倒贴进去,模型就按相反方向弯曲。解决方法是先确认你用的是哪套标定工具,把畸变系数贴进去后马上用一个已知平面的小场景做验证,比如拍一堵平直墙面,跑完对齐看稀疏点云是否平面,不平面就翻转k1符号再试。
4.2 照片太少时标定发散的用control:固定主点,不要全放开
十几张照片拍一个物体,Photoscan对齐后焦距变成原来的两倍,这个情况见得不少。原因是照片数量不够,光束法平差里内参外参一起解,数学上是欠定的。解决方法是分两级收敛:第一级把cx、cy、k2、k3、p1、p2全部固定,只让f和k1自由;第二级对齐完成后,再解锁全部参数做一次优化。这个“分级解锁”的做法一定要配合足够多的控制点,否则就算收敛了也容易落到局部极小。
4.3 D435i标定结果导入后警告“焦距与EXIF不一致”
从ROS相机标定拿到D435i的内参后写进Metashape,对齐时控制台打印“focal length differs from EXIF by 20%”之类的警告。这是因为D435i的彩色相机和深度相机各自有标定结果,你拿深度相机的内参填到了彩色相机上,或者反过来,两个镜头的焦距本来就是不同的。解决方法是导入前确定用的是RGB传感器的标定结果,并且核对sensor.width、sensor.height和标定时的图像分辨率一致。D435i在ROS下标定时一般用640×480,Photoscan里用1280×720照片时就该把fx按比例放大:新fx=原fx*(1280/640)。
4.4 鱼眼镜头按Brown模型标定,边缘仍然撕裂
鱼眼镜头视场角超过120度以后,Brown模型的拟合能力急剧下降,图像边缘畸变改正后还是弯。解决办法是使用Photoscan的“鱼眼"镜头类型:在相机标定对话框里把镜头类型(Lens type)从“针孔”切换为“鱼眼”,对应的畸变模型变成F-theta类型。注意切换后OpenCV标定的k1-k3不能直接填进来,这两种模型的参数物理意义不同,需要重新在Photoscan里自标定,或者用支持鱼眼模型的标定工具重新算。
4.5 对齐报告显示标定参数“没变”但模型偏了
手动填完标定,重新对齐后发现相机标定参数跟你填的一样,但模型整体偏移。这个坑的根子不在标定,而在照片EXIF里的焦距。Photoscan对齐前加载照片时,优先读取EXIF的FocalLength和FocalLengthIn35mmFilm,用它初始化或覆盖你填的像素焦距。解决方法是选中所有照片,右键菜单里把“焦距”(focal length)设为忽略EXIF,或者在导入前用exiftool把EXIF焦距统一改成符合实际的值。
5. Photoscan处理流程里,对齐与畸变改正如何配合
5.1 对齐照片时标定是怎么被“同时估计”的
“对齐照片”的执行过程,是用光束法平差同时解算相机位姿和标定参数。每一对匹配点都会构成一个误差方程,平差的目标是最小化所有像点的重投影误差,也就是把三维点重新投影到像平面后和原像点之间的距离。标定参数就藏在这个投影函数里,所以畸变系数不准,为了压低误差,软件会把相机位置姿态调到“不自然”的状态,这就是模型弯曲的数学来源。
理解这一点,就知道为什么不能孤立地看“相机标定”和“畸变改正”两个词:它们是同一道平差问题的两半。照片对齐对话框里的“精度”(Accuracy)选项和高阶参数的“自适应模型拟合”共同决定了标定参数的优化方式。精度选最高时,软件用原始分辨率参与匹配,标定参数能捕获更精细的畸变;精度选低时,用降采样图像匹配,标定会变得粗糙。
5.2 不同设备下的标定策略:无人机、D435i、全景相机
无人机航测(比如大疆系列)的镜头在出厂时有一个标称焦距,但不代表每台机器的真实焦距一致,温度变化也会让内参漂移。对无人机我一般默认开自标定,但一定要在航线里加入足够的交叉航线,让相机有多个旋转角度的观测。D435i这类深度相机则完全相反,它的RGB镜头焦距短、视场角大、畸变明显,自标定极易跑飞,必须从ROS标定或双目相机标定结果里拿内参,再用第3章的脚本写入。全景相机目前不是Photoscan的强项,它的多镜头拼接参数和普通单目标定模型不适配,实在要做,只能每个镜头拆开单独建块再对齐。
5.3 对齐质量不好时,按什么顺序排查
我在实际项目中把排查流程固定成了一串顺序操作。第一步看对齐报告的匹配点数和重投影误差,误差大于1像素就要警惕;第二步看相机标定参数是否落在合理区间,比如800万像素照片焦距在2000~4000像素区间,主点偏移不超过20像素;第三步用“查看稀疏点云”的误差颜色显示(置信度),置信度低的区域通常对应畸变改正不良的边缘地带;第四步拿几对同名点手动测量,在界面里对比它们在原始照片上的位置和重投影的点位差。
这套排查顺序能区分“标定坏了”和“匹配失败”两种问题。匹配失败时重投影误差会特别大,标定坏了则误差可能不大但模型几何形状扭曲。如果标定参数在合理区间但模型还是弯的,再回头看控制点误差;控制点如果也被拉偏,说明问题不是局部而是全局的,那就要考虑换成像模型或者重跑对齐。
6. 进阶验证:用重投影误差和控制点把畸变改正做到可量化
分享一个我每次项目必做的验证动作:对齐完成后不要急着生成密集点云,先写一小段Python脚本把每个相机的重投影误差导出来,并用控制点做二次检验。
import Metashape chunk = Metashape.app.document.chunk for camera in chunk.cameras: if camera.transform is None: continue err = camera.reproj_error if err > 0.75: print(camera.label, "重投影误差偏高:", round(err, 3))一个健康的对齐结果,平均重投影误差应低于0.5像素,个别覆盖边缘的相机可以到0.7~0.8像素,但如果多数相机超过1像素,标定参数大概率没有对上。控制点验证更直接:在模型上放置3到5个外业控制点,固定后看“控制点误差”弹窗里的平面和高程误差。如果控制点误差远大于重投影误差,说明存在系统性畸变残余。此时我一般会打开相机标定对话框,把k2或p1解锁再对齐一次,看误差是否明显下降,以此判断畸变模型的高阶项是否需要参与优化。
这个“解锁-对齐-看误差”的循环,一次只放开一个参数,是Photoscan处理流程里最稳定的相机标定调节方式。如果你用外部工具算出的畸变系数和Photoscan自标定结果差了20%以上,不要急着信某一方,用上面这个循环让数据说话。畸变改正做得好不好,最后都体现在这些数字里。希望这几条经验帮你在下一次建模时少走几步弯路。
本文还有配套的精品资源,点击获取