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

什么是畸变?

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

图像校正

成像过程基本分为:物理坐标变换、投影变换、畸变矫正、像素变换
在这里插入图片描述

畸变校正的基本流程

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

0.准备标定板

标定板可以直接从opencv官网上能下载到:
链接: 标定板.
然后直接打印出来即可。
得出标定板的内部行列交点个数:6*9——下面在求解相机参数和畸变系数时会用
在这里插入图片描述

1.采集标定板图像

附上代码:

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

#include <conio.h>  //按键事件头文件
#include <iostream>

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;
}

获取的图像如下图所示:
在这里插入图片描述

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

代码如下:

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

//#include <stdafx.h>
#include <opencv2\imgproc\types_c.h>
#include<opencv2/opencv.hpp>
#include<iostream>
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;
}

运行程序,每张图片都会检测角点,如下:
在这里插入图片描述
最终得到,相机内参及畸变系数:
在这里插入图片描述
测试畸变前后的图像,以图像2为例:
在这里插入图片描述
在这里插入图片描述
因此,我们使用的相机自身畸变问题并不突出,所以校正前后图像的变化基本不大。但对于畸变问题突出的相机,一般需要对其进行畸变校正后,方可使用。

GitHub 加速计划 / opencv31 / opencv
77.35 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:1 个月前 )
687e37e6 Add support for v_sin and v_cos (Sine and Cosine) #25892 This PR aims to implement `v_sincos(v_float16 x)`, `v_sincos(v_float32 x)` and `v_sincos(v_float64 x)`. Merged after https://github.com/opencv/opencv/pull/25891 and https://github.com/opencv/opencv/pull/26023 **NOTE:** Also, the patch changes already added `v_exp`, `v_log` and `v_erf` to pass parameters by reference instead of by value, to match API of other universal intrinsics. TODO: - [x] double and half float precision - [x] tests for them - [x] doc to explain the implementation ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake 6 小时前
69803e7b Add the HAL implementation for the merge function on RISC-V Vector. 1 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐