1. 为什么我们需要相机标定与畸变矫正
当你用手机拍下一张照片时,有没有发现边缘的建筑物看起来有点弯曲?这就是镜头畸变在作怪。在计算机视觉和机器人领域,这种畸变会严重影响算法的准确性。比如自动驾驶汽车依靠摄像头判断距离,如果图像本身就有畸变,那测距结果就会出错。
Matlab的Camera Calibrator工具箱就是为解决这个问题而生的。它通过分析棋盘格图案的照片,计算出相机的内参矩阵和畸变系数。内参矩阵包含了焦距、主点位置等信息,而畸变系数则描述了镜头产生的径向和切向畸变程度。
我曾在无人机视觉定位项目中遇到过这个问题。原始图像中建筑物的直线都变成了曲线,导致特征点匹配错误。使用Camera Calibrator标定后,矫正效果立竿见影,定位精度提升了30%以上。
2. 准备标定用的棋盘格图像
2.1 棋盘格的选择与打印
标定的第一步是准备高质量的棋盘格图案。根据我的经验,A3尺寸的棋盘格最适合室内标定。棋盘格方块数量建议在8×6到10×7之间,太小会影响角点检测精度,太大则不便使用。
打印时要注意:
- 使用哑光纸张避免反光
- 确保每个方块都是完美的正方形
- 打印后可以用直尺检查边长是否一致
2.2 拍摄标定图像
拍摄时要注意以下几点:
- 从不同角度拍摄15-20张照片
- 包含棋盘格在不同位置的图像(中心、边缘、倾斜)
- 确保棋盘格完整出现在画面中
- 避免强光直射造成过曝
我通常会这样操作:
- 固定相机位置,移动棋盘格
- 拍摄时保持相机对焦锁定
- 使用三脚架保持稳定
3. 使用Camera Calibrator工具箱进行标定
3.1 导入图像与参数设置
打开Matlab,在App选项卡中找到Camera Calibrator。点击"Add Images"导入拍摄的棋盘格图像。工具箱会自动检测角点,如果某些图像检测失败,可以手动调整。
关键参数设置:
- 棋盘格方块实际大小(单位毫米)
- 径向畸变系数个数(通常选2)
- 是否考虑切向畸变(建议勾选)
3.2 分析标定结果
标定完成后,工具箱会显示重投影误差。一般来说,误差小于0.5像素就算合格。如果误差过大,可以:
- 检查是否有模糊的图像
- 移除误差特别大的图像
- 重新拍摄补充更多样本
我遇到过误差偏大的情况,后来发现是棋盘格纸张有轻微弯曲。换成硬质板材后问题就解决了。
4. 批量处理畸变图像的完整方案
4.1 自动化脚本编写
标定完成后,我们需要编写批量处理脚本。下面是我优化过的代码框架:
function batchUndistortImages(inputFolder, outputFolder, cameraParams) % 支持多种图像格式 extensions = {'*.jpg','*.png','*.bmp'}; fileList = []; for i = 1:length(extensions) fileList = [fileList; dir(fullfile(inputFolder,extensions{i}))]; end % 创建输出目录 if ~exist(outputFolder, 'dir') mkdir(outputFolder); end % 并行处理加速 parfor i = 1:length(fileList) try img = imread(fullfile(inputFolder, fileList(i).name)); undistortedImg = undistortImage(img, cameraParams); [~,name,ext] = fileparts(fileList(i).name); imwrite(undistortedImg, fullfile(outputFolder, [name '_corrected' ext])); catch ME fprintf('处理 %s 时出错: %s\n', fileList(i).name, ME.message); end end end4.2 处理不同分辨率的技巧
在实际项目中,可能会遇到不同分辨率的图像。这时要注意:
- 如果图像尺寸与标定时不同,需要缩放内参矩阵
- 保持宽高比一致,否则会导致参数失效
- 对于超高分辨率图像,可分块处理避免内存溢出
我封装了一个自适应函数:
function adjustedParams = adjustCameraParams(originalParams, originalSize, newSize) scaleX = newSize(2)/originalSize(2); scaleY = newSize(1)/originalSize(1); adjustedParams = originalParams; adjustedParams.IntrinsicMatrix(1,1) = originalParams.IntrinsicMatrix(1,1)*scaleX; adjustedParams.IntrinsicMatrix(2,2) = originalParams.IntrinsicMatrix(2,2)*scaleY; adjustedParams.IntrinsicMatrix(3,1) = originalParams.IntrinsicMatrix(3,1)*scaleX; adjustedParams.IntrinsicMatrix(3,2) = originalParams.IntrinsicMatrix(3,2)*scaleY; end5. 实际应用中的问题与解决方案
5.1 边缘区域矫正效果不佳
这是最常见的问题,表现为图像边缘仍有明显畸变。解决方法包括:
- 增加标定图像的多样性,特别是包含边缘区域的样本
- 尝试增加径向畸变系数到3个
- 后期处理时适当裁剪边缘
5.2 处理速度优化
批量处理大量图像时,速度很关键。我的优化经验:
- 使用parfor并行计算
- 将图像转换为单精度减少内存占用
- 对超大图像先降采样处理
实测下来,这些优化能让处理速度提升3-5倍。
5.3 不同光照条件下的稳定性
光照变化会影响标定精度。建议:
- 标定时尽量覆盖各种光照条件
- 对过暗/过亮图像做预处理
- 考虑使用自适应阈值算法
在室外机器人项目中,我建立了不同时间段的标定参数库,根据环境光线自动选择最适合的参数集。
6. 进阶技巧与扩展应用
6.1 多相机系统标定
对于多相机系统(如立体视觉),需要分别标定每个相机后,再进行联合标定。Matlab的stereoCameraCalibrator可以很好地完成这个任务。
关键步骤:
- 单独标定每个相机
- 拍摄同时包含两个相机视野的棋盘格图像
- 计算相机间的旋转和平移矩阵
6.2 与深度学习结合
可以将矫正过程集成到深度学习pipeline中:
- 训练前统一矫正所有图像
- 在数据增强步骤模拟不同畸变
- 将矫正层嵌入网络结构
我在一个目标检测项目中采用第三种方案,使模型对原始畸变图像也有了很好的鲁棒性。
6.3 实时视频流处理
对于视频流,可以使用如下处理流程:
videoReader = VideoReader('input.mp4'); videoWriter = VideoWriter('output.mp4'); open(videoWriter); while hasFrame(videoReader) frame = readFrame(videoReader); correctedFrame = undistortImage(frame, cameraParams); writeVideo(videoWriter, correctedFrame); end close(videoWriter);7. 项目实战经验分享
在工业检测项目中,我们需要处理2000多张不同型号产品的图像。这些图像来自多个不同相机,分辨率从2K到8K不等。通过以下步骤建立了稳定的处理流程:
- 为每个相机建立独立的标定参数
- 开发自动识别图像来源的预处理模块
- 实现分块处理超大分辨率图像
- 建立质量检查机制验证矫正效果
这个系统已经稳定运行2年多,每天处理超过1万张图像。最大的收获是:良好的标定是计算机视觉项目的基石,值得投入足够的时间和精力。