MATLAB + OpenCV 简单相机标定教程

前言:
         由于2018年Robocn的比赛不可以使用激光,超声等,具有可以通讯的可疑设备,然而有需要全场定位这种要求,所以不得不采用视觉方案!然而其中最基础的就是解决相机的标定问题!接下来介绍Matlab 进行相机标定的流程操作!

           这种标定的方式在网上有很多的公式啊,原理讲解,这里只是在应用上进行介绍!
          当然了,还是需要简单了解下标定基础知识的:  点击打开链接

          在标定时需要标定板,就是黑白网格图例 ,opencv的官网上可以得到
          http://docs.opencv.org/2.4/_downloads/pattern.png

首先就是进行标定板的图像采集

         对于标定板,由于时间有限,就不采用打印的方式了,我直接在网页上显示!环保绿色!
         

   标定嘛,肯定需要具体尺寸样标的,所以我直接在电脑上量取,这个误差在小范围内可以允许!

如你所见我测的数据是33mm,这里的数据等会在Matlab的 Camera Calibrator是要使用的!

这里附上OpenCV简单的图片采集程序,按‘q' 获取,按esc退出!

#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>


using namespace cv;
using namespace std;

int main()
{
	VideoCapture inputVideo(0);
	inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 800);
	inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 600);
	if (!inputVideo.isOpened())
	{
		cout << "Could not open the input video " << endl;
		return -1;
	}
	Mat frame;
	string imgname;
	int f = 1;
	while (1) //Show the image captured in the window and repeat
	{
		inputVideo >> frame;              // read
		if (frame.empty()) break;         // check if at end
		imshow("Camera", frame);
		char key = waitKey(1);
		if (key == 27)break;
		if (key == 'q' || key == 'Q')
		{
			imgname = to_string(f++) + ".jpg";
			imwrite(imgname, frame);
		}
	}
	cout << "Finished writing" << endl;
	return 0;
}

注意这里inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 800);

inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 600);
如果没有设置,OpenCV直接按默认大小的获取图像尺寸!

接下来就是进行多角度的拍摄,角度越丰富越好! 

因为我是VS2017,且没有规定路径,所以图片直接存储在项目文件夹中!

MATLAB操作

如下图找到  Camera Calibrator

运行可以看到
点击Add Images时,会显示:

注意这里是要输入黑白正方体的大小的,在上面的测定中,显示的是33mm,所以这里填写33


注意这里的图片还是要多一点:
然后选定以下参数:

为了防止可能产生极大的扭曲,所以选择使用两参数,并且选择错切和桶形畸变。

直接点击Calibrate 就可以了
然后保存Camera Parameters就可以了

这是矫正前的图片:
点击show Undistorted即可看到校正后的图像:



数据分析:


白畸变参数,总共有五个,径向畸变3个(k1,k2,k3)和切向畸变2个(p1,p2)。
径向畸变:
这里写图片描述
切向畸变:
这里写图片描述
以及在OpenCV中的畸变系数的排列(这点一定要注意k1,k2,p1,p2,k3)。
这里写图片描述
对应 k1 k2      k3由于前面选择,所以这里就为0

对应 p1 p2



对应
这里写图片描述


矫正代码示例:

#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>


using namespace cv;
using namespace std;

int main()
{
	VideoCapture inputVideo(1);
	inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 800);
	inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 600);
	if (!inputVideo.isOpened())
	{
		cout << "Could not open the input video: " << endl;
		return -1;
	}
	Mat frame;
	Mat frameCalibration;

	inputVideo >> frame;
	Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
	cameraMatrix.at<double>(0, 0) = 917.052472085750;
	cameraMatrix.at<double>(0, 1) = 0.657056681717874;
	cameraMatrix.at<double>(0, 2) = 408.884053678499;
	cameraMatrix.at<double>(1, 1) = 916.541676777971;
	cameraMatrix.at<double>(1, 2) = 332.189066871859;

	Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
	distCoeffs.at<double>(0, 0) = -0.108750634204250;
	distCoeffs.at<double>(1, 0) = -0.155068804309725;
	distCoeffs.at<double>(2, 0) = -0.00261486335789016;
	distCoeffs.at<double>(3, 0) = 0.00154770538482982;
	distCoeffs.at<double>(4, 0) = 0;

	Mat view, rview, map1, map2;
	Size imageSize;

	imageSize = frame.size();
	initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
		getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
		imageSize, CV_16SC2, map1, map2);


	while (1) //Show the image captured in the window and repeat
	{
		inputVideo >> frame;              // read
		if (frame.empty()) break;         // check if at end
		remap(frame, frameCalibration, map1, map2, INTER_LINEAR);
		imshow("Origianl", frame);
		imshow("Calibration", frameCalibration);
		char key = waitKey(1);
		if (key == 27 || key == 'q' || key == 'Q')break;
	}
	return 0;
}

以上为OpenCV提供的简单 代码示例!
以下为原来的图像:

以下为矫正后的图像:

以上为基本的操作流程,可见Matlab 是有多么的强大!
至于矫正后对于那个黑色区域怎么办呢?  可以直接矩形框选中间区域就行了。

相机无畸变后,我们就可以把真实世界的坐标,直接转化为图像里的坐标! 依据像素做有意思的事情! 例如我曾经利用几何原理做过扫描线激光的三维重建! 这个原理也就是现在市面上的短距离激光雷达的基本结构,区别就是,我是三维的!

有误希望指点!

猜你喜欢

转载自blog.csdn.net/qq_37389133/article/details/79903011