OpenCV(C++)实现相机/图像的畸变校正

本次主要介绍一下相机的畸变以及如何获取相机的内参以及畸变系数,从而尽可能消除畸变的影响。

什么是畸变?

参考:单目摄像头标定与畸变矫正

图像校正

成像过程基本分为:物理坐标变换、投影变换、畸变矫正、像素变换
OpenCV(C++)实现相机/图像的畸变校正_第1张图片

畸变校正的基本流程

1.采集标定板图像,大约十五张左右;
2.根据使用的标定板确定标定板的内点数,找出标定板的角点坐标
3.进一步提取亚像素角点信息;
4.计算并获取相机的内参矩阵和畸变系数;
5.畸变图像的校正修复

0.准备标定板

标定板可以直接从opencv官网上能下载到:
链接: 标定板.
然后直接打印出来即可。
得出标定板的内部行列交点个数:6*9——下面在求解相机参数和畸变系数时会用
OpenCV(C++)实现相机/图像的畸变校正_第2张图片

1.采集标定板图像

附上代码:

#include "opencv2/opencv.hpp"
#include 
#include 

#include   //按键事件头文件
#include 

using namespace cv;
using namespace std;

int main()
{
	VideoCapture inputVideo(0);
	inputVideo.set(CAP_PROP_FRAME_WIDTH, 960);
	inputVideo.set(CAP_PROP_FRAME_HEIGHT, 480);
	if (!inputVideo.isOpened())
	{
		cout << "Could not open the input video " << endl;
		return -1;
	}
	Mat frame;
	string imgname;
	int f = 1;
	int ch;
	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);

		if (_kbhit()) {//如果有按键按下,则_kbhit()函数返回真
			ch = _getch();//使用_getch()函数获取按下的键值
			//cout << ch;
			if (ch == 27)
			{ 
				imgname = to_string(f++) + ".jpg";
				imwrite(imgname, frame);
			
			}//当按下ESC时循环,ESC键的键值时27.
		}

		char key = waitKey(10);

	}
	cout << "Finished writing" << endl;
	return 0;
}

获取的图像如下图所示:
OpenCV(C++)实现相机/图像的畸变校正_第3张图片

2.直接上程序,通过库函数的解算,即可获得相机内参及畸变系数

代码如下:

// CheckerBoardDemo.cpp : 定义控制台应用程序的入口点。
//

//#include 
#include 
#include
#include
using namespace cv;
using namespace std;

Mat image, img_gray;
int BOARDSIZE[2]{ 6,9 };//棋盘格每行每列角点个数
int main()
{
	vector<vector<Point3f>> objpoints_img;//保存棋盘格上角点的三维坐标
	vector<Point3f> obj_world_pts;//三维世界坐标
	vector<vector<Point2f>> images_points;//保存所有角点
	vector<Point2f> img_corner_points;//保存每张图检测到的角点
	vector<String> images_path;//创建容器存放读取图像路径

	string image_path = "F:/Works/C++/openCV/opencv study/Revise/Revise/Project1/*.jpg";//待处理图路径	F:/Works/C++/openCV/opencv study/Revise/Revise/Project1/
	glob(image_path, images_path);//读取指定文件夹下图像

	//转世界坐标系
	for (int i = 0; i < BOARDSIZE[1]; i++)
	{
		for (int j = 0; j < BOARDSIZE[0]; j++)
		{
			obj_world_pts.push_back(Point3f(j, i, 0));
		}
	}

	for (int i = 0; i < images_path.size(); i++)
	{
		image = imread(images_path[i]);
		cvtColor(image, img_gray, COLOR_BGR2GRAY);
		//检测角点
		bool found_success = findChessboardCorners(img_gray, Size(BOARDSIZE[0], BOARDSIZE[1]),
			img_corner_points,
			CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);

		//显示角点
		if (found_success)
		{
			//迭代终止条件
			TermCriteria criteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.001);

			//进一步提取亚像素角点
			cornerSubPix(img_gray, img_corner_points, Size(11, 11),
				Size(-1, -1), criteria);

			//绘制角点
			drawChessboardCorners(image, Size(BOARDSIZE[0], BOARDSIZE[1]), img_corner_points,
				found_success);

			objpoints_img.push_back(obj_world_pts);//从世界坐标系到相机坐标系
			images_points.push_back(img_corner_points);
		}
		//char *output = "image";
		char text[] = "image";
		char *output = text;
		imshow(output, image);
		waitKey(200);

	}

	/*
	计算内参和畸变系数等
	*/

	Mat cameraMatrix, distCoeffs, R, T;//内参矩阵,畸变系数,旋转量,偏移量
	calibrateCamera(objpoints_img, images_points, img_gray.size(),
		cameraMatrix, distCoeffs, R, T);

	cout << "cameraMatrix:" << endl;
	cout << cameraMatrix << endl;

	cout << "*****************************" << endl;
	cout << "distCoeffs:" << endl;
	cout << distCoeffs << endl;
	cout << "*****************************" << endl;

	cout << "Rotation vector:" << endl;
	cout << R << endl;

	cout << "*****************************" << endl;
	cout << "Translation vector:" << endl;
	cout << T << endl;

	///*
	//畸变图像校准
	//*/
	Mat src, dst;
	src = imread("F:/Works/C++/openCV/opencv study/Revise/image/2.jpg");  //F:/Works/C++/openCV/opencv study/Revise/image/2.jpg
	undistort(src, dst, cameraMatrix, distCoeffs);

	char texts[] = "image_dst";
	char *dst_output = texts;
	//char *dst_output = "image_dst";
	imshow(dst_output, dst);
	waitKey(100);
	imwrite("F:/Works/C++/openCV/opencv study/Revise/image/3.jpg", dst);

	destroyAllWindows();//销毁显示窗口
	system("pause");
	return 0;
}

运行程序,每张图片都会检测角点,如下:
OpenCV(C++)实现相机/图像的畸变校正_第4张图片
最终得到,相机内参及畸变系数:
OpenCV(C++)实现相机/图像的畸变校正_第5张图片
测试畸变前后的图像,以图像2为例:
OpenCV(C++)实现相机/图像的畸变校正_第6张图片
OpenCV(C++)实现相机/图像的畸变校正_第7张图片
因此,我们使用的相机自身畸变问题并不突出,所以校正前后图像的变化基本不大。但对于畸变问题突出的相机,一般需要对其进行畸变校正后,方可使用。

你可能感兴趣的:(OpenCV)