上一篇把前景抠出来、把划痕填回去。这一篇还是「几何」主题,但方向又不一样------把斜着拍的东西拉正,把两幅对不齐的图对齐。几何校正是工业视觉的必修课:文档扫描、车牌矫正、印刷套准、医学影像配准,都靠它。OpenCV 里这两个功能的代表作,就是透视变换 warpPerspective 和 ECC 图像对齐。
一、效果先行
先看透视变换。左上是一张电路板正视图,我用程序化指定 4 个角点,把它「斜拍」成梯形(右上),再用 4 对点找回单应矩阵拉正(左下)。右下是模拟「角点定位有 ±3px 误差」的矫正结果------明显模糊重影:

再看 ECC 图像对齐。我固定随机种子,程序化给测试图制造了 4 种已知的变换(平移/旋转/仿射/透视),再让 findTransformECC 找回。每行三列:模板、对齐结果、误差图(越黑说明对齐越好):

两张图记住两件事:透视变换靠 4 对点解矩阵,点越准矫正越准;ECC 不需要特征点,直接像素级对齐,精度能到亚像素。
二、透视变换:4 对点把斜的拉正
透视变换的核心是一个 3×3 的单应矩阵(homography),8 个自由度,能表达「近大远小」的透视畸变。和只支持平行四边形变换的仿射变换比,它多出来的就是「透视」这一项。
cpp
// 4 对点解单应矩阵(src→dst,顺序必须一一对应)
Mat M = getPerspectiveTransform(src4points, dst4points);
// 按单应矩阵重投影整幅图
warpPerspective(src_img, dst_img, M, dst_size);
4 对不共线的点就能唯一解出这个矩阵。文档扫描的思路就是:检测文档的 4 个角 → 解单应矩阵 → warpPerspective 拉正。
三、角点精度决定矫正质量
这个闭环实验值得记住。我把正视图制造斜视,再矫正回来,对比两种情况的 PSNR:
精确矫正(4 点零误差):24.01 dB
噪声矫正(4 点 ±3px 误差):14.82 dB
±3 像素的角点误差,让 PSNR 掉了 9 分贝,比两次插值的固有损失还大。结论很直接:角点定位精度决定矫正质量。真实文档扫描时,角点靠 Hough/轮廓检测得到,必然带误差,所以工程上要么用 findHomography 加 RANSAC 提纯角点,要么用更多点拟合,不能只靠 4 点精确解。
四、ECC:不用特征点的像素级对齐
ECC 全称增强相关系数(Enhanced Correlation Coefficient)。和 SIFT/ORB 特征匹配完全不同------它不找特征点,直接对整幅图像素做相关性优化,迭代估计两幅图之间的运动变换。
cpp
Mat warp = Mat::eye(2,3,CV_32F); // homography 用 3×3
double cc = findTransformECC(template_img, input_img, warp,
MOTION_AFFINE,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.0001));
它支持 4 种运动模型,参数越多越灵活也越慢:translation(平移,2 参数)、euclidean(平移+旋转,3 参数)、affine(+缩放剪切,6 参数)、homography(透视,8 参数)。返回的 cc 是相关系数,越接近 1 对齐越好。
五、实测对账
固定随机种子,程序化制造 4 种已知变换,再让 findTransformECC 找回,真值和检测值逐元素对账:
| 模型 | cc | 矩阵误差 |
|---|---|---|
| translation | 0.9998 | 0.0060 |
| euclidean | 0.9988 | 0.0021 |
| affine | 0.9986 | 0.0091 |
| homography | 0.9999 | 0.0067 |
四种模型全部对齐到亚像素级(cc 全大于 0.9986),参数最少的 euclidean 误差最小,参数最多的 affine 反而最大------参数多更灵活,但也更容易过拟合噪声。误差图接近全黑,肉眼几乎看不出差异。
六、踩坑记录
| 坑 | 现象 | 原因 | 正确姿势 |
|---|---|---|---|
| Mat 初始化编译不过 | brace-enclosed list 无法转换 | 官方是 Mat_<float>({2,3},{...}),不是 Mat_<float>(2,3)({...}) |
第一个参数用 {行,列} 花括号 |
| abs() 无 convertTo | 编译报错 | abs(Mat) 返回 MatExpr,不是 Mat | 先 Mat t = cv::abs(err); 再 convertTo |
| ECC 参数顺序 | 对齐结果反了 | findTransformECC 是 template 在前、input 在后 | 记住模板图放第一个参数 |
| 大位移对齐失败 | cc=-1 或误差大 | 默认单位矩阵初始估计,大位移收敛到局部最优 | 用 findTransformECCMultiScale 多尺度 |
七、AI 与 LLM Wiki:这一课沉淀了什么
LLM Wiki 从 22 页涨到 24 页,这一课新增「透视变换warpPerspective」和「ECC图像对齐findTransformECC」两个概念页,沉淀了单应矩阵 4 点解、角点精度对矫正质量的影响、ECC 四种运动模型的参数权衡。两张截图归档进素材目录,进度表上 warpPerspective_demo 和 image_alignment 勾选完成,从 28 个变成 30 个,进度 31%。

这一课最值得进知识库的,是「制造已知变换再找回」这个对账方法论------不靠肉眼看图说「对齐了」,而是固定种子制造已知的变换矩阵,让算法找回,逐元素对比真值和检测值。透视变换和 ECC 都用这一招验证,比任何主观判断都硬。
写在最后
97 个实例,今天完成第 30 个,进度 31%。几何校正这一站,透视变换给了「四点解矩阵」的几何思路,ECC 给了「像素级相关性优化」的对齐思路,一个靠点、一个靠像素,把「把图摆正」这个问题讲透了。
下一篇做 imgproc 收官------分水岭(watershed)和物体分割(segment_objects),粘连物体分割的经典方案。到时候见。