1、拍摄照片
首先拍摄10~20张图片。将棋盘贴在墙上或者板子上,对摄像头进行调焦。拍摄时将摄像头视野分成2×2,4个象限,在每个象限中正对棋盘拍摄一张图片;拉近视距,将棋盘置于视野中心正对拍摄一张,倾斜摄像头,8个角度各拍摄一张。一共4+1+8=13张图片,这样可以减少被camera calibrator拒绝的概率。
2、利用matlab工具箱获得内参
导入图片,calibrate,输出结果
cameraParams.IntrinsicMatrix 查看内参矩阵(跟网上的理论推导出来的矩阵是转置关系)
FocalLength: 焦距 fx,fy
PrincipalPoint: 中心点偏移 cx,cy
RadialDistortion:径向失真参数 k1 k2
TangentialDistortion: 切向失真参数 k3 k4
3、利用opencv进行图像矫正(vs 2015+opencv3)
两种方式:undistort与initUndistortRectifyMap+getOptimalNewCameraMatrix+remap
代码如下:
//#include "opencv2/core/core.hpp"
//#include "opencv2/calib3d/calib3d.hpp"
//#include "opencv2/imgproc/imgproc.hpp" // undistort
//#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include"opencv.hpp"
using namespace cv;
using namespace std;
void main()
{
double fc1, fc2, cc1, cc2, kc1, kc2, kc3, kc4; //用matlab事先获得
fc1 = 635.6616; fc2 = 493.5513;
cc1 = 502.5203; cc2 = 272.9890;
kc1 = -0.3917; kc2 = 0.1388;
kc3 = 0; kc4 = 0;
Mat Img = imread("C:\\Users\\sunmingzhe\\Desktop\\test\\1.jpg");
Mat intrinsic_matrix = (Mat_<double>(3, 3) << fc1, 0, cc1, 0, fc2, cc2, 0, 0, 1);//内参矩阵
Mat distortion_coeffs = (Mat_<double>(1, 4) << kc1, kc2, kc3, kc4);//畸变系数
string filePath = "Correction1.jpg";//处理后图像名
Mat ImgUndistort = imread(filePath),map1,map2;
TickMeter tm; //计时
//undistort(Img, ImgUndistort, intrinsic_matrix, distortion_coeffs); //矫正 300ms
Size imageSize=Size(960,576);//相机尺寸
initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, Mat(),
getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs,imageSize,1, imageSize, 0),
imageSize,CV_16SC2,map1,map2);//获得map1,map2映射表,用以提升速度,多张图片只需要运行一次
tm.start();//计时开始
remap(Img, ImgUndistort, map1, map2, INTER_LINEAR);//校准图像 70ms
tm.stop();//计时结束
cout << "count=" << tm.getCounter() << ",process time=" << tm.getTimeMilli() << endl;
imshow("Correction Image", ImgUndistort);//显示图像
waitKey(0);
}
输入相机参数→读取图片(绝对路径)→生成内参与畸变矩阵→定义输出(ImgUndistort)→矫正图像
矫正图像中首先利用了undistort函数,这个函数比较方便使用,但是运行时间长,不满足视频处理需求(300+ms)
然后采用initUndistortRectifyMap函数与remap函数配合处理图像,时间较短(70ms)
CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,
InputArray R, InputArray newCameraMatrix,
Size size, int m1type, OutputArray map1, OutputArray map2 );
initUndistortRectifyMap函数的作用是获得图像横纵方向映射关系表,供remap使用;其参数是(相机内参,畸变参数,映射矩阵(双目会用到,单目这里是单位阵,直接Mat()即可),输出的新的相机内参矩阵,图片尺寸,图像类型,图像x方向映射关系表,图像y方向映射关系表)
CV_EXPORTS_W Mat getOptimalNewCameraMatrix( InputArray cameraMatrix, InputArray distCoeffs,
Size imageSize, double alpha, Size newImgSize = Size(),
CV_OUT Rect* validPixROI = 0,
bool centerPrincipalPoint = false);
getOptimalNewCameraMatrix函数的作用是显示更大范围的图片(正常重映射之后会删掉一部分图像)(参考https://www.cnblogs.com/riddick/p/6711263.html)其用来显示所有图像;其参数是(内参矩阵,畸变参数,原图像大小,1,新生成图像大小,0);1代表源图像的像素都保留在未失真图像中,0代表未失真图像的所有像素都有效。
CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
remap函数作用是生成矫正后未失真图像;其参数是(源图像, 矫正后图像, map1, map2, 插值方法),差值方法一般用 INTER_LINEAR双线性插值